Reduce reliance on exception processing -- it's waay too bugy at present.

This moves some stuff to REPORTER APIs.  Moving more stuff would be good,
but it probably too high-risk at present.  We'll wait for 8.0 for that....

Fixes https://gitlab.com/kicad/code/kicad/issues/13359
This commit is contained in:
Jeff Young 2023-01-03 15:29:45 +00:00
parent d1c2ab957b
commit 9b9795a87d
16 changed files with 258 additions and 213 deletions

View File

@ -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<T_symbol, T_field>::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<T_symbol, T_field>::TransferDataToWindow()
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
try
{
wxString msg;
WX_STRING_REPORTER reporter( &msg );
m_builtinModelsMgr.SetReporter( &reporter );
if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType )
m_builtinModelsMgr.CreateModel( m_fields, sourcePins );
m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false );
else
m_builtinModelsMgr.CreateModel( type, sourcePins );
}
catch( const IO_ERROR& e )
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<T_symbol, T_field>::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<T_symbol, T_field>::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 );
for( auto& [baseModelName, baseModel] : library()->GetModels() )
{
if( baseModelName == modelName )
m_libraryModelsMgr.CreateModel( baseModel, sourcePins, m_fields );
m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields );
else
m_libraryModelsMgr.CreateModel( baseModel, sourcePins );
}
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( this, e.What() );
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 );

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
* 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 )
{

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 1992-2013 jp.charras at wanadoo.fr
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* 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,32 +395,14 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER&
for( const auto& node : root->children )
{
if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotTitle>() )
{
m_title = node->children.at( 0 )->string();
}
else if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotInclude>() )
{
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() );
}
}
}
}
}

View File

@ -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 <sim/sim_model.h>
#include <sim/sim_model_ideal.h>
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.
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 );
// 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.
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 );
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, aReporter, &f2 );
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, m_reporter, &f2 );
Clear();
m_libraries[path] = std::move( library );
return *m_libraries.at( path );
}
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<LI
}
SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel,
SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& 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 <typename T>
SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL& aBaseModel,
SIM_MODEL& SIM_LIB_MGR::CreateModel( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& 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<LIB_PIN*>& aPins,
const std::vector<SCH_FIELD>& 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<LIB_PIN*>& aPins,
const std::vector<LIB_FIELD>& 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 <typename T>
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins )
const std::vector<LIB_PIN*>& 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<T>& 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<SCH_FIELD>& aFields,
const std::vector<LIB_PIN*>& aPins );
const std::vector<LIB_PIN*>& aPins,
bool aResolved );
template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<LIB_FIELD>& aFields,
const std::vector<LIB_PIN*>& aPins );
const std::vector<LIB_PIN*>& aPins,
bool aResolved );
template <typename T>
@ -272,16 +283,20 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins )
{
wxString path = ResolveLibraryPath( aLibraryPath, m_project );
SIM_LIBRARY* library = nullptr;
wxString path;
wxString msg;
std::function<std::string(const std::string&, const std::string&)> 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<std::string( const std::string&, const std::string& )> 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,13 +320,18 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
m_reporter->Report( msg, RPT_SEVERITY_ERROR );
else
THROW_IO_ERROR( msg );
}
SIM_MODEL* baseModel = library->FindModel( aBaseModelName );
modelName = _( "unknown" ).ToStdString();
}
else if( library )
{
baseModel = library->FindModel( aBaseModelName );
modelName = aBaseModelName;
if( !baseModel )
{
msg.Printf( _( "Error loading simulation model: could not find base model '%s' in library '%s'" ),
msg.Printf( _( "Error loading simulation model: could not find base model '%s' "
"in library '%s'" ),
aBaseModelName,
path );
@ -320,10 +340,11 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
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() };
}

View File

@ -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<LIB_PIN*>& aPins );
SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector<LIB_PIN*>& aPins );
SIM_MODEL& CreateModel( const SIM_MODEL* aBaseModel, const std::vector<LIB_PIN*>& aPins );
template <typename T>
SIM_MODEL& CreateModel( const SIM_MODEL& aBaseModel, const std::vector<LIB_PIN*>& aPins,
SIM_MODEL& CreateModel( const SIM_MODEL* aBaseModel, const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& aFields );
// TODO: The argument can be made const.
@ -61,7 +63,7 @@ public:
template <typename T>
SIM_LIBRARY::MODEL CreateModel( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins );
const std::vector<LIB_PIN*>& aPins, bool aResolved );
template <typename T>
SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath,

View File

@ -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,7 +28,7 @@
#include <boost/algorithm/string/case_conv.hpp>
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString &aFilePath, REPORTER *aReporter,
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter,
std::function<std::string( const std::string&, const std::string& )> *aResolver )
{
std::unique_ptr<SIM_LIBRARY> library;
@ -40,12 +40,12 @@ std::unique_ptr<SIM_LIBRARY> 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;
}

View File

@ -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<SIM_LIBRARY> Create( const wxString& aFilePath,
REPORTER* aReporter = nullptr,
std::function<std::string(const std::string&, const std::string&)>* aResolver = nullptr);
std::function<std::string( const std::string&, const std::string& )>* 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).

