Rip out parsing of SPICE libraries for netlisting.

We only need to parse the libraries for the Sim Model Editor dialog
(so that we can determine the models to put in the popup).  Doing it
for netlisting just opens us up to incorrectly parsing the SPICE, and
returns no value.

This also means that a SIM_LIB_MGR manages a single library, and
never multiple libraries.

This also allows the tidying-up of some error reporting structures to
better inform the user what went wrong.

Fixes https://gitlab.com/kicad/code/kicad/issues/13431
This commit is contained in:
Jeff Young 2023-01-12 12:46:52 +00:00
parent 595bf70d5d
commit d839f11d49
13 changed files with 104 additions and 159 deletions

View File

@ -207,10 +207,9 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataToWindow()
for( const std::pair<std::string, std::string>& strs : kibismodel->GetIbisPins() ) for( const std::pair<std::string, std::string>& strs : kibismodel->GetIbisPins() )
{ {
if( strs.first if( strs.first == SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD ) )
== SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD ) )
{ {
auto kibisLibrary = static_cast<const SIM_LIBRARY_KIBIS*>( library() ); auto kibisLibrary = static_cast<const SIM_LIBRARY_KIBIS*>( m_libraryModelsMgr.GetLibrary() );
kibismodel->ChangePin( *kibisLibrary, strs.first ); kibismodel->ChangePin( *kibisLibrary, strs.first );
m_ibisPinCombobox->SetSelection( static_cast<int>( i ) ); m_ibisPinCombobox->SetSelection( static_cast<int>( i ) );
@ -310,7 +309,8 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
std::string path; std::string path;
if( ( library() && m_useLibraryModelRadioButton->GetValue() ) || isIbisLoaded() ) if( ( m_libraryModelsMgr.GetLibrary() && m_useLibraryModelRadioButton->GetValue() )
|| isIbisLoaded() )
{ {
path = m_libraryPathText->GetValue(); path = m_libraryPathText->GetValue();
wxFileName fn( path ); wxFileName fn( path );
@ -323,14 +323,14 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
if( isIbisLoaded() ) if( isIbisLoaded() )
{ {
SIM_MODEL_KIBIS* kibismodel = dynamic_cast<SIM_MODEL_KIBIS*>( SIM_MODEL_KIBIS* ibismodel = static_cast<SIM_MODEL_KIBIS*>(
&m_libraryModelsMgr.GetModels().at( m_modelNameChoice->GetSelection() ).get() ); &m_libraryModelsMgr.GetModels().at( m_modelNameChoice->GetSelection() ).get() );
if( kibismodel ) if( ibismodel )
{ {
SIM_MODEL::SetFieldValue( SIM_MODEL::SetFieldValue(
m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD, m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD,
kibismodel->GetIbisPins().at( m_ibisPinCombobox->GetSelection() ).first ); ibismodel->GetIbisPins().at( m_ibisPinCombobox->GetSelection() ).first );
SIM_MODEL::SetFieldValue( SIM_MODEL::SetFieldValue(
m_fields, SIM_LIBRARY_KIBIS::MODEL_FIELD, m_fields, SIM_LIBRARY_KIBIS::MODEL_FIELD,
@ -338,7 +338,7 @@ bool DIALOG_SIM_MODEL<T_symbol, T_field>::TransferDataFromWindow()
SIM_MODEL::SetFieldValue( SIM_MODEL::SetFieldValue(
m_fields, SIM_LIBRARY_KIBIS::DIFF_FIELD, m_fields, SIM_LIBRARY_KIBIS::DIFF_FIELD,
( kibismodel->CanDifferential() && m_differentialCheckbox->GetValue() ) ? "1" : "" ); ibismodel->CanDifferential() && m_differentialCheckbox->GetValue() ? "1" : "" );
} }
} }
@ -675,8 +675,6 @@ template <typename T_symbol, typename T_field>
void DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryPath, void DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryPath,
bool aForceReload ) bool aForceReload )
{ {
auto libraries = m_libraryModelsMgr.GetLibraries();
wxString msg; wxString msg;
WX_STRING_REPORTER reporter( &msg ); WX_STRING_REPORTER reporter( &msg );
@ -699,7 +697,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryP
std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD ); std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD );
for( auto& [baseModelName, baseModel] : library()->GetModels() ) for( auto& [baseModelName, baseModel] : m_libraryModelsMgr.GetLibrary()->GetModels() )
{ {
if( baseModelName == modelName ) if( baseModelName == modelName )
m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields ); m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields );
@ -715,7 +713,7 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryP
wxArrayString modelNames; wxArrayString modelNames;
for( auto& [name, model] : library()->GetModels() ) for( auto& [name, model] : m_libraryModelsMgr.GetLibrary()->GetModels() )
modelNames.Add( name ); modelNames.Add( name );
m_modelNameChoice->Clear(); m_modelNameChoice->Clear();
@ -924,16 +922,6 @@ SIM_MODEL& DIALOG_SIM_MODEL<T_symbol, T_field>::curModel() const
} }
template <typename T_symbol, typename T_field>
const SIM_LIBRARY* DIALOG_SIM_MODEL<T_symbol, T_field>::library() const
{
if( m_libraryModelsMgr.GetLibraries().size() == 1 )
return &m_libraryModelsMgr.GetLibraries().begin()->second.get();
return nullptr;
}
template <typename T_symbol, typename T_field> template <typename T_symbol, typename T_field>
wxString DIALOG_SIM_MODEL<T_symbol, T_field>::getSymbolPinString( int symbolPinIndex ) const wxString DIALOG_SIM_MODEL<T_symbol, T_field>::getSymbolPinString( int symbolPinIndex ) const
{ {
@ -1099,19 +1087,18 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::onIbisPinCombobox( wxCommandEvent& aEv
{ {
wxArrayString modelLabels; wxArrayString modelLabels;
SIM_MODEL_KIBIS& kibisModel = static_cast<SIM_MODEL_KIBIS&>( curModel() ); SIM_MODEL_KIBIS& ibisModel = static_cast<SIM_MODEL_KIBIS&>( curModel() );
std::vector<std::pair<std::string, std::string>> strs = kibisModel.GetIbisPins(); std::vector<std::pair<std::string, std::string>> strs = ibisModel.GetIbisPins();
std::string pinNumber = strs.at( m_ibisPinCombobox->GetSelection() ).first; std::string pinNumber = strs.at( m_ibisPinCombobox->GetSelection() ).first;
const SIM_LIBRARY_KIBIS* kibisLibrary = dynamic_cast<const SIM_LIBRARY_KIBIS*>( library() ); auto ibisLibrary = static_cast<const SIM_LIBRARY_KIBIS*>( m_libraryModelsMgr.GetLibrary() );
kibisModel.ChangePin( *kibisLibrary, pinNumber ); ibisModel.ChangePin( *ibisLibrary, pinNumber );
kibisModel.m_enableDiff = static_cast<const SIM_LIBRARY_KIBIS*>( library() ) ibisModel.m_enableDiff = ibisLibrary->isPinDiff( ibisModel.GetComponentName(), pinNumber );
->isPinDiff( kibisModel.GetComponentName(), pinNumber );
for( wxString modelName : kibisModel.GetIbisModels() ) for( wxString modelName : ibisModel.GetIbisModels() )
modelLabels.Add( modelName ); modelLabels.Add( modelName );
m_ibisModelCombobox->Set( modelLabels ); m_ibisModelCombobox->Set( modelLabels );

View File

@ -86,7 +86,6 @@ private:
int findSymbolPinRow( const wxString& aSymbolPinNumber ) const; int findSymbolPinRow( const wxString& aSymbolPinNumber ) const;
SIM_MODEL& curModel() const; SIM_MODEL& curModel() const;
const SIM_LIBRARY* library() const;
wxString getSymbolPinString( int aSymbolPinNumber ) const; wxString getSymbolPinString( int aSymbolPinNumber ) const;
wxString getModelPinString( int aModelPinIndex ) const; wxString getModelPinString( int aModelPinIndex ) const;
@ -114,7 +113,10 @@ private:
void adjustParamGridColumns( int aWidth, bool aForce ); void adjustParamGridColumns( int aWidth, bool aForce );
bool isIbisLoaded() { return dynamic_cast<const SIM_LIBRARY_KIBIS*>( library() ); } bool isIbisLoaded()
{
return dynamic_cast<const SIM_LIBRARY_KIBIS*>( m_libraryModelsMgr.GetLibrary() ) != nullptr;
}
private: private:
T_symbol& m_symbol; T_symbol& m_symbol;

View File

@ -1016,9 +1016,7 @@ int ERC_TESTER::TestSimModelIssues()
WX_STRING_REPORTER reporter( &msg ); WX_STRING_REPORTER reporter( &msg );
SCH_SHEET_LIST sheets = m_schematic->GetSheets(); SCH_SHEET_LIST sheets = m_schematic->GetSheets();
int err_count = 0; int err_count = 0;
SIM_LIB_MGR libMgr( &m_schematic->Prj() ); SIM_LIB_MGR libMgr( &m_schematic->Prj(), &reporter );
libMgr.SetReporter( &reporter );
for( SCH_SHEET_PATH& sheet : sheets ) for( SCH_SHEET_PATH& sheet : sheets )
{ {

View File

@ -26,7 +26,6 @@
#include <sim/kibis/kibis.h> #include <sim/kibis/kibis.h>
#include <netlist_exporter_spice.h> #include <netlist_exporter_spice.h>
#include <sim/ngspice_circuit_model.h> #include <sim/ngspice_circuit_model.h>
#include <sim/sim_library_spice.h>
#include <sim/sim_model_raw_spice.h> #include <sim/sim_model_raw_spice.h>
#include <sim/sim_model_ideal.h> #include <sim/sim_model_ideal.h>
#include <sim/spice_grammar.h> #include <sim/spice_grammar.h>
@ -56,7 +55,7 @@ namespace NETLIST_EXPORTER_SPICE_PARSER
{ {
using namespace SPICE_GRAMMAR; using namespace SPICE_GRAMMAR;
struct textGrammar : must<spiceSourceNothrow> {}; struct textGrammar : must<spiceSource> {};
template <typename Rule> struct textSelector : std::false_type {}; template <typename Rule> struct textSelector : std::false_type {};
template <> struct textSelector<modelUnit> : std::true_type {}; template <> struct textSelector<modelUnit> : std::true_type {};
@ -162,7 +161,7 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
std::set<std::string> refNames; // Set of reference names to check for duplication. std::set<std::string> refNames; // Set of reference names to check for duplication.
int ncCounter = 1; int ncCounter = 1;
ReadDirectives( aNetlistOptions, aReporter ); ReadDirectives( aNetlistOptions );
m_nets.clear(); m_nets.clear();
m_items.clear(); m_items.clear();
@ -260,8 +259,6 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
spiceItem.fields.back().SetText( pinMap ); spiceItem.fields.back().SetText( pinMap );
} }
// JEY TODO: move from try/catch to REPORTER interface...
// readModel() is the only one that throws, and it won't if m_libMgr has a REPORTER
try try
{ {
readRefName( sheet, *symbol, spiceItem, refNames ); readRefName( sheet, *symbol, spiceItem, refNames );
@ -277,7 +274,7 @@ bool NETLIST_EXPORTER_SPICE::ReadSchematicAndLibraries( unsigned aNetlistOptions
{ {
msg.Printf( _( "Error reading simulation model from symbol '%s':\n%s" ), msg.Printf( _( "Error reading simulation model from symbol '%s':\n%s" ),
symbol->GetRef( &sheet ), symbol->GetRef( &sheet ),
e.What() ); e.Problem() );
aReporter.Report( msg, RPT_SEVERITY_ERROR ); aReporter.Report( msg, RPT_SEVERITY_ERROR );
} }
} }
@ -364,7 +361,7 @@ const SPICE_ITEM* NETLIST_EXPORTER_SPICE::FindItem( const std::string& aRefName
} }
void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER& aReporter ) void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions )
{ {
wxString msg; wxString msg;
wxString text; wxString text;
@ -395,6 +392,10 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER&
} }
catch( const tao::pegtl::parse_error& ) catch( const tao::pegtl::parse_error& )
{ {
// If we couldn't parse it, but it -looks- like SPICE, then send it as raw SPICE
if( text.StartsWith( "." ) || text.StartsWith( "*" ) )
m_directives.emplace_back( text );
continue; continue;
} }
@ -404,8 +405,6 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER&
{ {
if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotTitle>() ) if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotTitle>() )
m_title = node->children.at( 0 )->string(); m_title = node->children.at( 0 )->string();
else if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotInclude>() )
m_libMgr.AddLibrary( node->children.at( 0 )->string() );
else else
m_directives.emplace_back( node->string() ); m_directives.emplace_back( node->string() );
} }
@ -415,8 +414,7 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER&
void NETLIST_EXPORTER_SPICE::readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol, void NETLIST_EXPORTER_SPICE::readRefName( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSymbol,
SPICE_ITEM& aItem, SPICE_ITEM& aItem, std::set<std::string>& aRefNames )
std::set<std::string>& aRefNames )
{ {
aItem.refName = aSymbol.GetRef( &aSheet ); aItem.refName = aSymbol.GetRef( &aSheet );
@ -524,12 +522,6 @@ void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
{ {
for( auto& [path, library] : m_libMgr.GetLibraries() )
{
if( dynamic_cast<const SIM_LIBRARY_SPICE*>( &library.get() ) )
writeInclude( aFormatter, aNetlistOptions, path );
}
for( const wxString& path : m_rawIncludes ) for( const wxString& path : m_rawIncludes )
writeInclude( aFormatter, aNetlistOptions, path ); writeInclude( aFormatter, aNetlistOptions, path );
} }
@ -560,7 +552,7 @@ void NETLIST_EXPORTER_SPICE::writeItems( OUTPUTFORMATTER& aFormatter )
void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter, void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter,
unsigned aNetlistOptions ) const unsigned aNetlistOptions ) const
{ {
if( aNetlistOptions & OPTION_SAVE_ALL_VOLTAGES ) if( aNetlistOptions & OPTION_SAVE_ALL_VOLTAGES )
aFormatter.Print( 0, ".save all\n" ); aFormatter.Print( 0, ".save all\n" );

View File

@ -3,7 +3,7 @@
* *
* Copyright (C) 1992-2013 jp.charras at wanadoo.fr * Copyright (C) 1992-2013 jp.charras at wanadoo.fr
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2021 KiCad Developers * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.TXT for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -126,7 +126,7 @@ public:
const std::vector<std::string>& GetDirectives() { return m_directives; } const std::vector<std::string>& GetDirectives() { return m_directives; }
protected: protected:
void ReadDirectives( unsigned aNetlistOptions, REPORTER& aReporter ); void ReadDirectives( unsigned aNetlistOptions );
virtual void WriteDirectives( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) const; virtual void WriteDirectives( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) const;
virtual std::string GenerateItemPinNetName( const std::string& aNetName, int& aNcCounter ) const; virtual std::string GenerateItemPinNetName( const std::string& aNetName, int& aNcCounter ) const;

View File

@ -350,7 +350,8 @@ void SCH_SEXPR_PLUGIN::Save( const wxString& aFileName, SCH_SHEET* aSheet, SCHEM
Format( aSheet ); Format( aSheet );
aSheet->GetScreen()->SetFileExists( true ); if( aSheet->GetScreen() )
aSheet->GetScreen()->SetFileExists( true );
} }

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016-2022 CERN * Copyright (C) 2016-2022 CERN
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.TXT for contributors. * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.TXT for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -67,10 +67,9 @@ SIM_PLOT_TYPE NGSPICE_CIRCUIT_MODEL::VectorToSignal( const std::string& aVector,
wxString NGSPICE_CIRCUIT_MODEL::GetSheetSimCommand() wxString NGSPICE_CIRCUIT_MODEL::GetSheetSimCommand()
{ {
NULL_REPORTER devnull;
wxString simCmd; wxString simCmd;
ReadDirectives( 0, devnull ); ReadDirectives( 0 );
for( const std::string& directive : GetDirectives() ) for( const std::string& directive : GetDirectives() )
{ {

View File

@ -36,20 +36,16 @@
#include <sim/sim_model.h> #include <sim/sim_model.h>
#include <sim/sim_model_ideal.h> #include <sim/sim_model_ideal.h>
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj ) : using namespace std::placeholders;
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj, REPORTER* aReporter ) :
m_project( aPrj ), m_project( aPrj ),
m_reporter( nullptr ) m_reporter( aReporter )
{ {
} }
void SIM_LIB_MGR::Clear()
{
m_libraries.clear();
m_models.clear();
}
wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject ) wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject )
{ {
wxString expandedPath = ExpandEnvVarSubstitutions( aLibraryPath, aProject ); wxString expandedPath = ExpandEnvVarSubstitutions( aLibraryPath, aProject );
@ -77,7 +73,8 @@ wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PR
} }
std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath, const std::string& aRelativeLib ) std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath,
const std::string& aRelativeLib )
{ {
wxFileName testPath( aLibPath ); wxFileName testPath( aLibPath );
wxString fullPath( aLibPath ); wxString fullPath( aLibPath );
@ -115,37 +112,19 @@ std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath
} }
void SIM_LIB_MGR::AddLibrary( const wxString& aLibraryPath )
{
try
{
wxString path = ResolveLibraryPath( aLibraryPath, m_project );
std::function<std::string(const std::string&, const std::string&)> f2 =
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 );
m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) );
}
catch( const IO_ERROR& e )
{
m_reporter->Report( e.What() );
}
}
void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath ) void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath )
{ {
m_models.clear();
m_library = nullptr;
try try
{ {
wxString path = ResolveLibraryPath( aLibraryPath, m_project ); wxString path = ResolveLibraryPath( aLibraryPath, m_project );
std::function<std::string(const std::string&, const std::string&)> f2 = std::function<std::string(const std::string&, const std::string&)> f2 =
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, m_reporter, &f2 ); m_library = SIM_LIBRARY::Create( path, m_reporter, &f2 );
Clear();
m_libraries[path] = std::move( library );
} }
catch( const IO_ERROR& e ) catch( const IO_ERROR& e )
{ {
@ -285,60 +264,60 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
{ {
wxString path; wxString path;
wxString msg; wxString msg;
SIM_LIBRARY* library = nullptr;
SIM_MODEL* baseModel = nullptr; SIM_MODEL* baseModel = nullptr;
std::string modelName; std::string modelName;
wxASSERT( !m_library );
try try
{ {
path = ResolveLibraryPath( aLibraryPath, m_project ); path = ResolveLibraryPath( aLibraryPath, m_project );
std::function<std::string( const std::string&, const std::string& )> f2 = std::function<std::string( const std::string&, const std::string& )> f2 =
std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, _1, _2 );
auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) ).first; m_library = SIM_LIBRARY::Create( path, m_reporter, &f2 );
library = &*it->second;
} }
catch( const IO_ERROR& e ) catch( const IO_ERROR& e )
{ {
msg.Printf( _( "Error loading simulation model library '%s': %s" ),
path,
e.What() );
if( m_reporter ) if( m_reporter )
{
msg.Printf( _( "Error loading simulation model library '%s': %s" ),
path,
e.What() );
m_reporter->Report( msg, RPT_SEVERITY_ERROR ); m_reporter->Report( msg, RPT_SEVERITY_ERROR );
else }
THROW_IO_ERROR( msg );
} }
if( aBaseModelName == "" ) if( aBaseModelName == "" )
{ {
msg.Printf( _( "Error loading simulation model: no '%s' field" ),
SIM_LIBRARY::NAME_FIELD );
if( m_reporter ) if( m_reporter )
{
msg.Printf( _( "Error loading simulation model: no '%s' field" ),
SIM_LIBRARY::NAME_FIELD );
m_reporter->Report( msg, RPT_SEVERITY_ERROR ); m_reporter->Report( msg, RPT_SEVERITY_ERROR );
else }
THROW_IO_ERROR( msg );
modelName = _( "unknown" ).ToStdString(); modelName = _( "unknown" ).ToStdString();
} }
else if( library ) else if( m_library )
{ {
baseModel = library->FindModel( aBaseModelName ); baseModel = m_library->FindModel( aBaseModelName );
modelName = aBaseModelName; modelName = aBaseModelName;
if( !baseModel ) if( !baseModel )
{ {
msg.Printf( _( "Error loading simulation model: could not find base model '%s' "
"in library '%s'" ),
aBaseModelName,
path );
if( m_reporter ) if( m_reporter )
{
msg.Printf( _( "Error loading simulation model: could not find base model '%s' "
"in library '%s'" ),
aBaseModelName,
path );
m_reporter->Report( msg, RPT_SEVERITY_ERROR ); m_reporter->Report( msg, RPT_SEVERITY_ERROR );
else }
THROW_IO_ERROR( msg );
} }
} }
@ -348,20 +327,15 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
} }
void SIM_LIB_MGR::SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel ) const SIM_LIBRARY* SIM_LIB_MGR::GetLibrary() const
{ {
m_models.at( aIndex ) = std::move( aModel ); return m_library.get();
} }
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> SIM_LIB_MGR::GetLibraries() const void SIM_LIB_MGR::SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel )
{ {
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> libraries; m_models.at( aIndex ) = std::move( aModel );
for( auto& [path, library] : m_libraries )
libraries.try_emplace( path, *library );
return libraries;
} }

