From 70e86434efc4778541a6c1fb1fdd110d6f85fef0 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 17 Mar 2023 14:12:58 +0000 Subject: [PATCH] Manual cherry-pick of much of 6d296038f37d05d149324af7950d2b8e882e1655 --- eeschema/dialogs/dialog_sim_model.cpp | 56 +++++++------- .../netlist_exporter_spice.cpp | 73 +++++-------------- eeschema/sim/sim_library_kibis.cpp | 2 +- eeschema/sim/sim_model.cpp | 62 +++++++++------- eeschema/sim/sim_model.h | 2 +- eeschema/sim/sim_model_ngspice.cpp | 1 - eeschema/sim/spice_generator.cpp | 4 + 7 files changed, 89 insertions(+), 111 deletions(-) diff --git a/eeschema/dialogs/dialog_sim_model.cpp b/eeschema/dialogs/dialog_sim_model.cpp index ddc44b58ca..a79dfd34f6 100644 --- a/eeschema/dialogs/dialog_sim_model.cpp +++ b/eeschema/dialogs/dialog_sim_model.cpp @@ -136,6 +136,9 @@ bool DIALOG_SIM_MODEL::TransferDataToWindow() wxString pinMap; bool storeInValue = false; + wxString msg; + WX_STRING_REPORTER reporter( &msg ); + // Infer RLC and VI models if they aren't specified if( SIM_MODEL::InferSimModel( m_symbol, &m_fields, false, SIM_VALUE_GRAMMAR::NOTATION::SI, &deviceType, &modelType, &modelParams, &pinMap ) ) @@ -180,7 +183,7 @@ bool DIALOG_SIM_MODEL::TransferDataToWindow() if( !loadLibrary( libraryFilename ) ) { m_libraryPathText->ChangeValue( libraryFilename ); - m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields ); + m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, &reporter ); m_libraryModelsMgr.CreateModel( nullptr, sourcePins, m_fields ); m_modelNameChoice->Append( _( "" ) ); @@ -256,25 +259,32 @@ bool DIALOG_SIM_MODEL::TransferDataToWindow() { // The model is sourced from the instance. m_useInstanceModelRadioButton->SetValue( true ); - m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields ); + + msg.clear(); + m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, &reporter ); + + if( reporter.HasMessage() ) + DisplayErrorMessage( this, msg ); } + m_builtinModelsMgr.SetReporter( &reporter ); + for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() ) { - wxString msg; - WX_STRING_REPORTER reporter( &msg ); - - m_builtinModelsMgr.SetReporter( &reporter ); - if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType ) - m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false ); - else - m_builtinModelsMgr.CreateModel( type, sourcePins ); - - if( reporter.HasMessage() ) { - DisplayErrorMessage( this, _( "Failed to read simulation model from fields." ) - + wxT( "\n\n" ) + msg ); + msg.clear(); + m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false ); + + if( reporter.HasMessage() ) + { + DisplayErrorMessage( this, _( "Failed to read simulation model from fields." ) + + wxT( "\n\n" ) + msg ); + } + } + else + { + m_builtinModelsMgr.CreateModel( type, sourcePins ); } SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType; @@ -698,7 +708,7 @@ bool DIALOG_SIM_MODEL::loadLibrary( const wxString& aLibraryP std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD ); - for( auto& [baseModelName, baseModel] : library()->GetModels() ) + for( const auto& [baseModelName, baseModel] : library()->GetModels() ) { if( baseModelName == modelName ) m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields ); @@ -714,7 +724,7 @@ bool DIALOG_SIM_MODEL::loadLibrary( const wxString& aLibraryP wxArrayString modelNames; - for( auto& [name, model] : library()->GetModels() ) + for( const auto& [name, model] : library()->GetModels() ) modelNames.Add( name ); m_modelNameChoice->Clear(); @@ -1407,22 +1417,16 @@ void DIALOG_SIM_MODEL::adjustParamGridColumns( int aWidth, bo for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ ) { - if( ii == 0 ) + if( ii == PARAM_COLUMN::DESCRIPTION ) colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin + indent ); - else if( ii == 1 ) - colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin ); + else if( ii == PARAM_COLUMN::VALUE ) + colWidths.push_back( std::max( 72, grid->GetState()->GetColumnWidth( ii ) ) + margin ); else - colWidths.push_back( 50 ); + colWidths.push_back( 60 + margin ); aWidth -= colWidths[ ii ]; } - // Account for scroll bars - aWidth -= ( grid->GetSize().x - grid->GetClientSize().x ); - - if( aWidth > 0 ) - colWidths[ PARAM_COLUMN::VALUE ] += aWidth; - for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ ) grid->SetColumnProportion( ii, colWidths[ ii ] ); diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index ec0aa43389..df2cc764f4 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -83,20 +83,13 @@ namespace NETLIST_EXPORTER_SPICE_PARSER std::string NAME_GENERATOR::Generate( const std::string& aProposedName ) { - if( !m_names.count( aProposedName ) ) - return aProposedName; + std::string name = aProposedName; + int ii = 1; - for( uint64_t i = 1; i < UINT64_MAX; ++i ) - { - std::string name = fmt::format( "{}#{}", aProposedName, i ); + while( m_names.count( name ) ) + name = fmt::format( "{}#{}", aProposedName, ii++ ); - if( !m_names.count( name ) ) - return name; - } - - // Should never happen. - THROW_IO_ERROR( wxString::Format( _( "Failed to generate a name for '%s': exceeded UINT64_MAX" ), - aProposedName ) ); + return name; } @@ -126,8 +119,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign // Cleanup list to avoid duplicate if the netlist exporter is run more than once. m_rawIncludes.clear(); - if( !ReadSchematicAndLibraries( aNetlistOptions, aReporter ) ) - return false; + bool result = ReadSchematicAndLibraries( aNetlistOptions, aReporter ); WriteHead( aFormatter, aNetlistOptions ); @@ -142,7 +134,7 @@ bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsign WriteTail( aFormatter, aNetlistOptions ); - return true; + return result; } @@ -165,6 +157,8 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions std::set refNames; // Set of reference names to check for duplication. int ncCounter = 1; + m_libMgr.SetReporter( &aReporter ); + ReadDirectives( aNetlistOptions ); m_nets.clear(); @@ -240,50 +234,19 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions wxString modelParams; wxString pinMap; - // JEY TODO: readModel() below will also do the inference, so I don't think this - // accomplishes anything.... - // Infer RLC and VI models if they aren't specified - if( SIM_MODEL::InferSimModel( *symbol, &spiceItem.fields, true, - SIM_VALUE_GRAMMAR::NOTATION::SPICE, &deviceType, - &modelType, &modelParams, &pinMap ) ) - { - spiceItem.fields.emplace_back( symbol, -1, SIM_DEVICE_TYPE_FIELD ); - spiceItem.fields.back().SetText( deviceType ); + readRefName( sheet, *symbol, spiceItem, refNames ); + readModel( sheet, *symbol, spiceItem ); + readPinNumbers( *symbol, spiceItem, pins ); + readPinNetNames( *symbol, spiceItem, pins, ncCounter ); - if( !modelType.IsEmpty() ) - { - spiceItem.fields.emplace_back( symbol, -1, SIM_TYPE_FIELD ); - spiceItem.fields.back().SetText( modelType ); - } + // TODO: transmission line handling? - spiceItem.fields.emplace_back( symbol, -1, SIM_PARAMS_FIELD ); - spiceItem.fields.back().SetText( modelParams ); - - spiceItem.fields.emplace_back( symbol, -1, SIM_PINS_FIELD ); - spiceItem.fields.back().SetText( pinMap ); - } - - try - { - readRefName( sheet, *symbol, spiceItem, refNames ); - readModel( sheet, *symbol, spiceItem ); - readPinNumbers( *symbol, spiceItem, pins ); - readPinNetNames( *symbol, spiceItem, pins, ncCounter ); - - // TODO: transmission line handling? - - m_items.push_back( std::move( spiceItem ) ); - } - catch( const IO_ERROR& e ) - { - msg.Printf( _( "Error reading simulation model from symbol '%s':\n%s" ), - symbol->GetRef( &sheet ), - e.Problem() ); - aReporter.Report( msg, RPT_SEVERITY_ERROR ); - } + m_items.push_back( std::move( spiceItem ) ); } } + m_libMgr.SetReporter( nullptr ); + return !aReporter.HasMessage(); } @@ -595,7 +558,7 @@ void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) { - for( auto& [path, library] : m_libMgr.GetLibraries() ) + for( const auto& [path, library] : m_libMgr.GetLibraries() ) { if( dynamic_cast( &library.get() ) ) writeInclude( aFormatter, aNetlistOptions, path ); diff --git a/eeschema/sim/sim_library_kibis.cpp b/eeschema/sim/sim_library_kibis.cpp index e8b0dc82b5..3c9b4b7155 100644 --- a/eeschema/sim/sim_library_kibis.cpp +++ b/eeschema/sim/sim_library_kibis.cpp @@ -49,7 +49,7 @@ void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, REPORTER* aRepor for( KIBIS_COMPONENT& kcomp : m_kibis.m_components ) { - m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins, nullptr ) ); + m_models.push_back( SIM_MODEL::Create( SIM_MODEL::TYPE::KIBIS_DEVICE, pins, aReporter ) ); m_modelNames.emplace_back( kcomp.m_name ); SIM_MODEL_KIBIS* libcomp = dynamic_cast( m_models.back().get() ); diff --git a/eeschema/sim/sim_model.cpp b/eeschema/sim/sim_model.cpp index 00319f4ac6..c5aec1d82c 100644 --- a/eeschema/sim/sim_model.cpp +++ b/eeschema/sim/sim_model.cpp @@ -361,11 +361,13 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType ) } -template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields ); -template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields ); +template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields, + REPORTER* aReporter ); +template TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields, + REPORTER* aReporter ); template -TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields ) +TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields, REPORTER* aReporter ) { std::string deviceTypeFieldValue = GetFieldValue( &aFields, SIM_DEVICE_TYPE_FIELD ); std::string typeFieldValue = GetFieldValue( &aFields, SIM_TYPE_FIELD ); @@ -392,6 +394,17 @@ TYPE SIM_MODEL::ReadTypeFromFields( const std::vector& aFields ) if( typeFromLegacyFields != TYPE::NONE ) return typeFromLegacyFields; + if( aReporter ) + { + if( aFields.size() > REFERENCE_FIELD ) + { + aReporter->Report( wxString::Format( _( "Error reading simulation model from symbol '%s':\n%s" ), + aFields[REFERENCE_FIELD].GetText(), + _( "Failed to read simulation model from fields." ) ), + RPT_SEVERITY_ERROR ); + } + } + return TYPE::NONE; } @@ -506,7 +519,7 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL* aBaseModel, const std::vector& aFields, REPORTER* aReporter ) { - TYPE type = ReadTypeFromFields( aFields ); + TYPE type = ReadTypeFromFields( aFields, aReporter ); // If the model has a specified type, it takes priority over the type of its base class. if( type == TYPE::NONE && aBaseModel ) @@ -533,9 +546,13 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL* aBaseModel, catch( IO_ERROR& err ) { if( aReporter ) - aReporter->Report( err.What(), RPT_SEVERITY_ERROR ); - else - DisplayErrorMessage( nullptr, err.What() ); + { + aReporter->Report( wxString::Format( _( "Error reading simulation model from " + "symbol '%s':\n%s" ), + aFields[REFERENCE_FIELD].GetText(), + err.Problem() ), + RPT_SEVERITY_ERROR ); + } } return model; @@ -557,7 +574,7 @@ std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, const std::vector& aPins, bool aResolved, REPORTER* aReporter ) { - TYPE type = ReadTypeFromFields( aFields ); + TYPE type = ReadTypeFromFields( aFields, aReporter ); std::unique_ptr model = SIM_MODEL::Create( type ); try @@ -589,11 +606,15 @@ std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, } catch( const IO_ERROR& err ) { - // We own the pin syntax, so if we can't parse it then there's an error, full stop. + // We own the pin syntax, so if we can't parse it then there's an error. if( aReporter ) - aReporter->Report( err.Problem(), RPT_SEVERITY_ERROR ); - else - THROW_IO_ERROR( err.Problem() ); + { + aReporter->Report( wxString::Format( _( "Error reading simulation model from " + "symbol '%s':\n%s" ), + aFields[REFERENCE_FIELD].GetText(), + err.Problem() ), + RPT_SEVERITY_ERROR ); + } } } @@ -726,21 +747,8 @@ void SIM_MODEL::AddParam( const PARAM::INFO& aInfo ) void SIM_MODEL::SetBaseModel( const SIM_MODEL& aBaseModel ) { - auto describe = - []( const SIM_MODEL* aModel ) - { - return fmt::format( "{} ({})", - aModel->GetDeviceInfo().fieldValue, - aModel->GetTypeInfo().description ); - }; - - if( GetType() != aBaseModel.GetType() ) - { - THROW_IO_ERROR( wxString::Format( _( "Simulation model type must be the same as of its " - "base class: '%s', but is '%s'" ), - describe( &aBaseModel ), - describe( this ) ) ); - } + wxASSERT_MSG( GetType() == aBaseModel.GetType(), + wxS( "Simulation model type must be the same as its base class!" ) ); m_baseModel = &aBaseModel; } diff --git a/eeschema/sim/sim_model.h b/eeschema/sim/sim_model.h index 899aebff9e..8b299981e8 100644 --- a/eeschema/sim/sim_model.h +++ b/eeschema/sim/sim_model.h @@ -384,7 +384,7 @@ public: template - static TYPE ReadTypeFromFields( const std::vector& aFields ); + static TYPE ReadTypeFromFields( const std::vector& aFields, REPORTER* aReporter ); template static TYPE InferTypeFromLegacyFields( const std::vector& aFields ); diff --git a/eeschema/sim/sim_model_ngspice.cpp b/eeschema/sim/sim_model_ngspice.cpp index 663bac8a7f..3575275fba 100644 --- a/eeschema/sim/sim_model_ngspice.cpp +++ b/eeschema/sim/sim_model_ngspice.cpp @@ -55,7 +55,6 @@ std::vector SPICE_GENERATOR_NGSPICE::CurrentNames( const SPICE_ITEM return SPICE_GENERATOR::CurrentNames( aItem ); default: - wxFAIL_MSG( "Unhandled model device type in SIM_MODEL_NGSPICE" ); return {}; } } diff --git a/eeschema/sim/spice_generator.cpp b/eeschema/sim/spice_generator.cpp index 54d36be732..c719e55d1b 100644 --- a/eeschema/sim/spice_generator.cpp +++ b/eeschema/sim/spice_generator.cpp @@ -95,6 +95,10 @@ std::string SPICE_GENERATOR::ModelLine( const SPICE_ITEM& aItem ) const value ) ); } + // Don't send SPICE empty models. + if( result.length() == indentLength + 1 /* line ending */ ) + result.clear(); + return result; }