diff --git a/eeschema/dialogs/dialog_sim_model.cpp b/eeschema/dialogs/dialog_sim_model.cpp index a7edc2f80a..e6d41e420e 100644 --- a/eeschema/dialogs/dialog_sim_model.cpp +++ b/eeschema/dialogs/dialog_sim_model.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2022 Mikolaj Wielgus * 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 * modify it under the terms of the GNU General Public License @@ -185,7 +185,9 @@ bool DIALOG_SIM_MODEL::TransferDataToWindow() { DisplayErrorMessage( this, wxString::Format( _( "No model named '%s' in library." ), modelName ) ); - m_modelNameChoice->SetSelection( -1 ); + + // Default to first item in library + m_modelNameChoice->SetSelection( 0 ); } else { @@ -257,18 +259,20 @@ bool DIALOG_SIM_MODEL::TransferDataToWindow() for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() ) { - try - { - if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType ) - m_builtinModelsMgr.CreateModel( m_fields, sourcePins ); - else - m_builtinModelsMgr.CreateModel( type, sourcePins ); - } - catch( const IO_ERROR& e ) + 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" ) - + e.What() ); + + wxT( "\n\n" ) + msg ); } SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType; @@ -670,25 +674,15 @@ void DIALOG_SIM_MODEL::loadLibrary( const wxString& aLibraryP { auto libraries = m_libraryModelsMgr.GetLibraries(); - DIALOG_IBIS_PARSER_REPORTER dlg( this ); - dlg.m_messagePanel->Clear(); + wxString msg; + WX_STRING_REPORTER reporter( &msg ); - try - { - m_libraryModelsMgr.SetLibrary( aLibraryPath, &dlg.m_messagePanel->Reporter() ); - } - catch( const IO_ERROR& e ) - { - if( dlg.m_messagePanel->Reporter().HasMessage() ) - { - dlg.m_messagePanel->Flush(); - dlg.ShowQuasiModal(); - } - else - { - DisplayErrorMessage( this, e.What() ); - } + m_libraryModelsMgr.SetReporter( &reporter ); + m_libraryModelsMgr.SetLibrary( aLibraryPath ); + if( reporter.HasMessage() ) + { + DisplayErrorMessage( this, msg ); return; } @@ -700,30 +694,26 @@ void DIALOG_SIM_MODEL::loadLibrary( const wxString& aLibraryP return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; } ); - try - { - 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() ) - { - if( baseModelName == modelName ) - m_libraryModelsMgr.CreateModel( baseModel, sourcePins, m_fields ); - else - m_libraryModelsMgr.CreateModel( baseModel, sourcePins ); - } - } - catch( const IO_ERROR& e ) + for( auto& [baseModelName, baseModel] : library()->GetModels() ) { - DisplayErrorMessage( this, e.What() ); + if( baseModelName == modelName ) + m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields ); + else + m_libraryModelsMgr.CreateModel( &baseModel, sourcePins ); } + if( reporter.HasMessage() ) + DisplayErrorMessage( this, msg ); + m_useLibraryModelRadioButton->SetValue( true ); m_libraryPathText->ChangeValue( aLibraryPath ); wxArrayString modelNames; - for( auto& [modelName, model] : library()->GetModels() ) - modelNames.Add( modelName ); + for( auto& [name, model] : library()->GetModels() ) + modelNames.Add( name ); m_modelNameChoice->Clear(); m_modelNameChoice->Append( modelNames ); diff --git a/eeschema/erc.cpp b/eeschema/erc.cpp index d31a26abe2..a45d20379a 100644 --- a/eeschema/erc.cpp +++ b/eeschema/erc.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2011 Wayne Stambaugh - * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1016,7 +1016,9 @@ int ERC_TESTER::TestSimModelIssues() WX_STRING_REPORTER reporter( &msg ); SCH_SHEET_LIST sheets = m_schematic->GetSheets(); int err_count = 0; - SIM_LIB_MGR libMgr( &m_schematic->Prj(), &reporter ); + SIM_LIB_MGR libMgr( &m_schematic->Prj() ); + + libMgr.SetReporter( &reporter ); for( SCH_SHEET_PATH& sheet : sheets ) { diff --git a/eeschema/netlist_exporters/netlist_exporter_spice.cpp b/eeschema/netlist_exporters/netlist_exporter_spice.cpp index 57122d0228..16e321b1a9 100644 --- a/eeschema/netlist_exporters/netlist_exporter_spice.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_spice.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 1992-2013 jp.charras at wanadoo.fr * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.TXT for contributors. + * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -107,6 +107,7 @@ NETLIST_EXPORTER_SPICE::NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic ) : bool NETLIST_EXPORTER_SPICE::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions, REPORTER& aReporter ) { + m_libMgr.SetReporter( &aReporter ); FILE_OUTPUTFORMATTER formatter( aOutFileName, wxT( "wt" ), '\'' ); return DoWriteNetlist( formatter, aNetlistOptions, aReporter ); } @@ -394,29 +395,11 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER& for( const auto& node : root->children ) { if( node->is_type() ) - { m_title = node->children.at( 0 )->string(); - } else if( node->is_type() ) - { - std::string path = node->children.at( 0 )->string(); - - try - { - m_libMgr.AddLibrary( path, &aReporter ); - } - catch( const IO_ERROR& e ) - { - msg.Printf( _( "Error reading simulation model library '%s':\n%s" ), - path, - e.What() ); - aReporter.Report( msg, RPT_SEVERITY_ERROR ); - } - } + m_libMgr.AddLibrary( node->children.at( 0 )->string() ); else - { m_directives.emplace_back( node->string() ); - } } } } diff --git a/eeschema/sim/sim_lib_mgr.cpp b/eeschema/sim/sim_lib_mgr.cpp index d0f1a7c543..17249ff871 100644 --- a/eeschema/sim/sim_lib_mgr.cpp +++ b/eeschema/sim/sim_lib_mgr.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -36,9 +36,9 @@ #include #include -SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj, REPORTER* aReporter ) : +SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj ) : m_project( aPrj ), - m_reporter( aReporter ) + m_reporter( nullptr ) { } @@ -115,33 +115,42 @@ std::string SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const std::string& aLibPath } -SIM_LIBRARY& SIM_LIB_MGR::AddLibrary( const wxString& aLibraryPath, REPORTER* aReporter ) +void SIM_LIB_MGR::AddLibrary( const wxString& aLibraryPath ) { - // May throw an exception. - wxString path = ResolveLibraryPath( aLibraryPath, m_project ); + try + { + wxString path = ResolveLibraryPath( aLibraryPath, m_project ); - std::function f2 = - std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); + std::function f2 = + std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); - // May throw an exception. - auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, aReporter, &f2 ) ).first; - return *it->second; + m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) ); + } + catch( const IO_ERROR& e ) + { + m_reporter->Report( e.What() ); + } } -SIM_LIBRARY& SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath, REPORTER* aReporter ) +void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath ) { - // May throw an exception. - wxString path = ResolveLibraryPath( aLibraryPath, m_project ); + try + { + wxString path = ResolveLibraryPath( aLibraryPath, m_project ); - std::function f2 = - std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); + std::function f2 = + std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); - std::unique_ptr library = SIM_LIBRARY::Create( path, aReporter, &f2 ); - - Clear(); - m_libraries[path] = std::move( library ); - return *m_libraries.at( path ); + std::unique_ptr library = SIM_LIBRARY::Create( path, m_reporter, &f2 ); + + Clear(); + m_libraries[path] = std::move( library ); + } + catch( const IO_ERROR& e ) + { + m_reporter->Report( e.What() ); + } } @@ -152,7 +161,7 @@ SIM_MODEL& SIM_LIB_MGR::CreateModel( SIM_MODEL::TYPE aType, const std::vector
  • & aPins ) { m_models.push_back( SIM_MODEL::Create( aBaseModel, aPins, m_reporter ) ); @@ -161,7 +170,7 @@ SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, template -SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, +SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields ) { @@ -169,10 +178,10 @@ SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, return *m_models.back(); } -template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, +template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields ); -template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel, +template SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields ); @@ -234,7 +243,7 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0; } ); - SIM_LIBRARY::MODEL model = CreateModel( fields, sourcePins ); + SIM_LIBRARY::MODEL model = CreateModel( fields, sourcePins, true ); model.model.SetIsStoredInValue( storeInValue ); @@ -244,7 +253,7 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const SCH_SHEET_PATH* aSheetPath, S template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, - const std::vector& aPins ) + const std::vector& aPins, bool aResolved ) { std::string libraryPath = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::LIBRARY_FIELD ); std::string baseModelName = SIM_MODEL::GetFieldValue( &aFields, SIM_LIBRARY::NAME_FIELD ); @@ -255,15 +264,17 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, } else { - m_models.push_back( SIM_MODEL::Create( aFields, aPins, m_reporter ) ); + m_models.push_back( SIM_MODEL::Create( aFields, aPins, aResolved, m_reporter ) ); return { baseModelName, *m_models.back() }; } } template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, - const std::vector& aPins ); + const std::vector& aPins, + bool aResolved ); template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector& aFields, - const std::vector& aPins ); + const std::vector& aPins, + bool aResolved ); template @@ -272,16 +283,20 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath, const std::vector& aFields, const std::vector& aPins ) { - wxString path = ResolveLibraryPath( aLibraryPath, m_project ); - SIM_LIBRARY* library = nullptr; + wxString path; wxString msg; - - std::function f2 = - std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); + SIM_LIBRARY* library = nullptr; + SIM_MODEL* baseModel = nullptr; + std::string modelName; try { - auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, nullptr, &f2 ) ).first; + path = ResolveLibraryPath( aLibraryPath, m_project ); + + std::function f2 = + std::bind( &SIM_LIB_MGR::ResolveEmbeddedLibraryPath, this, std::placeholders::_1, std::placeholders::_2 ); + + auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( path, m_reporter, &f2 ) ).first; library = &*it->second; } catch( const IO_ERROR& e ) @@ -305,25 +320,31 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath, m_reporter->Report( msg, RPT_SEVERITY_ERROR ); else THROW_IO_ERROR( msg ); + + modelName = _( "unknown" ).ToStdString(); } - - SIM_MODEL* baseModel = library->FindModel( aBaseModelName ); - - if( !baseModel ) + else if( library ) { - msg.Printf( _( "Error loading simulation model: could not find base model '%s' in library '%s'" ), - aBaseModelName, - path ); + baseModel = library->FindModel( aBaseModelName ); + modelName = aBaseModelName; - if( m_reporter ) - m_reporter->Report( msg, RPT_SEVERITY_ERROR ); - else - THROW_IO_ERROR( msg ); + if( !baseModel ) + { + msg.Printf( _( "Error loading simulation model: could not find base model '%s' " + "in library '%s'" ), + aBaseModelName, + path ); + + if( m_reporter ) + m_reporter->Report( msg, RPT_SEVERITY_ERROR ); + else + THROW_IO_ERROR( msg ); + } } - m_models.push_back( SIM_MODEL::Create( *baseModel, aPins, aFields, m_reporter ) ); + m_models.push_back( SIM_MODEL::Create( baseModel, aPins, aFields, m_reporter ) ); - return { aBaseModelName, *m_models.back() }; + return { modelName, *m_models.back() }; } diff --git a/eeschema/sim/sim_lib_mgr.h b/eeschema/sim/sim_lib_mgr.h index b266fe5947..3e58098bf3 100644 --- a/eeschema/sim/sim_lib_mgr.h +++ b/eeschema/sim/sim_lib_mgr.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -40,20 +40,22 @@ class SCH_SYMBOL; class SIM_LIB_MGR { public: - SIM_LIB_MGR( const PROJECT* aPrj, REPORTER* aReporter = nullptr ); + SIM_LIB_MGR( const PROJECT* aPrj ); virtual ~SIM_LIB_MGR() = default; + void SetReporter( REPORTER* aReporter ) { m_reporter = aReporter; } + void Clear(); - SIM_LIBRARY& AddLibrary( const wxString& aLibraryPath, REPORTER* aReporter ); - SIM_LIBRARY& SetLibrary( const wxString& aLibraryPath, REPORTER* aReporter ); + void AddLibrary( const wxString& aLibraryPath ); + void SetLibrary( const wxString& aLibraryPath ); SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, const std::vector& aPins ); - SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector& aPins ); + SIM_MODEL& CreateModel( const SIM_MODEL* aBaseModel, const std::vector& aPins ); template - SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector& aPins, + SIM_MODEL& CreateModel( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields ); // TODO: The argument can be made const. @@ -61,7 +63,7 @@ public: template SIM_LIBRARY::MODEL CreateModel( const std::vector& aFields, - const std::vector& aPins ); + const std::vector& aPins, bool aResolved ); template SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath, diff --git a/eeschema/sim/sim_library.cpp b/eeschema/sim/sim_library.cpp index 16a5938148..3d0159851f 100644 --- a/eeschema/sim/sim_library.cpp +++ b/eeschema/sim/sim_library.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -28,8 +28,8 @@ #include -std::unique_ptr SIM_LIBRARY::Create( const wxString &aFilePath, REPORTER *aReporter, - std::function *aResolver ) +std::unique_ptr SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter, + std::function *aResolver ) { std::unique_ptr library; @@ -40,12 +40,12 @@ std::unique_ptr SIM_LIBRARY::Create( const wxString &aFilePath, REP library->m_reporter = aReporter; library->m_pathResolver = aResolver; - library->ReadFile( std::string( aFilePath.c_str() ) ); + library->ReadFile( std::string( aFilePath.c_str() ), aReporter ); return library; } -void SIM_LIBRARY::ReadFile( const std::string& aFilePath ) +void SIM_LIBRARY::ReadFile( const std::string& aFilePath, REPORTER* aReporter ) { m_filePath = aFilePath; } diff --git a/eeschema/sim/sim_library.h b/eeschema/sim/sim_library.h index f6a447bddb..7ce2a92eea 100644 --- a/eeschema/sim/sim_library.h +++ b/eeschema/sim/sim_library.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -54,7 +54,7 @@ public: */ static std::unique_ptr Create( const wxString& aFilePath, REPORTER* aReporter = nullptr, - std::function* aResolver = nullptr); + std::function* aResolver = nullptr); /** * Read library from a source file. Must be in the format appropriate to the subclass, e.g. @@ -63,7 +63,7 @@ public: * @param aFilePath Path to the file. * @throw IO_ERROR on read or parsing error. */ - virtual void ReadFile( const std::string& aFilePath ) = 0; + virtual void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) = 0; /** * Write library to a source file (e.g. in Spice format). diff --git a/eeschema/sim/sim_library_kibis.cpp b/eeschema/sim/sim_library_kibis.cpp index 2f8538d301..e8b0dc82b5 100644 --- a/eeschema/sim/sim_library_kibis.cpp +++ b/eeschema/sim/sim_library_kibis.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * 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 * modify it under the terms of the GNU General Public License @@ -23,21 +23,23 @@ #include #include -#include #include #include -#include #include #include -void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath ) +void SIM_LIBRARY_KIBIS::ReadFile( const std::string& aFilePath, REPORTER* aReporter ) { - SIM_LIBRARY::ReadFile( aFilePath ); + SIM_LIBRARY::ReadFile( aFilePath, aReporter ); m_kibis = KIBIS( aFilePath, m_reporter ); if( !m_kibis.m_valid ) - THROW_IO_ERROR( wxString::Format( "Invalid ibis file" ) ); + { + aReporter->Report( wxString::Format( _( "Invalid IBIS file '%s'" ), aFilePath ), + RPT_SEVERITY_ERROR ); + return; + } LIB_PIN pinA( nullptr ); LIB_PIN pinB( nullptr ); diff --git a/eeschema/sim/sim_library_kibis.h b/eeschema/sim/sim_library_kibis.h index 7822d713b9..12ae08f9ea 100644 --- a/eeschema/sim/sim_library_kibis.h +++ b/eeschema/sim/sim_library_kibis.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * 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 * modify it under the terms of the GNU General Public License @@ -38,7 +38,7 @@ public: static constexpr auto DIFF_FIELD = "Sim.Ibis.Diff"; // @copydoc SIM_LIBRARY::ReadFile() - void ReadFile( const std::string& aFilePath ) override; + void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) override; // @copydoc SIM_LIBRARY::WriteFile() void WriteFile( const std::string& aFilePath ) override{}; diff --git a/eeschema/sim/sim_library_spice.cpp b/eeschema/sim/sim_library_spice.cpp index c628b9884e..3d29313f5e 100644 --- a/eeschema/sim/sim_library_spice.cpp +++ b/eeschema/sim/sim_library_spice.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -33,10 +33,10 @@ SIM_LIBRARY_SPICE::SIM_LIBRARY_SPICE() : } -void SIM_LIBRARY_SPICE::ReadFile( const std::string& aFilePath ) +void SIM_LIBRARY_SPICE::ReadFile( const std::string& aFilePath, REPORTER* aReporter ) { - SIM_LIBRARY::ReadFile( aFilePath ); - m_spiceLibraryParser->ReadFile( aFilePath ); + SIM_LIBRARY::ReadFile( aFilePath, aReporter ); + m_spiceLibraryParser->ReadFile( aFilePath, aReporter ); } diff --git a/eeschema/sim/sim_library_spice.h b/eeschema/sim/sim_library_spice.h index 048778cc26..a97144b3e3 100644 --- a/eeschema/sim/sim_library_spice.h +++ b/eeschema/sim/sim_library_spice.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -37,7 +37,7 @@ public: SIM_LIBRARY_SPICE(); // @copydoc SIM_LIBRARY::ReadFile() - void ReadFile( const std::string& aFilePath ) override; + void ReadFile( const std::string& aFilePath, REPORTER* aReporter ) override; // @copydoc SIM_LIBRARY::WriteFile() void WriteFile( const std::string& aFilePath ) override; diff --git a/eeschema/sim/sim_model.cpp b/eeschema/sim/sim_model.cpp index 38e4eb1fe5..99f62a030a 100644 --- a/eeschema/sim/sim_model.cpp +++ b/eeschema/sim/sim_model.cpp @@ -465,23 +465,28 @@ std::unique_ptr SIM_MODEL::Create( TYPE aType, const std::vector SIM_MODEL::Create( const SIM_MODEL& aBaseModel, +std::unique_ptr SIM_MODEL::Create( const SIM_MODEL* aBaseModel, const std::vector& aPins, REPORTER* aReporter ) { + TYPE type = aBaseModel ? aBaseModel->GetType() : TYPE::NONE; std::unique_ptr model; - if( dynamic_cast( &aBaseModel ) ) - model = std::make_unique( aBaseModel.GetType() ); - else if( dynamic_cast< const SIM_MODEL_RAW_SPICE*>( &aBaseModel ) ) + // A null base model means the model wasn't found in the library, so create a fallback + + if( !aBaseModel || dynamic_cast( aBaseModel ) ) + model = std::make_unique( type ); + else if( dynamic_cast< const SIM_MODEL_RAW_SPICE*>( aBaseModel ) ) model = std::make_unique(); else - model = Create( aBaseModel.GetType() ); + model = Create( type ); try { + if( aBaseModel ) + model->SetBaseModel( *aBaseModel ); + model->ReadDataFields( static_cast*>( nullptr ), aPins ); - model->SetBaseModel( aBaseModel ); } catch( IO_ERROR& err ) { @@ -496,7 +501,7 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, template -std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, +std::unique_ptr SIM_MODEL::Create( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields, REPORTER* aReporter ) @@ -504,21 +509,25 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, TYPE type = ReadTypeFromFields( aFields ); // If the model has a specified type, it takes priority over the type of its base class. - if( type == TYPE::NONE ) - type = aBaseModel.GetType(); + if( type == TYPE::NONE && aBaseModel ) + type = aBaseModel->GetType(); std::unique_ptr model; - if( dynamic_cast( &aBaseModel ) ) + // A null base model means the model wasn't found in the library, so create a fallback + + if( !aBaseModel || dynamic_cast( aBaseModel ) ) model = std::make_unique( type ); - else if( dynamic_cast< const SIM_MODEL_RAW_SPICE*>( &aBaseModel ) ) + else if( dynamic_cast< const SIM_MODEL_RAW_SPICE*>( aBaseModel ) ) model = std::make_unique(); else model = Create( type ); try { - model->SetBaseModel( aBaseModel ); + if( aBaseModel ) + model->SetBaseModel( *aBaseModel ); + model->ReadDataFields( &aFields, aPins ); } catch( IO_ERROR& err ) @@ -532,12 +541,12 @@ std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, return model; } -template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, +template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields, REPORTER* aReporter ); -template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseModel, +template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields, REPORTER* aReporter ); @@ -546,7 +555,7 @@ template std::unique_ptr SIM_MODEL::Create( const SIM_MODEL& aBaseMod template std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, const std::vector& aPins, - REPORTER* aReporter ) + bool aResolved, REPORTER* aReporter ) { TYPE type = ReadTypeFromFields( aFields ); std::unique_ptr model = SIM_MODEL::Create( type ); @@ -557,6 +566,12 @@ std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, } catch( const IO_ERROR& parse_err ) { + if( !aResolved ) + { + aReporter->Report( parse_err.What(), RPT_SEVERITY_ERROR ); + return model; + } + // Just because we can't parse it doesn't mean that a SPICE interpreter can't. Fall // back to a raw spice code model. @@ -587,10 +602,10 @@ std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, template std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, const std::vector& aPins, - REPORTER* aReporter ); + bool aResolved, REPORTER* aReporter ); template std::unique_ptr SIM_MODEL::Create( const std::vector& aFields, const std::vector& aPins, - REPORTER* aReporter ); + bool aResolved, REPORTER* aReporter ); template @@ -1560,13 +1575,18 @@ void SIM_MODEL::MigrateSimModel( T_symbol& aSymbol, const PROJECT* aProject ) { wxString msg; WX_STRING_REPORTER reporter( &msg ); - SIM_LIB_MGR libMgr( aProject, &reporter ); + SIM_LIB_MGR libMgr( aProject ); std::vector emptyFields; + libMgr.SetReporter( &reporter ); + SIM_LIBRARY::MODEL model = libMgr.CreateModel( spiceLib, spiceModel.ToStdString(), emptyFields, sourcePins ); - libraryModel = !reporter.HasMessage(); // Otherwise we'll fall back to raw spice model + if( reporter.HasMessage() ) + libraryModel = false; // Fall back to raw spice model + else + libraryModel = true; if( pinMapInfo.IsEmpty() ) { diff --git a/eeschema/sim/sim_model.h b/eeschema/sim/sim_model.h index e3d54da8a1..ce0600fc22 100644 --- a/eeschema/sim/sim_model.h +++ b/eeschema/sim/sim_model.h @@ -404,12 +404,12 @@ public: static std::unique_ptr Create( TYPE aType, const std::vector& aPins, REPORTER* aReporter ); - static std::unique_ptr Create( const SIM_MODEL& aBaseModel, + static std::unique_ptr Create( const SIM_MODEL* aBaseModel, const std::vector& aPins, REPORTER* aReporter ); template - static std::unique_ptr Create( const SIM_MODEL& aBaseModel, + static std::unique_ptr Create( const SIM_MODEL* aBaseModel, const std::vector& aPins, const std::vector& aFields, REPORTER* aReporter ); @@ -417,7 +417,7 @@ public: template static std::unique_ptr Create( const std::vector& aFields, const std::vector& aPins, - REPORTER* aReporter ); + bool aResolved, REPORTER* aReporter ); template static std::string GetFieldValue( const std::vector* aFields, const std::string& aFieldName, diff --git a/eeschema/sim/spice_library_parser.cpp b/eeschema/sim/spice_library_parser.cpp index ecb024b0f8..7e3aa0c4cb 100644 --- a/eeschema/sim/spice_library_parser.cpp +++ b/eeschema/sim/spice_library_parser.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -57,65 +57,89 @@ namespace SIM_LIBRARY_SPICE_PARSER }; -void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath ) +void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath, REPORTER& aReporter ) { - tao::pegtl::file_input in( aFilePath ); - std::unique_ptr root = - tao::pegtl::parse_tree::parse( in ); - - for( const auto& node : root->children ) + try { - if( node->is_type() ) + tao::pegtl::file_input in( aFilePath ); + std::unique_ptr root = + tao::pegtl::parse_tree::parse + ( in ); + + for( const auto& node : root->children ) { - try + if( node->is_type() ) { - m_library.m_models.push_back( SIM_MODEL_SPICE::Create( m_library, node->string() ) ); - m_library.m_modelNames.emplace_back( node->children.at( 0 )->string() ); + std::string model = node->string(); + std::string modelName = node->children.at( 0 )->string(); + + try + { + m_library.m_models.push_back( SIM_MODEL_SPICE::Create( m_library, model ) ); + m_library.m_modelNames.emplace_back( modelName ); + } + catch( const IO_ERROR& e ) + { + aReporter.Report( e.What(), RPT_SEVERITY_ERROR ); + } } - catch( const IO_ERROR& e ) + else if( node->is_type() ) { - DisplayErrorMessage( nullptr, e.What() ); + std::string lib = node->children.at( 0 )->string(); + + try + { + if( m_library.m_pathResolver ) + lib = ( *m_library.m_pathResolver )( lib, aFilePath ); + + readElement( lib, aReporter ); + } + catch( const IO_ERROR& e ) + { + aReporter.Report( e.What(), RPT_SEVERITY_ERROR ); + } + } + else if( node->is_type() ) + { + // Do nothing. + } + else + { + wxFAIL_MSG( "Unhandled parse tree node" ); } } - else if( node->is_type() ) - { - std::string lib = node->children.at( 0 )->string(); - - if( m_library.m_pathResolver ) - lib = ( *m_library.m_pathResolver )( lib, aFilePath ); - - readElement( lib ); - } - else if( node->is_type() ) - { - // Do nothing. - } - else - { - wxFAIL_MSG( "Unhandled parse tree node" ); - } + } + catch( const std::filesystem::filesystem_error& e ) + { + aReporter.Report( e.what(), RPT_SEVERITY_ERROR ); + } + catch( const tao::pegtl::parse_error& e ) + { + aReporter.Report( e.what(), RPT_SEVERITY_ERROR ); } } -void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath ) +void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath, REPORTER* aReporter ) { m_library.m_models.clear(); m_library.m_modelNames.clear(); - try + if( aReporter ) { - readElement( aFilePath ); + readElement( aFilePath, *aReporter ); } - catch( const std::filesystem::filesystem_error& e ) + else { - THROW_IO_ERROR( e.what() ); - } - catch( const tao::pegtl::parse_error& e ) - { - THROW_IO_ERROR( e.what() ); + wxString msg; + WX_STRING_REPORTER reporter( &msg ); + + readElement( aFilePath, reporter ); + + if( reporter.HasMessage() ) + THROW_IO_ERROR( msg ); } } diff --git a/eeschema/sim/spice_library_parser.h b/eeschema/sim/spice_library_parser.h index a4af8ca567..e364e810bf 100644 --- a/eeschema/sim/spice_library_parser.h +++ b/eeschema/sim/spice_library_parser.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * 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 * modify it under the terms of the GNU General Public License @@ -28,6 +28,7 @@ #include class SIM_LIBRARY_SPICE; +class REPORTER; class SPICE_LIBRARY_PARSER { @@ -39,10 +40,10 @@ public: virtual ~SPICE_LIBRARY_PARSER() {}; - virtual void ReadFile( const std::string& aFilePath ); + virtual void ReadFile( const std::string& aFilePath, REPORTER* aReporter ); protected: - void readElement( const std::string& aFilePath ); + void readElement( const std::string& aFilePath, REPORTER& aReporter ); private: SIM_LIBRARY_SPICE& m_library; diff --git a/qa/unittests/eeschema/sim/test_library_spice.cpp b/qa/unittests/eeschema/sim/test_library_spice.cpp index a3e51eb3e8..4aaf3a7a57 100644 --- a/qa/unittests/eeschema/sim/test_library_spice.cpp +++ b/qa/unittests/eeschema/sim/test_library_spice.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * 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 * modify it under the terms of the GNU General Public License @@ -48,7 +48,7 @@ public: { std::string path = GetLibraryPath( aBaseName ); m_library = std::make_unique(); - m_library->ReadFile( path ); + m_library->ReadFile( path, nullptr ); } void CompareToUsualDiodeModel( const SIM_MODEL& aModel, const std::string& aModelName, int aModelIndex )