//************************************************************************************************** // Component.cpp * // --------------- * // Started : 2004-05-14 * // Last Update : 2016-10-23 * // Copyright : (C) 2004-2016 MSWaters * //************************************************************************************************** //************************************************************************************************** // * // This program is free software; you can redistribute it and/or modify it under the * // terms of the GNU General Public License as published by the Free Software Foundation; * // either version 3 of the License, or (at your option) any later version. * // * //************************************************************************************************** #include "Component.hpp" //************************************************************************************************** // Finish the definition of the ArrayComponent type. The following expands into // some C++ code and so should only be compiled once (ie. don't put this into a // header file rather put it in a source file or there will be linker errors). #include WX_DEFINE_OBJARRAY( ArrayComponent ); //************************************************************************************************** // Constructor. Component::Component( void ) : wxString( ) { bClear( ); } //************************************************************************************************** // Destructor. Component::~Component( ) { } //************************************************************************************************** // Get the component ports. void Component::GetPorts( void ) { // Not yet implemented ??? } //************************************************************************************************** // Test the values against each other. // // Return Values : // true - Success // false - Failure bool Component::bValidate( void ) { m_osErrMsg.Empty( ); if( IsEmpty( ) ) bSetErrMsg( wxT("component is empty") ); else if( m_osName.IsEmpty( ) ) bSetErrMsg( wxT("component has no name") ); else if( m_osaNodes.GetCount( ) < 2 ) bSetErrMsg( wxT("component has less than two nodes") ); else if( m_osValue.IsEmpty( ) ) bSetErrMsg( wxT("component has no value") ); return( bIsValid( ) ); } //************************************************************************************************** // Attempt to set the objects error message string attribute. // // Argument List : // rosErrMsg - A reference to a string containing the new error message // // Return Values : // true - Success // false - Failure bool Component::bSetErrMsg( const wxString & rosErrMsg ) { if( ! bIsValid( ) ) return( false ); m_osErrMsg = rosErrMsg; return( true ); } //************************************************************************************************** // Compare algorithm for sorting Component objects. // // Argument List : // ppo1 - The address of a pointer to the first Component object to compare // ppo2 - The address of a pointer to the second Component object to compare // // Return Values : // >0 - If *(*ppo1) is greater than *(*ppo2) // =0 - If *(*ppo1) is equal to *(*ppo2) // <0 - If *(*ppo1) is less than *(*ppo2) int Component::iCompare( Component ** ppo1, Component ** ppo2 ) { const wxString & ros1 = (const wxString &) **ppo1; const wxString & ros2 = (const wxString &) **ppo2; return( ros1.Cmp( ros2 ) ); } //************************************************************************************************** // Clear the object attributes. // // Return Values : // true - Success // false - Failure bool Component::bClear( void ) { wxString::Empty( ); m_osErrMsg = wxT("Invalid"); m_osName .Clear( ); m_osaNodes.Clear( ); m_osValue .Clear( ); m_eType = eCPNT_NONE; m_osaPorts.Clear( ); return( true ); } //************************************************************************************************** // Parse a component definition string extracted from a netlist. // // Return Values : // true - Success // false - Failure bool Component::bParse( void ) { wxStringTokenizer ostk1; wxString os1; size_t sz1; // Clear the object attributes os1 = (wxString &) *this; bClear( ); wxString::assign( os1 ); m_osErrMsg.Empty( ); // Tokenize the command string if( IsEmpty( ) ) return( bValidate( ) ); ostk1.SetString( os1 ); // Extract the component name bSetName( ostk1.GetNextToken( ) ); // Extract the nodes the component is connected to if( ! ostk1.HasMoreTokens( ) ) return( bValidate( ) ); bSetNodes( ostk1.GetString( ) ); for( sz1=0; sz1=wxT('a') && oc1<=wxT('z')) && !(oc1>=wxT('A') && oc1<=wxT('Z')) ) return( false ); m_osName = os1; // Determine the component type and units type m_eType = eGetType( m_osName ); return( true ); } //************************************************************************************************** // Set the component nodes. // // Argument List : // rosNodes - A reference to a string containing component nodes eg. "2,1". // // Return Values : // true - Success // false - Failure bool Component::bSetNodes( const wxString & rosNodes ) { wxStringTokenizer ostk1; size_t szNodeCnt; size_t sz1; // Tokenize the name string ostk1.SetString( rosNodes, wxT(" \t\r\n,") ); if( ostk1.CountTokens( ) <=0 ) return( false ); // Determine how many nodes to look for based on the component type switch( m_eType ) { case eCPNT_CAP : case eCPNT_RES : case eCPNT_IND : case eCPNT_CIND : case eCPNT_DIODE : case eCPNT_VCVS : case eCPNT_CCCS : case eCPNT_VCCS : case eCPNT_CCVS : case eCPNT_IVS : case eCPNT_ICS : case eCPNT_NLDS : case eCPNT_NLDCS : case eCPNT_NLDVS : case eCPNT_STJ : szNodeCnt = 2; break; case eCPNT_JFET : case eCPNT_MOSFET : case eCPNT_MESFET : case eCPNT_BJT : case eCPNT_VCSW : case eCPNT_CCSW : case eCPNT_URC : szNodeCnt = 3; break; case eCPNT_TLINE : case eCPNT_LTRA : case eCPNT_TXL : szNodeCnt = 4; break; case eCPNT_LOGIC : szNodeCnt = ostk1.CountTokens( ) - 2; break; case eCPNT_CPL : case eCPNT_SUBCKT : szNodeCnt = ostk1.CountTokens( ) - 1; break; // For the default guess that all but the last token are nodes default : szNodeCnt = ostk1.CountTokens( ) - 1; break; } if( szNodeCnt > ostk1.CountTokens( ) ) return( false ); // Extract the nodes the component is connected to m_osaNodes.Empty( ); if( szNodeCnt > 0 ) { for( sz1=0; sz1mb_str( ) << '\n'; std::cout << rosPrefix.mb_str( ) << "m_osErrMsg : " << m_osErrMsg .mb_str( ) << '\n'; std::cout << rosPrefix.mb_str( ) << "m_eType : "; switch( m_eType ) { case eCPNT_CAP : std::cout << "eCPNT_CAP" ; break; // Capacitor case eCPNT_RES : std::cout << "eCPNT_RES" ; break; // Resistor case eCPNT_IND : std::cout << "eCPNT_IND" ; break; // Inductor case eCPNT_CIND : std::cout << "eCPNT_CIND" ; break; // Coupled (Mutual) Inductors case eCPNT_DIODE : std::cout << "eCPNT_DIODE" ; break; // Diode case eCPNT_BJT : std::cout << "eCPNT_BJT" ; break; // BJT (Bipolar Junction Transistor) case eCPNT_JFET : std::cout << "eCPNT_JFET" ; break; // JFET (Junction Field-Effect Transistor) case eCPNT_MOSFET : std::cout << "eCPNT_MOSFET"; break; // MOSFET (Metal-Oxide Semiconductor Field-Effect Transistor) case eCPNT_MESFET : std::cout << "eCPNT_MESFET"; break; // MESFET (Metal–Semiconductor Field Effect Transistor) case eCPNT_VCVS : std::cout << "eCPNT_VCVS" ; break; // Voltage Controlled Voltage Source case eCPNT_CCCS : std::cout << "eCPNT_CCCS" ; break; // Current Controlled Current Source case eCPNT_VCCS : std::cout << "eCPNT_VCCS" ; break; // Voltage Controlled Current Source case eCPNT_CCVS : std::cout << "eCPNT_CCVS" ; break; // Current Controlled Voltage Source case eCPNT_TLINE : std::cout << "eCPNT_TLINE" ; break; // Lossless Transmission Line case eCPNT_LTRA : std::cout << "eCPNT_LTRA" ; break; // Lossy Transmission Line (LTRA) case eCPNT_CPL : std::cout << "eCPNT_CPL" ; break; // Coupled Multi-conductor Transmission Line (CPL) case eCPNT_TXL : std::cout << "eCPNT_TXL" ; break; // Single Lossy Transmission Line (TXL) case eCPNT_URC : std::cout << "eCPNT_URC" ; break; // Uniform Distributed RC Transmission Line (URC) case eCPNT_ICS : std::cout << "eCPNT_ICS" ; break; // Independent Current Source case eCPNT_IVS : std::cout << "eCPNT_IVS" ; break; // Independent Voltage Source case eCPNT_NLDS : std::cout << "eCPNT_NLDS" ; break; // Non-Linear Dependent Source case eCPNT_NLDCS : std::cout << "eCPNT_NLDCS" ; break; // Non-Linear Dependent Current Source case eCPNT_NLDVS : std::cout << "eCPNT_NLDVS" ; break; // Non-Linear Dependent Voltage Source case eCPNT_CCSW : std::cout << "eCPNT_CCSW" ; break; // Current Controlled Switch case eCPNT_VCSW : std::cout << "eCPNT_VCSW" ; break; // Voltage Controlled Switch case eCPNT_SUBCKT : std::cout << "eCPNT_SUBCKT"; break; // Sub-circuit case eCPNT_LOGIC : std::cout << "eCPNT_LOGIC" ; break; // Logic Device case eCPNT_STJ : std::cout << "eCPNT_STJ" ; break; // Super-conducting Tunnel Junction default : std::cout << "Invalid"; } std::cout << '\n'; std::cout << rosPrefix.mb_str( ) << "m_osName : " << m_osName .mb_str( ) << '\n'; std::cout << rosPrefix.mb_str( ) << "m_osaNodes[ ] : "; for( sz1=0; sz1 0 ) std::cout << ", "; std::cout << m_osaNodes.Item( sz1 ).mb_str( ); } std::cout << '\n'; std::cout << rosPrefix.mb_str( ) << "m_osaPorts[ ] : "; for( sz1=0; sz1 0 ) std::cout << " "; std::cout << m_osaPorts.Item( sz1 ).mb_str( ); } std::cout << '\n'; std::cout << rosPrefix.mb_str( ) << "m_osValue : " << m_osValue .mb_str( ) << '\n'; std::cout << rosPrefix.mb_str( ) << "rosGetNumValue( ) : " << rosGetNumValue( ).mb_str( ) << '\n'; std::cout << rosPrefix.mb_str( ) << "eGetUnitsType( ) : "; switch( eGetUnitsType( m_osName ) ) { case eUNITS_CAP : std::cout << "eUNITS_CAP"; break; case eUNITS_IND : std::cout << "eUNITS_IND"; break; case eUNITS_RES : std::cout << "eUNITS_RES"; break; case eUNITS_VOLT : std::cout << "eUNITS_VOLT"; break; case eUNITS_CURR : std::cout << "eUNITS_CURR"; break; case eUNITS_TIME : std::cout << "eUNITS_TIME"; break; case eUNITS_FREQ : std::cout << "eUNITS_FREQ"; break; case eUNITS_PHAD : std::cout << "eUNITS_PHAD"; break; case eUNITS_PHAR : std::cout << "eUNITS_PHAR"; break; case eUNITS_TMPC : std::cout << "eUNITS_TMPC"; break; case eUNITS_TMPF : std::cout << "eUNITS_TMPF"; break; case eUNITS_EXP : std::cout << "eUNITS_EXP"; break; case eUNITS_NONE : std::cout << "eUNITS_NONE"; break; default : std::cout << "Invalid"; break; } std::cout << '\n'; } //************************************************************************************************** // Test Utility * //************************************************************************************************** #ifdef TEST_COMPONENT using namespace std; // Function prototypes void Usage( char * psAppName ); //************************************************************************************************** int main( int argc, char * argv[ ] ) { // This function is used in wxBase only and only if an wxApp object isn't created at all. In this // case wxInitialize( ) must be called in main( ) before calling any other wxWidgets functions. if( ! wxInitialize( ) ) exit( EXIT_FAILURE ); wxString osCpnt; wxString os1; // Validate the argument count passed to the application if( argc > 2 ) { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); } // Process the command line arguments if( argc > 1 ) { os1 = wxConvLibc.cMB2WC( argv[ 1 ] ); if( os1.at( 0 ) == wxT('-') ) { if( os1.at( 1 ) == wxT('h') ) { Usage( argv[ 0 ] ); exit( EXIT_SUCCESS ); } else { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); } } } else { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); } // Display the utility banner cout << "\n Component Class Test Utility" << "\n Version 1.09 (2016-09-29)\n"; // Create a component object Component oCpnt; // Use the following command example to check the formatter and the parser : osCpnt = wxT("Vin 2 0 AC 1V"); // This definition does contain TABs and SPACEs cout << "\nCpnt defn to test : " << osCpnt.mb_str( ) << "\n\n"; // ******************** Test the formatter ******************** cout << "Test the component formatter :"; // Set things up for a formatter test oCpnt.bClear( ); oCpnt.bSetName ( wxT("Vin") ); oCpnt.bSetNodes( wxT("2,0") ); oCpnt.bSetValue( wxT("AC 1V") ); // Run the formatter cout << "\n Run formatter : "; if( oCpnt.bFormat( ) ) cout << "OK"; else cout << "FAULT (" << oCpnt.rosGetErrMsg( ).mb_str( ) << ')'; // Test the formatter output cout << "\n Test format : "; if( (wxString) oCpnt == Component::rosTrim( osCpnt ) ) cout << "OK\n" << " Component defn : " << oCpnt.rosGetString( ).mb_str( ) << '\n'; else { // There's been an error so print the component contents cout << "FAULT\n"; cout << " oCpnt Contents : \n"; oCpnt.Print( wxT(" ") ); } cout << "\n"; // ********************* Test the parser ********************* cout << "Test the component parser :"; // Set things up for a parser test oCpnt.bClear( ); oCpnt = osCpnt; // Run the parser cout << "\n Run parser : "; if( oCpnt.bParse( ) ) cout << "OK"; else cout << "FAULT (" << oCpnt.rosGetErrMsg( ).mb_str( ) << ')'; // Test the parser output oCpnt.bFormat( ); cout << "\n Test format : "; if( (wxString) oCpnt == Component::rosTrim( osCpnt ) ) cout << "OK\n" << " Component defn : " << oCpnt.rosGetString( ).mb_str( ) << '\n'; else { // There's been an error so print the component contents cout << "FAULT\n"; cout << " oCpnt Contents : \n"; oCpnt.Print( wxT(" ") ); } cout << "\n"; // This function must be called for each successful call to wxInitialize( ). Clean up; the library // can't be used any more. wxInitialize( ); exit( EXIT_SUCCESS ); } //************************************************************************************************** void Usage( char * psAppName ) { cout << "\nUsage : " << psAppName << " [-OPTIONS] [CPNTDEF]" << "\nOptions : -h : Print usage (this message)" << "\n CPNTDEF : An component definition (not yet implemented)" << "\n\n"; } #endif // TEST_COMPONENT //**************************************************************************************************