View File

@ -40,15 +40,13 @@ class SCH_SYMBOL;
class SIM_LIB_MGR class SIM_LIB_MGR
{ {
public: public:
SIM_LIB_MGR( const PROJECT* aPrj ); SIM_LIB_MGR( const PROJECT* aPrj, REPORTER* aReporter = nullptr );
virtual ~SIM_LIB_MGR() = default; virtual ~SIM_LIB_MGR() = default;
void SetReporter( REPORTER* aReporter ) { m_reporter = aReporter; } void SetReporter( REPORTER* aReporter ) { m_reporter = aReporter; }
void Clear();
void AddLibrary( const wxString& aLibraryPath );
void SetLibrary( const wxString& aLibraryPath ); void SetLibrary( const wxString& aLibraryPath );
const SIM_LIBRARY* GetLibrary() const;
SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, const std::vector<LIB_PIN*>& aPins ); SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, const std::vector<LIB_PIN*>& aPins );
@ -73,18 +71,18 @@ public:
void SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel ); void SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel );
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const; std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject ); static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject );
std::string ResolveEmbeddedLibraryPath( const std::string& aLibPath, const std::string& aRelativeLib ); std::string ResolveEmbeddedLibraryPath( const std::string& aLibPath,
const std::string& aRelativeLib );
private: private:
const PROJECT* m_project; const PROJECT* m_project;
REPORTER* m_reporter; REPORTER* m_reporter;
std::map<wxString, std::unique_ptr<SIM_LIBRARY>> m_libraries; std::unique_ptr<SIM_LIBRARY> m_library;
std::vector<std::unique_ptr<SIM_MODEL>> m_models; std::vector<std::unique_ptr<SIM_MODEL>> m_models;
}; };

