//************************************************************************************************** // CmdNgSpicePR.cpp * // ------------------ * // Started : 2007-10-16 * // Last Update : 2016-10-01 * // Copyright : (C) 2007-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 "CmdNgSpicePR.hpp" //************************************************************************************************** // Constructor. CmdNgSpicePR::CmdNgSpicePR( void ) { bSetDefaults( ); } //************************************************************************************************** // Destructor. CmdNgSpicePR::~CmdNgSpicePR( ) { } //************************************************************************************************** // Check that the object attributes are valid. // // Return Values : // true - Success // false - Failure bool CmdNgSpicePR::bValidate( void ) { CmdBase::bValidate( ); if( m_osaNodes.GetCount( )<=0 && m_osaCpnts.GetCount( )<=0 ) SetErrMsg( wxT("No components or nodes have been selected.") ); if( ! m_bParams[ ePARAM_VLT ] ) SetErrMsg( wxT("No parameters selected.") ); return( bIsValid( ) ); } //************************************************************************************************** // Set the object attributes to they're default values. // // Return Values : // true - Success // false - Failure bool CmdNgSpicePR::bSetDefaults( void ) { int i1; CmdBase::bSetDefaults( ); m_eSimEng = eSIMR_NGSPICE; m_eCmdType = eCMD_PR; m_eAnaType = eCMD_NONE; m_osaNodes.Empty( ); m_osaCpnts.Empty( ); for( i1=0; i1<(int)ePARAM_NONE; i1++ ) m_bParams[ i1 ] = false; for( i1=0; i1<(int)eCPXPT_NONE; i1++ ) m_bCpxPts[ i1 ] = false; return( true ); } //************************************************************************************************** // Set the analysis type. // // Argument List : // eAnaType - An analysis command type // // Return Values : // true - Success // false - Failure bool CmdNgSpicePR::bSetAnaType( eTypeCmd eAnaType ) { // Does anything actually need to be done? if( eAnaType == m_eAnaType ) return( true ); // Check that the desired analysis type is supported switch( eAnaType ) { case eCMD_OP : case eCMD_DC : case eCMD_AC : case eCMD_TR : break; default : return( false ); } m_eAnaType = eAnaType; return( true ); } //************************************************************************************************** // Parse the command string. // // Eg.s : .PRINT AC VM(6,0) 0-VM(5) VM(1,7) VM(2) VP(6,0) 0-VP(5) VP(1,7) VP(2) // .PRINT AC VDB(4) // // Return Values : // true - Success // false - Failure bool CmdNgSpicePR::bParse( void ) { wxStringTokenizer ostk1; Component oCpnt1; wxString os1, os2; int i1, i2; size_t sz1; // Clear the object attributes os1 = *this; bSetDefaults( ); assign( os1 ); // Tokenize the command string ostk1.SetString( *this ); if( ostk1.CountTokens( ) < 3 ) return( bValidate( ) ); // Check command type os1 = ostk1.GetNextToken( ).Left( 3 ).Upper( ); if( os1 != wxT(".PR") ) return( bValidate( ) ); // Extract the analysis type os1 = ostk1.GetNextToken( ); if( os1 == wxT("DC") ) m_eAnaType = eCMD_DC; else if( os1 == wxT("AC") ) m_eAnaType = eCMD_AC; else if( os1 == wxT("TRAN") ) m_eAnaType = eCMD_TR; else return( bValidate( ) ); // Standardize the argument list format; there are 3 possible formats eg. V(n), V(n,m) or 0-V(n), // reformat the latter to : V(0,n). os2.Empty( ); while( ostk1.HasMoreTokens( ) ) { os1 = ostk1.GetNextToken( ); if( os1.Length( ) < 4 ) return( bValidate( ) ); if( os1.StartsWith( wxT("0-") ) ) { i1 = os1.Index( wxT('(') ); i2 = os1.Index( wxT(')') ); if( i1!=-1 && i2!=-1 && i2>(i1+1) ) os1 = os1.Mid( 2, (size_t) i1-1 ) + wxT("0,") + os1.Mid( (size_t) i1+1 ); } os2 << os1 << wxT(' '); } ostk1.SetString( os2 ); // Extract the parameters to derive, any complex parts and test component and/or test node labels while( ostk1.HasMoreTokens( ) ) { // Extract the next field os1 = ostk1.GetNextToken( ); // Extract the parameter specifiers switch( (char) os1.GetChar( 0 ) ) { case wxT('V') : m_bParams[ ePARAM_VLT ] = true; break; case wxT('I') : m_bParams[ ePARAM_CUR ] = true; break; case wxT('P') : m_bParams[ ePARAM_PWR ] = true; break; case wxT('R') : m_bParams[ ePARAM_RES ] = true; break; default : return( bValidate( ) ); } // Extract the complex parts if the analysis type is AC if( m_eAnaType == eCMD_AC ) { switch( (char) os1.GetChar( 1 ) ) { case wxT('M') : m_bCpxPts[ eCPXPT_MAG ] = true; break; case wxT('P') : m_bCpxPts[ eCPXPT_PHASE ] = true; break; case wxT('R') : m_bCpxPts[ eCPXPT_REAL ] = true; break; case wxT('I') : m_bCpxPts[ eCPXPT_IMAG ] = true; break; case wxT('D') : if( os1.Mid( 1, 2 ).Upper( ) == wxT("DB") ) { m_bCpxPts[ eCPXPT_MAG ] = true; m_bCpxPts[ eCPXPT_MAGDB ] = true; break; } default : return( bValidate( ) ); } } // Extract the node and component label/s, there are 2 possible formats eg. V(n) or V(n,m,...), // the first denotes a node and the second component. i1 = os1.Index( wxT('(') ); i2 = os1.Index( wxT(')') ); if( i1!=-1 && i2!=-1 && i2>(i1+1) ) { os1 = os1.Mid( (size_t) i1+1, (size_t) i2-i1-1 ); if( os1.Find( wxT(',') ) == wxNOT_FOUND ) { // This is a node, add it to the list if it's not already there if( m_osaNodes.Index( os1 ) == wxNOT_FOUND ) m_osaNodes.Add( os1 ); } else { // This is a component, add it to the list if it's not already there for( sz1=0; sz1sz1+1 ) { os2 = os1.SubString( sz1+1, sz2-1 ); oCpnt1 = NetList::roGetCpnt( os2 ); if( m_osaCpnts.Index( os2 )!=wxNOT_FOUND && oCpnt1.bIsValid( ) ) { os1.Remove( sz1+1, sz2-sz1-1 ); os1.insert( sz1+1, oCpnt1.rosGetNodes( ) ); } sz1 = os1.find( wxT('('), sz2 ); sz2 = os1.find( wxT(')'), sz1 ); } osCmd << wxT(' ') << os1; // Modify the argument list slightly; reformat V(0,n) to 0-V(n) otherwise NG-Spice barfs ostk1.SetString( osCmd ); osCmd.Empty( ); while( ostk1.HasMoreTokens( ) ) { os1 = ostk1.GetNextToken( ); if( (i1=os1.Find( wxT("(0,") )) != wxNOT_FOUND ) { os1.Remove( (size_t) i1+1, 2 ); os1.Prepend( wxT("0-") ); } if( ! osCmd.IsEmpty( ) ) osCmd << wxT(' '); osCmd << os1; } // Assign the command string value to the base class assign( osCmd ); return( bValidate( ) ); } //************************************************************************************************** // Get the list of parameters to print. // // Return Values : // The number of parameters to derive const wxString & CmdNgSpicePR::rosGetParamLst( void ) { static wxString osParamLst; wxString osParam, osCpxPt; int i1, i2, i3; // Clear the static variable osParamLst = wxT(""); // Sequence through the various parameter types for( i1=0; i1<(int)ePARAM_NONE; i1++ ) { if( ! m_bParams[ i1 ] ) continue; switch( (eTypeParam) i1 ) { case ePARAM_VLT : osParam = wxT('V'); break; case ePARAM_CUR : osParam = wxT('I'); break; case ePARAM_PWR : osParam = wxT('P'); break; case ePARAM_RES : osParam = wxT('R'); break; default : break; } // Sequence through the various complex parts for( i2=0; i2<(int)eCPXPT_NONE-1; i2++ ) { if( m_eAnaType == eCMD_AC ) { if( ! m_bCpxPts[ i2 ] ) continue; switch( (eTypeCpxPt) i2 ) { case eCPXPT_MAG : osCpxPt = ( m_bCpxPts[ eCPXPT_MAGDB ] ? wxT("DB") : wxT("M") ); break; case eCPXPT_PHASE : osCpxPt = wxT('P'); break; case eCPXPT_REAL : osCpxPt = wxT('R'); break; case eCPXPT_IMAG : osCpxPt = wxT('I'); break; default : break; } } else osCpxPt = wxT(""); // Sequence throught all the components and nodes for( i3=0; i3<(int)m_osaCpnts.GetCount( ); i3++ ) osParamLst << osParam << osCpxPt << wxT('(') << m_osaCpnts.Item( i3 ) << wxT(") "); for( i3=0; i3<(int)m_osaNodes.GetCount( ); i3++ ) osParamLst << osParam << osCpxPt << wxT('(') << m_osaNodes.Item( i3 ) << wxT(") "); if( m_eAnaType != eCMD_AC ) break; } } osParamLst.Trim( ); return( osParamLst ); } //************************************************************************************************** // Get the total number of parameters to print. // // Return Values : // The number of parameters to derive int CmdNgSpicePR::iGetParamCnt( void ) { int iProbes, iParams, iCpxPts, i1; iProbes = m_osaNodes.GetCount( ) + m_osaCpnts.GetCount( ); for( iParams=0, i1=0; i1<(int)ePARAM_NONE; i1++ ) if( m_bParams[ i1 ] ) iParams++; if( m_eAnaType == eCMD_AC ) { for( iCpxPts=0, i1=0; i1<(int)eCPXPT_NONE-1; i1++ ) if( m_bCpxPts[ i1 ] ) iCpxPts++; } else iCpxPts = 1; return( iProbes * iParams * iCpxPts ); } //************************************************************************************************** // Copy the contents of another CmdNgSpicePR object. // // Argument List : // roCmdPR - A reference to a CmdNgSpicePR object // // Return Values : // A reference to this object CmdNgSpicePR & CmdNgSpicePR::operator = ( const CmdNgSpicePR & roCmdPR ) { int i1; (CmdBase &) *this = (CmdBase &) roCmdPR; bSetAnaType( roCmdPR.m_eAnaType ); m_osaNodes = roCmdPR.m_osaNodes; m_osaCpnts = roCmdPR.m_osaCpnts; for( i1=0; i1<(int)ePARAM_NONE; i1++ ) m_bParams[ i1 ] = roCmdPR.m_bParams[ i1 ]; for( i1=0; i1<(int)eCPXPT_NONE; i1++ ) m_bCpxPts[ i1 ] = roCmdPR.m_bCpxPts[ i1 ]; bFormat( ); return( *this ); } //************************************************************************************************** // Copy the contents of a CmdGnuCapPR object. // // Argument List : // roCmdPR - A reference to a CmdGnuCapPR object // // Return Values : // A reference to this object CmdNgSpicePR & CmdNgSpicePR::operator = ( const CmdGnuCapPR & roCmdPR ) { int i1; (CmdBase &) *this = (CmdBase &) roCmdPR; bSetAnaType( roCmdPR.eGetAnaType( ) ); m_osaNodes = roCmdPR.m_osaNodes; m_osaCpnts = roCmdPR.m_osaCpnts; for( i1=0; i1<(int)ePARAM_NONE; i1++ ) m_bParams[ i1 ] = roCmdPR.m_bParams[ i1 ]; for( i1=0; i1<(int)eCPXPT_NONE; i1++ ) m_bCpxPts[ i1 ] = roCmdPR.m_bCpxPts[ i1 ]; bFormat( ); return( *this ); } //************************************************************************************************** // Print the object attributes. // // Argument List : // rosPrefix - A prefix to every line displayed (usually just spaces) void CmdNgSpicePR::Print( const wxString & rosPrefix ) { int i1; size_t sz1; CmdBase::Print( rosPrefix + wxT("CmdBase::") ); std::cout << rosPrefix.mb_str( ) << "m_eAnaType : "; switch( m_eAnaType ) { case eCMD_OP : std::cout << "eCMD_OP"; break; // Operating point analysis case eCMD_DC : std::cout << "eCMD_DC"; break; // DC analysis case eCMD_AC : std::cout << "eCMD_AC"; break; // AC analysis case eCMD_TR : std::cout << "eCMD_TR"; break; // Transient analysis case eCMD_FO : std::cout << "eCMD_FO"; break; // Fourier analysis case eCMD_DI : std::cout << "eCMD_DI"; break; // Distortion analysis case eCMD_NO : std::cout << "eCMD_NO"; break; // Noise analysis case eCMD_PZ : std::cout << "eCMD_PZ"; break; // Pole-zero analysis case eCMD_SE : std::cout << "eCMD_SE"; break; // Sensitivity analysis case eCMD_TF : std::cout << "eCMD_TF"; break; // Transfer function analysis case eCMD_NONE : std::cout << "eCMD_NONE"; break; // Analysis type not set default : std::cout << "Invalid"; break; } std::cout << '\n'; std::cout << rosPrefix.mb_str( ) << "m_osaCpnts[ n ] :"; for( sz1=0; sz1 2 ) { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); } // Process the command line arguments os1 = wxConvLibc.cMB2WC( argv[ 1 ] ); if( argc > 1 ) { if( os1 == wxT("-h") ) { Usage( argv[ 0 ] ); exit( EXIT_SUCCESS ); } else { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); } } // Display the utility banner cout << "\n Class CmdNgSpicePR Test Utility" << "\n Version 1.03 (2014-04-04)\n"; // Create a NG-SPICE PRINT command object CmdNgSpicePR oCmd_PR; // Use the following command example to check the formatter and the parser : osCmd = wxT(".PRINT AC VM(6,0) 0-VM(5) VM(1,7) VM(2) VP(6,0) 0-VP(5) VP(1,7) VP(2)"); // Set things up for a formatter test oCmd_PR.bSetAnaType( eCMD_AC ); oCmd_PR.m_osaCpnts.Add( wxT("6,0") ); oCmd_PR.m_osaCpnts.Add( wxT("0,5") ); oCmd_PR.m_osaCpnts.Add( wxT("1,7") ); oCmd_PR.m_osaNodes.Add( wxT("2") ); oCmd_PR.m_bParams[ ePARAM_VLT ] = true; oCmd_PR.m_bCpxPts[ eCPXPT_MAG ] = true; oCmd_PR.m_bCpxPts[ eCPXPT_PHASE ] = true; cout << "\nRun Formatter : " << ( oCmd_PR.bFormat( ) ? "OK" : "FAULT" ); cout << "\nTest Cmd Format : " << ( oCmd_PR == osCmd ? "OK" : "FAULT" ); cout << "\nExample Command : " << osCmd .mb_str( ); cout << "\noCmdPR Contents : " << oCmd_PR.mb_str( ) << '\n'; // Set things up for a parser test oCmd_PR.bSetString( osCmd ); cout << "\nRun Parser : " << ( oCmd_PR.bParse( ) ? "OK" : "FAULT" ); oCmd_PR.bFormat( ); cout << "\nTest Cmd Format : " << ( oCmd_PR == osCmd ? "OK" : "FAULT" ); cout << "\nExample Command : " << osCmd .mb_str( ); cout << "\noCmdPR Contents : " << oCmd_PR.mb_str( ) << '\n'; cout << '\n'; exit( EXIT_SUCCESS ); } //************************************************************************************************** void Usage( char * psAppName ) { cout << "\nUsage : " << psAppName << " [-OPTIONS]" << "\nOptions :" << "\n -h : Print usage (this message)\n"; } #endif // TEST_CMDNGSPICEPR //**************************************************************************************************