// Copyright (c) 2015-2016 by Silicon Laboratories Inc. All rights reserved. // The program contained in this listing is proprietary to Silicon Laboratories, // headquartered in Austin, Texas, U.S.A. and is subject to worldwide copyright // protection, including protection under the United States Copyright Act of 1976 // as an unpublished work, pursuant to Section 104 and Section 408 of Title XVII // of the United States code. Unauthorized copying, adaptation, distribution, // use, or display is prohibited by this law. #include #include #include #include #include #ifdef _WIN32 #include #pragma comment (lib, "CP210xManufacturing.lib") #include "CP210xManufacturingDLL.h" #else #include "OsDep.h" #include "CP210xManufacturing.h" #endif #include "stdio.h" #include "util.h" #include "smt.h" void AbortOnErr( CP210x_STATUS status, std::string funcName) { if( status != CP210x_SUCCESS) { char msg[ 128]; sprintf( msg, /*SIZEOF_ARRAY( msg),*/ "%s returned 0x%x", funcName.c_str(), status); throw CDllErr( msg); } } //--------------------------------------------------------------------------------- DWORD LibSpecificNumDevices( const CVidPid &, const CVidPid &) { DWORD DevCnt; AbortOnErr( CP210x_GetNumDevices( &DevCnt ), "CP210x_GetNumDevices"); return DevCnt; } //--------------------------------------------------------------------------------- class CCP210xDev { public: CCP210xDev( const CVidPid &FilterVidPid, DWORD devIndex); ~CCP210xDev(); HANDLE handle() const { return m_H; } bool isLocked() const; void lock() const; void reset() const; CDevType getDevType() const; CVidPid getVidPid() const; BYTE getPowerMode() const; BYTE getMaxPower() const; WORD getDevVer() const; WORD getFlushBufCfg() const; std::vector getSerNum( bool isAscii) const; std::vector getManufacturer( bool isAscii) const; std::vector getProduct( bool isAscii) const; void setVidPid( WORD vid, WORD pid) const; void setPowerMode( BYTE val) const; void setMaxPower( BYTE val) const; void setDevVer( WORD val) const; void setFlushBufCfg( WORD val) const; void setSerNum( const std::vector &str, bool isAscii) const; void setManufacturer( const std::vector &str, bool isAscii) const; void setProduct( const std::vector &str, bool isAscii) const; HANDLE m_H; }; CCP210xDev::CCP210xDev( const CVidPid &, DWORD devIndex) { AbortOnErr( CP210x_Open( devIndex, &m_H), "CP210x_Open"); } CCP210xDev::~CCP210xDev() { CP210x_STATUS status = CP210x_Close( m_H); if( status != CP210x_SUCCESS) { std::cerr << "CP210x_Close failed\n"; } } bool CCP210xDev::isLocked() const { BYTE lock; AbortOnErr( CP210x_GetLockValue( m_H, &lock), "CP210x_GetLockValue"); return lock != 0; } void CCP210xDev::lock() const { AbortOnErr( CP210x_SetLockValue( m_H), "CP210x_SetLockValue"); } void CCP210xDev::reset() const { AbortOnErr( CP210x_Reset( m_H), "CP210x_Reset"); } CDevType CCP210xDev::getDevType() const { BYTE partNum; AbortOnErr( CP210x_GetPartNumber( m_H, &partNum ), "CP210x_GetPartNumber"); return CDevType( partNum); } CVidPid CCP210xDev::getVidPid() const { WORD vid, pid; AbortOnErr( CP210x_GetDeviceVid( m_H, &vid ), "CP210x_GetDeviceVid"); AbortOnErr( CP210x_GetDevicePid( m_H, &pid ), "CP210x_GetDevicePid"); return CVidPid( vid, pid); } BYTE CCP210xDev::getPowerMode() const { BOOL SelfPower; AbortOnErr( CP210x_GetSelfPower( m_H, &SelfPower), "CP210x_GetSelfPower"); return SelfPower ? 1 : 0; } BYTE CCP210xDev::getMaxPower() const { BYTE MaxPower; AbortOnErr( CP210x_GetMaxPower( m_H, &MaxPower), "CP210x_GetMaxPower"); return MaxPower; } WORD CCP210xDev::getDevVer() const { WORD devVer; AbortOnErr( CP210x_GetDeviceVersion( m_H, &devVer), "CP210x_GetDeviceVersion"); return devVer; } WORD CCP210xDev::getFlushBufCfg() const { WORD flushBufCfg; AbortOnErr( CP210x_GetFlushBufferConfig( m_H, &flushBufCfg), "CP210x_GetFlushBufferConfig"); return flushBufCfg; } std::vector CCP210xDev::getSerNum( bool isAscii) const { std::vector str( MAX_UCHAR); BYTE CchStr = 0; AbortOnErr( CP210x_GetDeviceSerialNumber( m_H, str.data(), &CchStr, isAscii), "CP210x_GetDeviceSerialNumber"); str.resize( CchStr * (isAscii ? 1 : 2)); return str; } std::vector CCP210xDev::getManufacturer( bool isAscii) const { std::vector str( MAX_UCHAR); BYTE CchStr = 0; AbortOnErr( CP210x_GetDeviceManufacturerString( m_H, str.data(), &CchStr, isAscii), "CP210x_GetDeviceManufacturerString"); str.resize( CchStr * (isAscii ? 1 : 2)); return str; } std::vector CCP210xDev::getProduct( bool isAscii) const { std::vector str( MAX_UCHAR); BYTE CchStr = 0; AbortOnErr( CP210x_GetDeviceProductString( m_H, str.data(), &CchStr, isAscii), "CP210x_GetDeviceProductString"); str.resize( CchStr * (isAscii ? 1 : 2)); return str; } void CCP210xDev::setVidPid( WORD vid, WORD pid) const { AbortOnErr( CP210x_SetVid( m_H, vid), "CP210x_SetVid"); AbortOnErr( CP210x_SetPid( m_H, pid), "CP210x_SetPid"); } void CCP210xDev::setPowerMode( BYTE val) const { AbortOnErr( CP210x_SetSelfPower( m_H, val ? TRUE : FALSE ), "CP210x_SetSelfPower"); } void CCP210xDev::setMaxPower( BYTE val) const { AbortOnErr( CP210x_SetMaxPower( m_H, val), "CP210x_SetMaxPower"); } void CCP210xDev::setDevVer( WORD val) const { AbortOnErr( CP210x_SetDeviceVersion( m_H, val), "CP210x_SetDeviceVersion"); } void CCP210xDev::setFlushBufCfg( WORD val) const { AbortOnErr( CP210x_SetFlushBufferConfig( m_H, val), "CP210x_SetFlushBufferConfig"); } void CCP210xDev::setSerNum( const std::vector &str, bool isAscii) const { BYTE CchStr = static_cast ( str.size() / (isAscii ? 1 : 2)); AbortOnErr( CP210x_SetSerialNumber( m_H, const_cast( str.data()), CchStr, isAscii), "CP210x_SetSerialNumber"); } void CCP210xDev::setManufacturer( const std::vector &str, bool isAscii) const { BYTE CchStr = static_cast ( str.size() / (isAscii ? 1 : 2)); AbortOnErr( CP210x_SetManufacturerString( m_H, const_cast( str.data()), CchStr, isAscii), "CP210x_SetManufacturerString"); } void CCP210xDev::setProduct( const std::vector &str, bool isAscii) const { BYTE CchStr = static_cast ( str.size() / (isAscii ? 1 : 2)); AbortOnErr( CP210x_SetProductString( m_H, const_cast( str.data()), CchStr, isAscii), "CP210x_SetProductString"); } //--------------------------------------------------------------------------------- // CP2102N has non-standard get/set lock functions. #pragma pack(push, 1) // The original complete copy of the below struct is called Config_t in the CP2102N repo. // "Used to store default settings and customized values passed from host PC." union CCP2102NConfig { struct { // just the top of it, as far as we need WORD configSize; BYTE configVersion; // Allows Bootloader entry from VCP vendor command/HID report. Bootloader always runs // if flash address 0x0 is 0xFF. BYTE enableBootloader; // Allows configuration updates. If a bad burn happens, this will become // 0xff allowing a recovery. BYTE enableConfigUpdate; } Fields; BYTE Raw[ 0x2a6]; }; #pragma pack(pop) #define CP2102N_CONFIG_VERSION 1 #define CP2102N_CONFIG_UNLOCKED 0xff class CCP2102NDev : public CCP210xDev { public: CCP2102NDev( const CVidPid &FilterVidPid, DWORD devIndex) : CCP210xDev( FilterVidPid, devIndex) {} bool isLocked() const; void lock() const; }; bool CCP2102NDev::isLocked() const { CCP2102NConfig Config = {0}; AbortOnErr( CP210x_GetConfig( m_H, &Config.Raw[0], static_cast( sizeof( Config))), "CP210x_GetConfig"); if( Config.Fields.configVersion != CP2102N_CONFIG_VERSION) { throw CCustErr( "CP2102N returned unknown config version"); } if( Config.Fields.configSize < sizeof( Config.Fields)) { throw CCustErr( "CP2102N returned invalid config size"); } return Config.Fields.enableConfigUpdate != CP2102N_CONFIG_UNLOCKED; } void CCP2102NDev::lock() const { CCP2102NConfig Config; AbortOnErr( CP210x_GetConfig( m_H, &Config.Raw[0], static_cast( sizeof( Config))), "CP210x_GetConfig"); Config.Fields.enableConfigUpdate = 0; AbortOnErr( CP210x_SetConfig( m_H, &Config.Raw[0], static_cast( sizeof( Config))), "CP210x_SetConfig"); CCP2102NConfig finalConfig; AbortOnErr( CP210x_GetConfig( m_H, &finalConfig.Raw[0], static_cast( sizeof( finalConfig))), "CP210x_GetConfig"); if( memcmp( &Config.Raw[0], &finalConfig.Raw[0], sizeof( finalConfig))) { throw CCustErr( "CP2102N config verification failed after locking"); } } //--------------------------------------------------------------------------------- // Here is a bunch of customization parametersfound in cp210x devices. They are included // into each individual cp210x device that supports the parameter. //--------------------------------------------------------------------------------- struct CFlushBufferConfig { CFlushBufferConfig() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; WORD m_Config; }; bool CFlushBufferConfig::readParm( const std::string &parmName) { if( parmName == "FlushBufferConfig") { setSpecified( m_Specified, parmName); m_Config = readUshortParm(); readKeyword( "}"); // end of parameter list return true; } return false; } void CFlushBufferConfig::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } dev.setFlushBufCfg( m_Config); } void CFlushBufferConfig::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } if( m_Config != dev.getFlushBufCfg()) { throw CCustErr( "Failed FlushBufferConfig verification"); } } //--------------------------------------------------------------------------------- struct CDeviceMode { CDeviceMode() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; BYTE m_ModeECI; BYTE m_ModeSCI; }; bool CDeviceMode::readParm( const std::string &parmName) { if( parmName == "DeviceMode") { setSpecified( m_Specified, parmName); m_ModeECI = readUcharParm(); m_ModeSCI = readUcharParm(); readKeyword( "}"); // end of parameter list return true; } return false; } void CDeviceMode::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } AbortOnErr( CP210x_SetDeviceMode( dev.handle(), m_ModeECI, m_ModeSCI), "CP210x_SetDeviceMode"); } void CDeviceMode::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } BYTE ModeECI; BYTE ModeSCI; AbortOnErr( CP210x_GetDeviceMode( dev.handle(), &ModeECI, &ModeSCI), "CP210x_GetDeviceMode"); if( m_ModeECI != ModeECI || m_ModeSCI != ModeSCI) { throw CCustErr( "Failed DeviceMode verification"); } } //--------------------------------------------------------------------------------- struct CInterfaceString { CInterfaceString() { m_Specified = false; } bool readParm( BYTE ifc, const std::string &parmName); void program( BYTE ifc, const CCP210xDev &dev) const; void verify( BYTE ifc, const CCP210xDev &dev) const; private: bool m_Specified; bool m_IsAscii; std::vector m_str; }; bool CInterfaceString::readParm( BYTE ifc, const std::string &parmName) { char ifcDigit = '0' + ifc; if( parmName == std::string( "InterfaceStringAscii") + ifcDigit) { setSpecified( m_Specified, parmName); m_IsAscii = true; readByteArrayParm( m_str, MAX_UCHAR); readKeyword( "}"); // end of parameter list return true; } else if( parmName == std::string("InterfaceStringUnicode") + ifcDigit) { setSpecified( m_Specified, parmName); m_IsAscii = false; readByteArrayParm( m_str, MAX_UCHAR); readKeyword( "}"); // end of parameter list return true; } return false; } void CInterfaceString::program( BYTE ifc, const CCP210xDev &dev) const { if( !m_Specified) { return; } BYTE CchStr = static_cast ( m_str.size() / (m_IsAscii ? 1 : 2)); AbortOnErr( CP210x_SetInterfaceString( dev.handle(), ifc, const_cast( m_str.data()), CchStr, m_IsAscii), "CP210x_SetInterfaceString"); } void CInterfaceString::verify( BYTE ifc, const CCP210xDev &dev) const { if( !m_Specified) { return; } std::vector str( MAX_UCHAR); BYTE CchStr = 0; AbortOnErr( CP210x_GetDeviceInterfaceString( dev.handle(), ifc, str.data(), &CchStr, m_IsAscii), "CP210x_GetDeviceInterfaceString"); str.resize( CchStr * (m_IsAscii ? 1 : 2)); if( m_str != str) { throw CCustErr( "Failed InterfaceString verification"); } } //--------------------------------------------------------------------------------- struct CBaudRateConfig { CBaudRateConfig() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; BAUD_CONFIG m_Config[ NUM_BAUD_CONFIGS]; }; bool CBaudRateConfig::readParm( const std::string &parmName) { if( parmName == "BaudRateConfig") { setSpecified( m_Specified, parmName); readKeyword( "{"); for( DWORD i = 0; i < SIZEOF_ARRAY( m_Config); i++) { m_Config[ i].BaudGen = readUshort(); m_Config[ i].Timer0Reload = readUshort(); m_Config[ i].Prescaler = readUchar(); m_Config[ i].BaudRate = readUlong(); } readKeyword( "}"); readKeyword( "}"); // end of parameter list return true; } return false; } void CBaudRateConfig::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } AbortOnErr( CP210x_SetBaudRateConfig( dev.handle(), const_cast(&m_Config[ 0])), "CP210x_SetBaudRateConfig"); } void CBaudRateConfig::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } BAUD_CONFIG Config[ NUM_BAUD_CONFIGS]; AbortOnErr( CP210x_GetBaudRateConfig( dev.handle(), &Config[ 0]), "CP210x_GetBaudRateConfig"); for( DWORD i = 0; i < SIZEOF_ARRAY( m_Config); i++) { // printf("verify %d\n", Config[ i].BaudRate); // TODO remove if( m_Config[ i].BaudGen != Config[ i].BaudGen || m_Config[ i].Timer0Reload != Config[ i].Timer0Reload || m_Config[ i].Prescaler != Config[ i].Prescaler || m_Config[ i].BaudRate != Config[ i].BaudRate) { throw CCustErr( "Failed BaudRateConfig verification"); } } } //--------------------------------------------------------------------------------- struct CPortConfig { CPortConfig() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; PORT_CONFIG m_PortCfg; }; bool CPortConfig::readParm( const std::string &parmName) { if( parmName == "PortConfig") { setSpecified( m_Specified, parmName); readKeyword( "{"); m_PortCfg.Mode = readUshort(); m_PortCfg.Reset_Latch = readUshort(); m_PortCfg.Suspend_Latch = readUshort(); m_PortCfg.EnhancedFxn = readUchar(); readKeyword( "}"); readKeyword( "}"); // end of parameter list return true; } return false; } void CPortConfig::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } AbortOnErr( CP210x_SetPortConfig( dev.handle(), const_cast(&m_PortCfg)), "CP210x_SetPortConfig"); } void CPortConfig::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } PORT_CONFIG PortCfg; AbortOnErr( CP210x_GetPortConfig( dev.handle(), &PortCfg), "CP210x_GetPortConfig"); if( m_PortCfg.Mode != PortCfg.Mode || m_PortCfg.Reset_Latch != PortCfg.Reset_Latch || m_PortCfg.Suspend_Latch != PortCfg.Suspend_Latch || m_PortCfg.EnhancedFxn != PortCfg.EnhancedFxn) { throw CCustErr( "Failed PortConfig verification"); } } //--------------------------------------------------------------------------------- struct CDualPortConfig { CDualPortConfig() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; DUAL_PORT_CONFIG m_PortCfg; }; bool CDualPortConfig::readParm( const std::string &parmName) { if( parmName == "DualPortConfig") { setSpecified( m_Specified, parmName); readKeyword( "{"); m_PortCfg.Mode = readUshort(); m_PortCfg.Reset_Latch = readUshort(); m_PortCfg.Suspend_Latch = readUshort(); m_PortCfg.EnhancedFxn_ECI = readUchar(); m_PortCfg.EnhancedFxn_SCI = readUchar(); m_PortCfg.EnhancedFxn_Device = readUchar(); readKeyword( "}"); readKeyword( "}"); // end of parameter list return true; } return false; } void CDualPortConfig::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } AbortOnErr( CP210x_SetDualPortConfig( dev.handle(), const_cast(&m_PortCfg)), "CP210x_SetDualPortConfig"); } void CDualPortConfig::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } DUAL_PORT_CONFIG PortCfg; AbortOnErr( CP210x_GetDualPortConfig( dev.handle(), &PortCfg), "CP210x_GetDualPortConfig"); if( m_PortCfg.Mode != PortCfg.Mode || m_PortCfg.Reset_Latch != PortCfg.Reset_Latch || m_PortCfg.Suspend_Latch != PortCfg.Suspend_Latch || m_PortCfg.EnhancedFxn_ECI != PortCfg.EnhancedFxn_ECI || m_PortCfg.EnhancedFxn_SCI != PortCfg.EnhancedFxn_SCI || m_PortCfg.EnhancedFxn_Device != PortCfg.EnhancedFxn_Device) { throw CCustErr( "Failed DualPortConfig verification"); } } //--------------------------------------------------------------------------------- struct CQuadPortConfig { CQuadPortConfig() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; QUAD_PORT_CONFIG m_PortCfg; }; void readQuadPortState( QUAD_PORT_STATE &qps) { qps.Mode_PB0 = readUshort(); qps.Mode_PB1 = readUshort(); qps.Mode_PB2 = readUshort(); qps.Mode_PB3 = readUshort(); qps.Mode_PB4 = readUshort(); qps.LowPower_PB0 = readUshort(); qps.LowPower_PB1 = readUshort(); qps.LowPower_PB2 = readUshort(); qps.LowPower_PB3 = readUshort(); qps.LowPower_PB4 = readUshort(); qps.Latch_PB0 = readUshort(); qps.Latch_PB1 = readUshort(); qps.Latch_PB2 = readUshort(); qps.Latch_PB3 = readUshort(); qps.Latch_PB4 = readUshort(); } bool CQuadPortConfig::readParm( const std::string &parmName) { if( parmName == "QuadPortConfig") { setSpecified( m_Specified, parmName); readKeyword( "{"); readQuadPortState( m_PortCfg.Reset_Latch); readQuadPortState( m_PortCfg.Suspend_Latch); m_PortCfg.IPDelay_IFC0 = readUchar(); m_PortCfg.IPDelay_IFC1 = readUchar(); m_PortCfg.IPDelay_IFC2 = readUchar(); m_PortCfg.IPDelay_IFC3 = readUchar(); m_PortCfg.EnhancedFxn_IFC0 = readUchar(); m_PortCfg.EnhancedFxn_IFC1 = readUchar(); m_PortCfg.EnhancedFxn_IFC2 = readUchar(); m_PortCfg.EnhancedFxn_IFC3 = readUchar(); m_PortCfg.EnhancedFxn_Device = readUchar(); m_PortCfg.ExtClk0Freq = readUchar(); m_PortCfg.ExtClk1Freq = readUchar(); m_PortCfg.ExtClk2Freq = readUchar(); m_PortCfg.ExtClk3Freq = readUchar(); readKeyword( "}"); readKeyword( "}"); // end of parameter list return true; } return false; } void CQuadPortConfig::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } AbortOnErr( CP210x_SetQuadPortConfig( dev.handle(), const_cast(&m_PortCfg)), "CP210x_SetQuadPortConfig"); } bool isEqualQuadPortState( const QUAD_PORT_STATE &qps1, const QUAD_PORT_STATE &qps2) { if( qps1.Mode_PB0 != qps2.Mode_PB0 || qps1.Mode_PB1 != qps2.Mode_PB1 || qps1.Mode_PB2 != qps2.Mode_PB2 || qps1.Mode_PB3 != qps2.Mode_PB3 || qps1.Mode_PB4 != qps2.Mode_PB4 || qps1.LowPower_PB0 != qps2.LowPower_PB0 || qps1.LowPower_PB1 != qps2.LowPower_PB1 || qps1.LowPower_PB2 != qps2.LowPower_PB2 || qps1.LowPower_PB3 != qps2.LowPower_PB3 || qps1.LowPower_PB4 != qps2.LowPower_PB4 || qps1.Latch_PB0 != qps2.Latch_PB0 || qps1.Latch_PB1 != qps2.Latch_PB1 || qps1.Latch_PB2 != qps2.Latch_PB2 || qps1.Latch_PB3 != qps2.Latch_PB3 || qps1.Latch_PB4 != qps2.Latch_PB4) { return false; } return true; } void CQuadPortConfig::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } QUAD_PORT_CONFIG PortCfg; AbortOnErr( CP210x_GetQuadPortConfig( dev.handle(), &PortCfg), "CP210x_GetQuadPortConfig"); if( !isEqualQuadPortState( m_PortCfg.Reset_Latch, PortCfg.Reset_Latch ) || !isEqualQuadPortState( m_PortCfg.Suspend_Latch, PortCfg.Suspend_Latch ) || m_PortCfg.IPDelay_IFC0 != PortCfg.IPDelay_IFC0 || m_PortCfg.IPDelay_IFC1 != PortCfg.IPDelay_IFC1 || m_PortCfg.IPDelay_IFC2 != PortCfg.IPDelay_IFC2 || m_PortCfg.IPDelay_IFC3 != PortCfg.IPDelay_IFC3 || m_PortCfg.EnhancedFxn_IFC0 != PortCfg.EnhancedFxn_IFC0 || m_PortCfg.EnhancedFxn_IFC1 != PortCfg.EnhancedFxn_IFC1 || m_PortCfg.EnhancedFxn_IFC2 != PortCfg.EnhancedFxn_IFC2 || m_PortCfg.EnhancedFxn_IFC3 != PortCfg.EnhancedFxn_IFC3 || m_PortCfg.EnhancedFxn_Device != PortCfg.EnhancedFxn_Device || m_PortCfg.ExtClk0Freq != PortCfg.ExtClk0Freq || m_PortCfg.ExtClk1Freq != PortCfg.ExtClk1Freq || m_PortCfg.ExtClk2Freq != PortCfg.ExtClk2Freq || m_PortCfg.ExtClk3Freq != PortCfg.ExtClk3Freq) { throw CCustErr( "Failed QuadPortConfig verification"); } } //--------------------------------------------------------------------------------- struct CConfig { CConfig() { m_Specified = false; } bool readParm( const std::string &parmName); void program( const CCP210xDev &dev) const; void verify( const CCP210xDev &dev) const; private: bool m_Specified; CCP2102NConfig m_Config; }; bool CConfig::readParm( const std::string &parmName) { if( parmName == "Config") { setSpecified( m_Specified, parmName); // Jeff said it's best to always write the whole thing, hence "Exact" read std::vector Config; readByteArrayParmExact( Config, sizeof( m_Config)); readKeyword( "}"); // end of parameter list std::memcpy( &m_Config.Raw[0], &Config[0], sizeof( m_Config)); // Copy into the formatted storage // Few sanity checks if( m_Config.Fields.configVersion != CP2102N_CONFIG_VERSION) { throw CUsageErr( "CP2102N Config::configVersion is invalid"); } if( m_Config.Fields.configSize != sizeof(CCP2102NConfig)) { throw CUsageErr( "CP2102N Config::configSize is invalid"); } if( m_Config.Fields.enableConfigUpdate != CP2102N_CONFIG_UNLOCKED) { // The user isn't trying to lock the config by enableConfigUpdate. We don't allow this, // we lock it explicitly after verification, by writing same data with enableConfigUpdate // clear. throw CUsageErr( "CP2102N Config::enableConfigUpdate attempts to lock, use --lock instead"); } return true; } return false; } void CConfig::program( const CCP210xDev &dev) const { if( !m_Specified) { return; } AbortOnErr( CP210x_SetConfig( dev.handle(), const_cast( &m_Config.Raw[0]), static_cast( sizeof( m_Config.Raw))), "CP210x_SetConfig"); } void CConfig::verify( const CCP210xDev &dev) const { if( !m_Specified) { return; } CCP2102NConfig readConfig; AbortOnErr( CP210x_GetConfig( dev.handle(), &readConfig.Raw[0], static_cast( sizeof( readConfig.Raw))), "CP210x_GetConfig"); // A little hack to workaround locked configurations. // If the Config on the chip is locked, the dumb array comparison will fail because of enableConfigUpdate. // But it wouldn't be a valid failure. So, hack the "unlocked" value into it before comparing. ASSERT( m_Config.Fields.enableConfigUpdate == CP2102N_CONFIG_UNLOCKED); readConfig.Fields.enableConfigUpdate = CP2102N_CONFIG_UNLOCKED; if( memcmp( &readConfig.Raw[0], &m_Config.Raw[0], sizeof( readConfig))) { throw CCustErr( "Failed Config verification"); } } //--------------------------------------------------------------------------------- // Base class for all cp210x devices, contains ommmon customization parameters //--------------------------------------------------------------------------------- template< class TDev > struct CCP210xParms : public CDevParms { virtual bool supportsUnicode() const { return true; } virtual void readParm( const std::string &parmName); void program( const TDev &dev, const std::vector *pSerNum) const; void verify( const TDev &dev, CSerNumSet &serNumSet) const; }; template< class TDev > void CCP210xParms::readParm( const std::string &parmName) { CDevParms::readParm( parmName); } template< class TDev > void CCP210xParms::program( const TDev &dev, const std::vector *pSerNum) const { #if 0 // TODO remove if( pSerNum) { std::vector sn = *pSerNum; sn.push_back( 0); printf( "program serial num: %s\n", sn.data()); sn.pop_back(); } #endif CDevParms::program( dev, pSerNum); if( CDevParms::m_VidPidSpecified) { dev.setVidPid( CDevParms::m_Vid, CDevParms::m_Pid); } if( CDevParms::m_PowerModeSpecified) { dev.setPowerMode( CDevParms::m_PowerMode); } if( CDevParms::m_MaxPowerSpecified) { dev.setMaxPower( CDevParms::m_MaxPower); } if( CDevParms::m_DevVerSpecified) { dev.setDevVer( CDevParms::m_DevVer); } } template< class TDev > void CCP210xParms::verify( const TDev &dev, CSerNumSet &serNumSet) const { CDevParms::verify( dev, serNumSet); } //--------------------------------------------------------------------------------- struct CCP2101Parms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; }; void CCP2101Parms::readParm( const std::string &parmName) { CCP210xParms::readParm( parmName); } void CCP2101Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); } void CCP2101Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); } //--------------------------------------------------------------------------------- struct CCP2102Parms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; private: CBaudRateConfig m_BaudRateCfg; }; void CCP2102Parms::readParm( const std::string &parmName) { if( m_BaudRateCfg.readParm( parmName)) { return; } CCP210xParms::readParm( parmName); } void CCP2102Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_BaudRateCfg.program( dev); } void CCP2102Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_BaudRateCfg.verify( dev); } //--------------------------------------------------------------------------------- struct CCP2102NParms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP2102NDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP2102NDev &dev, CSerNumSet &serNumSet) const; private: CConfig m_Cfg; }; void CCP2102NParms::readParm( const std::string &parmName) { if( m_Cfg.readParm( parmName)) { return; } CCP210xParms::readParm( parmName); } void CCP2102NParms::program( const CCP2102NDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_Cfg.program( dev); } void CCP2102NParms::verify( const CCP2102NDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_Cfg.verify( dev); } //--------------------------------------------------------------------------------- struct CCP2103Parms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; private: CBaudRateConfig m_BaudRateCfg; CPortConfig m_PortCfg; }; void CCP2103Parms::readParm( const std::string &parmName) { if( m_PortCfg.readParm( parmName)) { return; } if( m_BaudRateCfg.readParm( parmName)) { return; } CCP210xParms::readParm( parmName); } void CCP2103Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_BaudRateCfg.program( dev); m_PortCfg.program( dev); } void CCP2103Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_BaudRateCfg.verify( dev); m_PortCfg.verify( dev); } //--------------------------------------------------------------------------------- struct CCP2104Parms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; private: CPortConfig m_PortCfg; CFlushBufferConfig m_FlushBufferConfig; }; void CCP2104Parms::readParm( const std::string &parmName) { if( m_PortCfg.readParm( parmName)) { return; } if( m_FlushBufferConfig.readParm( parmName)) { return; } CCP210xParms::readParm( parmName); } void CCP2104Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_PortCfg.program( dev); m_FlushBufferConfig.program( dev); } void CCP2104Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_PortCfg.verify( dev); m_FlushBufferConfig.verify( dev); } //--------------------------------------------------------------------------------- struct CCP2105Parms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; private: CFlushBufferConfig m_FlushBufferConfig; CDeviceMode m_DeviceMode; CDualPortConfig m_PortCfg; CInterfaceString m_IfcStr[ 2]; }; void CCP2105Parms::readParm( const std::string &parmName) { if( m_FlushBufferConfig.readParm( parmName)) { return; } if( m_DeviceMode.readParm( parmName)) { return; } if( m_PortCfg.readParm( parmName)) { return; } for( BYTE i = 0; i < SIZEOF_ARRAY( m_IfcStr); i++) { if( m_IfcStr[ i].readParm( i, parmName)) { return; } } CCP210xParms::readParm( parmName); } void CCP2105Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_FlushBufferConfig.program( dev); m_DeviceMode.program( dev); m_PortCfg.program( dev); for( BYTE i = 0; i < SIZEOF_ARRAY( m_IfcStr); i++) { m_IfcStr[ i].program( i, dev); } } void CCP2105Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_FlushBufferConfig.verify( dev); m_DeviceMode.verify( dev); m_PortCfg.verify( dev); for( BYTE i = 0; i < SIZEOF_ARRAY( m_IfcStr); i++) { m_IfcStr[ i].verify( i, dev); } } //--------------------------------------------------------------------------------- struct CCP2108Parms : public CCP210xParms { CCP2108Parms() : m_ManufStr( true /*supportsUnicode*/) {} virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; private: CFlushBufferConfig m_FlushBufferConfig; CManufacturerString m_ManufStr; CQuadPortConfig m_PortCfg; CInterfaceString m_IfcStr[ 4]; }; void CCP2108Parms::readParm( const std::string &parmName) { if( m_FlushBufferConfig.readParm( parmName)) { return; } if( m_ManufStr.readParm( parmName)) { return; } if( m_PortCfg.readParm( parmName)) { return; } for( BYTE i = 0; i < SIZEOF_ARRAY( m_IfcStr); i++) { if( m_IfcStr[ i].readParm( i, parmName)) { return; } } CCP210xParms::readParm( parmName); } void CCP2108Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_FlushBufferConfig.program( dev); m_ManufStr.program( dev); m_PortCfg.program( dev); for( BYTE i = 0; i < SIZEOF_ARRAY( m_IfcStr); i++) { m_IfcStr[ i].program( i, dev); } } void CCP2108Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_FlushBufferConfig.verify( dev); m_ManufStr.verify( dev); m_PortCfg.verify( dev); for( BYTE i = 0; i < SIZEOF_ARRAY( m_IfcStr); i++) { m_IfcStr[ i].verify( i, dev); } } //--------------------------------------------------------------------------------- struct CCP2109Parms : public CCP210xParms { virtual void readParm( const std::string &parmName); virtual void program( const CCP210xDev &dev, const std::vector *pSerNum) const; virtual void verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const; private: CBaudRateConfig m_BaudRateCfg; }; void CCP2109Parms::readParm( const std::string &parmName) { if( m_BaudRateCfg.readParm( parmName)) { return; } CCP210xParms::readParm( parmName); } void CCP2109Parms::program( const CCP210xDev &dev, const std::vector *pSerNum) const { CCP210xParms::program( dev, pSerNum); m_BaudRateCfg.program( dev); } void CCP2109Parms::verify( const CCP210xDev &dev, CSerNumSet &serNumSet) const { CCP210xParms::verify( dev, serNumSet); m_BaudRateCfg.verify( dev); } //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- void LibSpecificMain( const CDevType &devType, const CVidPid &vidPid, int argc, const char * argv[]) { if( devType.Value() == CP210x_CP2101_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2102_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2102N_QFN28_VERSION || devType.Value() == CP210x_CP2102N_QFN24_VERSION || devType.Value() == CP210x_CP2102N_QFN20_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2103_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2104_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2105_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2108_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else if( devType.Value() == CP210x_CP2109_VERSION) { DevSpecificMain ( devType, vidPid, argc, argv); } else { throw CSyntErr( "Unsupported PartNum"); } }