View File

@ -3,7 +3,7 @@
* *
* Copyright (C) 2022 Mikolaj Wielgus * Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 CERN * Copyright (C) 2022 CERN
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -591,9 +591,9 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
{ {
// 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, full stop.
if( aReporter ) if( aReporter )
aReporter->Report( err.What(), RPT_SEVERITY_ERROR ); aReporter->Report( err.Problem(), RPT_SEVERITY_ERROR );
else else
DisplayErrorMessage( nullptr, err.What() ); THROW_IO_ERROR( err.Problem() );
} }
} }
@ -1575,11 +1575,9 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject )
{ {
wxString msg; wxString msg;
WX_STRING_REPORTER reporter( &msg ); WX_STRING_REPORTER reporter( &msg );
SIM_LIB_MGR libMgr( aProject ); SIM_LIB_MGR libMgr( aProject, &reporter );
std::vector<T_field> emptyFields; std::vector<T_field> emptyFields;
libMgr.SetReporter( &reporter );
SIM_LIBRARY::MODEL model = libMgr.CreateModel( spiceLib, spiceModel.ToStdString(), SIM_LIBRARY::MODEL model = libMgr.CreateModel( spiceLib, spiceModel.ToStdString(),
emptyFields, sourcePins ); emptyFields, sourcePins );

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2022 Mikolaj Wielgus * Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -159,7 +159,7 @@ void SIM_MODEL_SERIALIZER::ParseValue( const std::string& aValue )
{ {
try try
{ {
tao::pegtl::string_input<> in( aValue, "'Value' symbol field" ); tao::pegtl::string_input<> in( aValue, "Value field" );
auto root = auto root =
tao::pegtl::parse_tree::parse<SIM_MODEL_SERIALIZER_PARSER::fieldInferValueGrammar, tao::pegtl::parse_tree::parse<SIM_MODEL_SERIALIZER_PARSER::fieldInferValueGrammar,
SIM_MODEL_SERIALIZER_PARSER::fieldInferValueSelector, SIM_MODEL_SERIALIZER_PARSER::fieldInferValueSelector,
@ -179,9 +179,7 @@ void SIM_MODEL_SERIALIZER::ParseValue( const std::string& aValue )
} }
catch( const tao::pegtl::parse_error& e ) catch( const tao::pegtl::parse_error& e )
{ {
wxString msg; THROW_IO_ERROR( e.what() );
msg.Printf( wxT( "ParseValue: parse <%s>, error <%s>" ), aValue.c_str(), e.what() );
THROW_IO_ERROR( msg );
} }
m_model.SetIsStoredInValue( true ); m_model.SetIsStoredInValue( true );
@ -190,7 +188,7 @@ void SIM_MODEL_SERIALIZER::ParseValue( const std::string& aValue )
bool SIM_MODEL_SERIALIZER::ParseParams( const std::string& aParams ) bool SIM_MODEL_SERIALIZER::ParseParams( const std::string& aParams )
{ {
tao::pegtl::string_input<> in( aParams, "'Sim.Params' symbol field" ); tao::pegtl::string_input<> in( aParams, "Sim.Params field" );
std::unique_ptr<tao::pegtl::parse_tree::node> root; std::unique_ptr<tao::pegtl::parse_tree::node> root;
try try
@ -205,9 +203,7 @@ bool SIM_MODEL_SERIALIZER::ParseParams( const std::string& aParams )
} }
catch( const tao::pegtl::parse_error& e ) catch( const tao::pegtl::parse_error& e )
{ {
wxString msg; THROW_IO_ERROR( e.what() );
msg.Printf( wxT( "ParseParams: parse <%s>, error <%s>" ), aParams.c_str(), e.what() );
THROW_IO_ERROR( msg );
} }
std::string paramName; std::string paramName;
@ -254,7 +250,7 @@ void SIM_MODEL_SERIALIZER::ParsePins( const std::string& aPins )
if( aPins == "" ) if( aPins == "" )
return; return;
tao::pegtl::string_input<> in( aPins, "'Sim.Pins' symbol field" ); tao::pegtl::string_input<> in( aPins, "Sim.Pins field" );
std::unique_ptr<tao::pegtl::parse_tree::node> root; std::unique_ptr<tao::pegtl::parse_tree::node> root;
try try
@ -275,9 +271,7 @@ void SIM_MODEL_SERIALIZER::ParsePins( const std::string& aPins )
} }
catch( const tao::pegtl::parse_error& e ) catch( const tao::pegtl::parse_error& e )
{ {
wxString msg; THROW_IO_ERROR( e.what() );
msg.Printf( wxT( "ParsePins: parse <%s>, error <%s>" ), aPins.c_str(), e.what() );
THROW_IO_ERROR( msg );
} }
} }

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2022 Mikolaj Wielgus * Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -260,7 +260,6 @@ namespace SPICE_GRAMMAR
struct spiceSource : star<spiceUnit> {}; struct spiceSource : star<spiceUnit> {};
struct spiceSourceNothrow : star<try_catch<spiceUnit>> {};
struct spiceSourceGrammar : must<spiceSource> {}; struct spiceSourceGrammar : must<spiceSource> {};
@ -289,8 +288,6 @@ namespace SPICE_GRAMMAR
"expected Spice directive, item, subcircuit definitions, or empty or commented-out line"; "expected Spice directive, item, subcircuit definitions, or empty or commented-out line";
template <> inline constexpr auto errorMessage<spiceSource> = template <> inline constexpr auto errorMessage<spiceSource> =
"expected zero or more Spice directives, items, subcircuit definitions, or empty or commented-out lines"; "expected zero or more Spice directives, items, subcircuit definitions, or empty or commented-out lines";
template <> inline constexpr auto errorMessage<spiceSourceNothrow> =
"expected zero or more Spice directives, items, subcircuit definitions, or empty or commented-out lines";
// We create a custom PEGTL control to modify the parser error messages. // We create a custom PEGTL control to modify the parser error messages.
struct error struct error

View File

@ -489,10 +489,15 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
LIB_PIN* pin = static_cast<SCH_PIN*>( item )->GetLibPin(); LIB_PIN* pin = static_cast<SCH_PIN*>( item )->GetLibPin();
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item->GetParent() ); SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item->GetParent() );
// JEY TODO: move to reporter interface instead of try/catch.... wxString msg;
SIM_LIB_MGR mgr( &m_frame->Prj() ); WX_STRING_REPORTER reporter( &msg );
SIM_LIB_MGR mgr( &m_frame->Prj(), &reporter );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol ).model; SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol ).model;
if( reporter.HasMessage() )
THROW_IO_ERROR( msg );
SPICE_ITEM spiceItem; SPICE_ITEM spiceItem;
spiceItem.refName = std::string( symbol->GetRef( &sheet ).ToUTF8() ); spiceItem.refName = std::string( symbol->GetRef( &sheet ).ToUTF8() );
std::vector<std::string> currentNames = std::vector<std::string> currentNames =