Gracefully fall back to raw spice when we can't parse the data.

Fixes https://gitlab.com/kicad/code/kicad/issues/13329
This commit is contained in:
Jeff Young 2022-12-31 18:51:47 +00:00
parent 77b361a077
commit 55b8f0bc00
6 changed files with 59 additions and 36 deletions

View File

@ -568,9 +568,6 @@ void DIALOG_SIM_MODEL<T_symbol, T_field>::updateModelCodeTab()
text << model.SpiceGenerator().Preview( item );
if( SIM_MODEL_RAW_SPICE* rawSpice = dynamic_cast<SIM_MODEL_RAW_SPICE*>( &model ) )
text << rawSpice->GetSource();
m_codePreview->SetText( text );
m_codePreview->SelectNone();
}

View File

@ -443,19 +443,20 @@ void SIM_MODEL::WriteFields( std::vector<LIB_FIELD>& aFields ) const
}
std::unique_ptr<SIM_MODEL> SIM_MODEL::CreateFallback( TYPE aType, const std::string& aSpiceCode )
{
std::unique_ptr<SIM_MODEL> model( new SIM_MODEL_SPICE_FALLBACK( aType, aSpiceCode ) );
return model;
}
std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( TYPE aType, const std::vector<LIB_PIN*>& aPins )
{
std::unique_ptr<SIM_MODEL> model = Create( aType );
// Passing nullptr to ReadDataFields will make it act as if all fields were empty.
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
try
{
// Passing nullptr to ReadDataFields will make it act as if all fields were empty.
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
}
catch( ... )
{
// Shouldn't happen with nothing to read from fields
}
return model;
}
@ -466,12 +467,15 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
std::unique_ptr<SIM_MODEL> model;
if( dynamic_cast<const SIM_MODEL_SPICE_FALLBACK*>( &aBaseModel ) )
model = CreateFallback( aBaseModel.GetType() );
model = std::make_unique<SIM_MODEL_SPICE_FALLBACK>( aBaseModel.GetType() );
else if( dynamic_cast< const SIM_MODEL_RAW_SPICE*>( &aBaseModel ) )
model = std::make_unique<SIM_MODEL_RAW_SPICE>();
else
model = Create( aBaseModel.GetType() );
try
{
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
model->SetBaseModel( aBaseModel );
}
catch( IO_ERROR& err )
@ -479,7 +483,6 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
DisplayErrorMessage( nullptr, err.What() );
}
model->ReadDataFields( static_cast<const std::vector<SCH_FIELD>*>( nullptr ), aPins );
return model;
}
@ -498,20 +501,22 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const SIM_MODEL& aBaseModel,
std::unique_ptr<SIM_MODEL> model;
if( dynamic_cast<const SIM_MODEL_SPICE_FALLBACK*>( &aBaseModel ) )
model = CreateFallback( type );
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( type );
try
{
model->SetBaseModel( aBaseModel );
model->ReadDataFields( &aFields, aPins );
}
catch( IO_ERROR& err )
{
DisplayErrorMessage( nullptr, err.What() );
}
model->ReadDataFields( &aFields, aPins );
return model;
}
@ -531,7 +536,34 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::Create( const std::vector<T>& aFields,
TYPE type = ReadTypeFromFields( aFields );
std::unique_ptr<SIM_MODEL> model = SIM_MODEL::Create( type );
model->ReadDataFields( &aFields, aPins );
try
{
model->ReadDataFields( &aFields, aPins );
}
catch( const IO_ERROR& e )
{
// Just because we can't parse it doesn't mean that a SPICE interpreter can't. Fall
// back to a raw spice code model.
std::string modelData = GetFieldValue( &aFields, PARAMS_FIELD );
if( modelData.empty() )
modelData = GetFieldValue( &aFields, VALUE_FIELD );
model = std::make_unique<SIM_MODEL_RAW_SPICE>( modelData );
try
{
model->createPins( aPins );
model->m_serializer->ParsePins( GetFieldValue( &aFields, PINS_FIELD ) );
}
catch( const IO_ERROR& e )
{
// We own the pin syntax, so if we can't parse it then there's an error, full stop.
DisplayErrorMessage( nullptr, e.What() );
}
}
return model;
}
@ -965,22 +997,15 @@ void SIM_MODEL::doReadDataFields( const std::vector<T>* aFields,
bool diffMode = GetFieldValue( aFields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
SwitchSingleEndedDiff( diffMode );
try
{
m_serializer->ParseEnable( GetFieldValue( aFields, ENABLE_FIELD ) );
m_serializer->ParseEnable( GetFieldValue( aFields, ENABLE_FIELD ) );
createPins( aPins );
m_serializer->ParsePins( GetFieldValue( aFields, PINS_FIELD ) );
createPins( aPins );
m_serializer->ParsePins( GetFieldValue( aFields, PINS_FIELD ) );
std::string paramsField = GetFieldValue( aFields, PARAMS_FIELD );
std::string paramsField = GetFieldValue( aFields, PARAMS_FIELD );
if( !m_serializer->ParseParams( paramsField ) )
m_serializer->ParseValue( GetFieldValue( aFields, VALUE_FIELD ) );
}
catch( IO_ERROR& err )
{
DisplayErrorMessage( nullptr, err.What() );
}
if( !m_serializer->ParseParams( paramsField ) )
m_serializer->ParseValue( GetFieldValue( aFields, VALUE_FIELD ) );
}

View File

@ -414,9 +414,6 @@ public:
static std::unique_ptr<SIM_MODEL> Create( const std::vector<T>& aFields,
const std::vector<LIB_PIN*>& aPins );
static std::unique_ptr<SIM_MODEL> CreateFallback( TYPE aType,
const std::string& aSpiceCode = "" );
template <typename T>
static std::string GetFieldValue( const std::vector<T>* aFields, const std::string& aFieldName,
bool aResolve = true );

View File

@ -112,13 +112,16 @@ std::string SPICE_GENERATOR_RAW_SPICE::Preview( const SPICE_ITEM& aItem ) const
}
SIM_MODEL_RAW_SPICE::SIM_MODEL_RAW_SPICE() :
SIM_MODEL( TYPE::RAWSPICE, std::make_unique<SPICE_GENERATOR_RAW_SPICE>( *this ) )
SIM_MODEL_RAW_SPICE::SIM_MODEL_RAW_SPICE( const std::string& aSpiceSource ) :
SIM_MODEL( TYPE::RAWSPICE, std::make_unique<SPICE_GENERATOR_RAW_SPICE>( *this ) ),
m_spiceCode( aSpiceSource )
{
static std::vector<PARAM::INFO> paramInfos = makeParamInfos();
for( const PARAM::INFO& paramInfo : paramInfos )
AddParam( paramInfo );
SetParamValue( "model", aSpiceSource );
}

View File

@ -62,7 +62,7 @@ public:
static constexpr auto LEGACY_ENABLED_FIELD = "Spice_Netlist_Enabled";
static constexpr auto LEGACY_LIB_FIELD = "Spice_Lib_File";
SIM_MODEL_RAW_SPICE();
SIM_MODEL_RAW_SPICE( const std::string& aSpiceSource = "" );
void SetSource( const std::string& aSpiceSource ) { m_spiceCode = aSpiceSource; }

View File

@ -194,6 +194,7 @@ std::string SPICE_GENERATOR::Preview( const SPICE_ITEM& aItem ) const
std::string spiceCode = ModelLine( aItem );
std::string itemLine = ItemLine( aItem );
if( spiceCode != "" )
spiceCode.append( "\n" );