View File

@ -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 <sim/sim_library_kibis.h>
#include <sim/sim_model_kibis.h>
#include <sim/spice_grammar.h>
#include <ki_exception.h>
#include <locale_io.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
#include <lib_pin.h>
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 );

View File

@ -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{};

View File

@ -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 );
}

View File

@ -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;

View File

@ -465,23 +465,28 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType, const std::vector<LIB_
}
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter )
{
TYPE type = aBaseModel ? aBaseModel->GetType() : TYPE::NONE;
std::unique_ptr<SIM_MODEL> model;
if( dynamic_cast<const SIM_MODEL_SPICE_FALLBACK*>( &aBaseModel ) )
model = std::make_unique<SIM_MODEL_SPICE_FALLBACK>( 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<const SIM_MODEL_SPICE_FALLBACK*>( aBaseModel ) )
model = std::make_unique<SIM_MODEL_SPICE_FALLBACK>( type );
else if( dynamic_cast< const SIM_MODEL_RAW_SPICE*>( aBaseModel ) )
model = std::make_unique<SIM_MODEL_RAW_SPICE>();
else
model = Create( aBaseModel.GetType() );
model = Create( type );
try
{
if( aBaseModel )
model->SetBaseModel( *aBaseModel );
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
model->SetBaseModel( aBaseModel );
}
catch( IO_ERROR& err )
{
@ -496,7 +501,7 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
template <typename T>
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& aFields,
REPORTER* aReporter )
@ -504,21 +509,25 @@ std::unique_ptr<SIM_MODEL> 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<SIM_MODEL> model;
if( dynamic_cast<const SIM_MODEL_SPICE_FALLBACK*>( &aBaseModel ) )
// A null base model means the model wasn't found in the library, so create a fallback
if( !aBaseModel || dynamic_cast<const SIM_MODEL_SPICE_FALLBACK*>( aBaseModel ) )
model = std::make_unique<SIM_MODEL_SPICE_FALLBACK>( 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<SIM_MODEL_RAW_SPICE>();
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> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
return model;
}
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<SCH_FIELD>& aFields,
REPORTER* aReporter );
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<LIB_FIELD>& aFields,
REPORTER* aReporter );
@ -546,7 +555,7 @@ template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseMod
template <typename T>
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter )
bool aResolved, REPORTER* aReporter )
{
TYPE type = ReadTypeFromFields( aFields );
std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
@ -557,6 +566,12 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& 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> SIM_MODEL::Create( const std::vector<T>& aFields,
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<SCH_FIELD>& aFields,
const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter );
bool aResolved, REPORTER* aReporter );
template std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<LIB_FIELD>& aFields,
const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter );
bool aResolved, REPORTER* aReporter );
template <typename T>
@ -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<T_field> 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() )
{

View File

@ -404,12 +404,12 @@ public:
static std::unique_ptr<SIM_MODEL> Create( TYPE aType, const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter );
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel,
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel,
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL* aBaseModel,
const std::vector<LIB_PIN*>& aPins,
const std::vector<T>& aFields,
REPORTER* aReporter );
@ -417,7 +417,7 @@ public:
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins,
REPORTER* aReporter );
bool aResolved, REPORTER* aReporter );
template <typename T>
static std::string GetFieldValue( const std::vector<T>* aFields, const std::string& aFieldName,

View File

@ -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,37 +57,50 @@ 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 )
{
try
{
tao::pegtl::file_input in( aFilePath );
std::unique_ptr<tao::pegtl::parse_tree::node> root =
tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
SIM_LIBRARY_SPICE_PARSER::librarySelector,
tao::pegtl::nothing,
SIM_LIBRARY_SPICE_PARSER::control>( in );
SIM_LIBRARY_SPICE_PARSER::control>
( in );
for( const auto& node : root->children )
{
if( node->is_type<SIM_LIBRARY_SPICE_PARSER::modelUnit>() )
{
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, node->string() ) );
m_library.m_modelNames.emplace_back( node->children.at( 0 )->string() );
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 )
{
DisplayErrorMessage( nullptr, e.What() );
aReporter.Report( e.What(), RPT_SEVERITY_ERROR );
}
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::dotInclude>() )
{
std::string lib = node->children.at( 0 )->string();
try
{
if( m_library.m_pathResolver )
lib = ( *m_library.m_pathResolver )( lib, aFilePath );
readElement( lib );
readElement( lib, aReporter );
}
catch( const IO_ERROR& e )
{
aReporter.Report( e.What(), RPT_SEVERITY_ERROR );
}
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::unknownLine>() )
{
@ -98,24 +111,35 @@ void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath )
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 );
}
}

View File

@ -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 <wx/string.h>
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;

View File

@ -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<SIM_LIBRARY_SPICE>();
m_library->ReadFile( path );
m_library->ReadFile( path, nullptr );
}
void CompareToUsualDiodeModel( const SIM_MODEL& aModel, const std::string& aModelName, int aModelIndex )