Sim: Implement loading Spice library files

Implement parsing and loading Spice libraries into KiCad. This is done
without any involvement of Ngspice -- we create our own in-tree parser
using PEGTL -- because Ngspice doesn't offer any intermediate output we
could plug ourselves into. We don't parse everything -- just the library
content, so this won't be that much effort.

We implement some basic Spice code preview to give the user a hint what
Spice code eir model will correspond to.
This commit is contained in:
Mikolaj Wielgus 2022-04-01 06:30:50 +02:00
parent 978f01553b
commit ce84a48037
32 changed files with 2135 additions and 725 deletions

View File

@ -320,6 +320,8 @@ if( KICAD_SPICE )
sim/sim_plot_panel.cpp
sim/sim_property.cpp
sim/sim_workbook.cpp
sim/sim_library.cpp
sim/sim_library_spice.cpp
sim/sim_model.cpp
sim/sim_model_behavioral.cpp
sim/sim_model_codemodel.cpp

View File

@ -24,10 +24,12 @@
#include <dialog_spice_model.h>
#include <sim/sim_property.h>
#include <sim/sim_library_spice.h>
#include <widgets/wx_grid.h>
#include <kiplatform/ui.h>
#include <confirm.h>
#include <locale_io.h>
#include <wx/filedlg.h>
using TYPE = SIM_VALUE_BASE::TYPE;
using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
@ -42,26 +44,18 @@ DIALOG_SPICE_MODEL<T>::DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbo
: DIALOG_SPICE_MODEL_BASE( aParent ),
m_symbol( aSymbol ),
m_fields( aFields ),
m_library( std::make_shared<SIM_LIBRARY_SPICE>() ),
m_prevModel( nullptr ),
m_firstCategory( nullptr )
{
try
{
SIM_MODEL::TYPE typeFromFields = SIM_MODEL::ReadTypeFromFields( aFields );
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
if( type == typeFromFields )
{
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size(),
&aFields ) );
m_curModelType = type;
}
else
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size() ) );
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size() ) );
SIM_MODEL::DEVICE_TYPE deviceType = SIM_MODEL::TypeInfo( type ).deviceType;
// By default choose the first model type of each device type.
if( !m_curModelTypeOfDeviceType.count( deviceType ) )
m_curModelTypeOfDeviceType[deviceType] = type;
}
@ -114,30 +108,40 @@ DIALOG_SPICE_MODEL<T>::DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbo
}
template <typename T>
bool DIALOG_SPICE_MODEL<T>::TransferDataFromWindow()
{
if( !DIALOG_SPICE_MODEL_BASE::TransferDataFromWindow() )
return false;
getCurModel().WriteFields( m_fields );
return true;
}
template <typename T>
bool DIALOG_SPICE_MODEL<T>::TransferDataToWindow()
{
try
wxString libraryFilename = SIM_MODEL::GetFieldValue( &m_fields, LIBRARY_FIELD );
if( !libraryFilename.IsEmpty() )
{
m_models.at( static_cast<int>( SIM_MODEL::ReadTypeFromFields( m_fields ) ) )
= SIM_MODEL::Create( m_symbol.GetAllPins().size(), m_fields );
// The model is sourced from a library, optionally with instance overrides.
loadLibrary( libraryFilename );
// Must be set before curModel() is used since the latter checks the combobox value.
m_modelNameCombobox->SetStringSelection( SIM_MODEL::GetFieldValue( &m_fields, NAME_FIELD ) );
curModel().ReadDataFields( m_symbol.GetAllPins().size(), &m_fields );
m_overrideCheckbox->SetValue( curModel().HasNonPrincipalOverrides() );
}
catch( KI_PARAM_ERROR& e )
else
{
DisplayErrorMessage( this, e.What() );
return DIALOG_SPICE_MODEL_BASE::TransferDataToWindow();
// The model is sourced from the instance.
SIM_MODEL::TYPE type = SIM_MODEL::ReadTypeFromFields( m_fields );
try
{
m_models.at( static_cast<int>( SIM_MODEL::ReadTypeFromFields( m_fields ) ) )
= SIM_MODEL::Create( m_symbol.GetAllPins().size(), m_fields );
}
catch( KI_PARAM_ERROR& e )
{
DisplayErrorMessage( this, e.What() );
return DIALOG_SPICE_MODEL_BASE::TransferDataToWindow();
}
m_curModelType = type;
}
updateWidgets();
@ -146,94 +150,145 @@ bool DIALOG_SPICE_MODEL<T>::TransferDataToWindow()
}
template <typename T>
bool DIALOG_SPICE_MODEL<T>::TransferDataFromWindow()
{
if( !DIALOG_SPICE_MODEL_BASE::TransferDataFromWindow() )
return false;
if( m_useLibraryModelRadioButton->GetValue() )
{
SIM_MODEL::SetFieldValue( m_fields, NAME_FIELD, m_modelNameCombobox->GetValue() );
SIM_MODEL::SetFieldValue( m_fields, LIBRARY_FIELD, m_library->GetFilename() );
}
curModel().WriteFields( m_fields );
return true;
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::updateWidgets()
{
updateModelParamsTab();
updateModelCodeTab();
updatePinAssignmentsTab();
m_prevModel = &curModel();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::updateModelParamsTab()
{
SIM_MODEL::DEVICE_TYPE deviceType = SIM_MODEL::TypeInfo( m_curModelType ).deviceType;
m_deviceTypeChoice->SetSelection( static_cast<int>( deviceType ) );
m_typeChoice->Clear();
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
if( &curModel() != m_prevModel )
{
if( SIM_MODEL::TypeInfo( type ).deviceType == deviceType )
SIM_MODEL::DEVICE_TYPE deviceType = SIM_MODEL::TypeInfo( curModel().GetType() ).deviceType;
m_deviceTypeChoice->SetSelection( static_cast<int>( deviceType ) );
m_typeChoice->Clear();
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
wxString description = SIM_MODEL::TypeInfo( type ).description;
if( SIM_MODEL::TypeInfo( type ).deviceType == deviceType )
{
wxString description = SIM_MODEL::TypeInfo( type ).description;
if( !description.IsEmpty() )
m_typeChoice->Append( description );
if( !description.IsEmpty() )
m_typeChoice->Append( description );
if( type == m_curModelType )
m_typeChoice->SetSelection( m_typeChoice->GetCount() - 1 );
if( type == curModel().GetType() )
m_typeChoice->SetSelection( m_typeChoice->GetCount() - 1 );
}
}
// This wxPropertyGridManager column and header stuff has to be here because it segfaults in
// the constructor.
m_paramGridMgr->SetColumnCount( static_cast<int>( PARAM_COLUMN::END_ ) );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::UNIT ), "Unit" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::DEFAULT ), "Default" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::TYPE ), "Type" );
m_paramGridMgr->ShowHeader();
m_paramGrid->Clear();
m_firstCategory = m_paramGrid->Append( new wxPropertyCategory( "DC" ) );
m_paramGrid->HideProperty( "DC" );
m_paramGrid->Append( new wxPropertyCategory( "Temperature" ) );
m_paramGrid->HideProperty( "Temperature" );
m_paramGrid->Append( new wxPropertyCategory( "Noise" ) );
m_paramGrid->HideProperty( "Noise" );
m_paramGrid->Append( new wxPropertyCategory( "Distributed Quantities" ) );
m_paramGrid->HideProperty( "Distributed Quantities" );
m_paramGrid->Append( new wxPropertyCategory( "Geometry" ) );
m_paramGrid->HideProperty( "Geometry" );
m_paramGrid->Append( new wxPropertyCategory( "Limiting Values" ) );
m_paramGrid->HideProperty( "Limiting Values" );
m_paramGrid->Append( new wxPropertyCategory( "Advanced" ) );
m_paramGrid->HideProperty( "Advanced" );
m_paramGrid->Append( new wxPropertyCategory( "Flags" ) );
m_paramGrid->HideProperty( "Flags" );
for( int i = 0; i < curModel().GetParamCount(); ++i )
addParamPropertyIfRelevant( i );
m_paramGrid->CollapseAll();
}
// Either enable all properties or disable all except the principal ones.
for( wxPropertyGridIterator it = m_paramGrid->GetIterator(); !it.AtEnd(); ++it )
{
SIM_PROPERTY* prop = dynamic_cast<SIM_PROPERTY*>( *it );
// This wxPropertyGridManager stuff has to be here because it segfaults in the constructor.
if( !prop ) // Not all properties are SIM_PROPERTY yet. TODO.
continue;
m_paramGridMgr->SetColumnCount( static_cast<int>( PARAM_COLUMN::END_ ) );
// Model values other than the currently edited value may have changed. Update them.
// This feature is called "autofill" and present only in certain models. Don't do it for
// models that don't have it for performance reasons.
if( curModel().HasAutofill() )
prop->SetValueFromString( prop->GetParam().value->ToString() );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::UNIT ), "Unit" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::DEFAULT ), "Default" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::TYPE ), "Type" );
m_paramGridMgr->ShowHeader();
m_paramGrid->Clear();
m_firstCategory = m_paramGrid->Append( new wxPropertyCategory( "DC" ) );
m_paramGrid->HideProperty( "DC" );
m_paramGrid->Append( new wxPropertyCategory( "Temperature" ) );
m_paramGrid->HideProperty( "Temperature" );
m_paramGrid->Append( new wxPropertyCategory( "Noise" ) );
m_paramGrid->HideProperty( "Noise" );
m_paramGrid->Append( new wxPropertyCategory( "Distributed Quantities" ) );
m_paramGrid->HideProperty( "Distributed Quantities" );
m_paramGrid->Append( new wxPropertyCategory( "Geometry" ) );
m_paramGrid->HideProperty( "Geometry" );
m_paramGrid->Append( new wxPropertyCategory( "Limiting Values" ) );
m_paramGrid->HideProperty( "Limiting Values" );
m_paramGrid->Append( new wxPropertyCategory( "Advanced" ) );
m_paramGrid->HideProperty( "Advanced" );
m_paramGrid->Append( new wxPropertyCategory( "Flags" ) );
m_paramGrid->HideProperty( "Flags" );
for( const SIM_MODEL::PARAM& param : getCurModel().Params() )
addParamPropertyIfRelevant( param );
m_paramGrid->CollapseAll();
// Most of the values are disabled when the override checkbox is unchecked.
prop->Enable( m_useInstanceModelRadioButton->GetValue()
|| prop->GetParam().info.category == CATEGORY::PRINCIPAL
|| m_overrideCheckbox->GetValue() );
}
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::updateModelCodeTab()
{
wxString modelName = m_modelNameCombobox->GetStringSelection();
if( m_useInstanceModelRadioButton->GetValue() || modelName.IsEmpty() )
modelName = m_fields.at( REFERENCE_FIELD ).GetText();
m_codePreview->SetText( curModel().GenerateSpicePreview( modelName ) );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::updatePinAssignmentsTab()
{
m_pinAssignmentsGrid->ClearRows();
if( &curModel() == m_prevModel )
return;
m_pinAssignmentsGrid->ClearRows();
std::vector<SCH_PIN*> pinList = m_symbol.GetAllPins();
m_pinAssignmentsGrid->AppendRows( static_cast<int>( pinList.size() ) );
@ -254,9 +309,9 @@ void DIALOG_SPICE_MODEL<T>::updatePinAssignmentsTab()
"Not Connected" );
}
for( unsigned int i = 0; i < getCurModel().Pins().size(); ++i )
for( int i = 0; i < curModel().GetPinCount(); ++i )
{
int symbolPinNumber = getCurModel().Pins().at( i ).symbolPinNumber;
int symbolPinNumber = curModel().GetPin( i ).symbolPinNumber;
if( symbolPinNumber == SIM_MODEL::PIN::NOT_CONNECTED )
continue;
@ -282,9 +337,9 @@ void DIALOG_SPICE_MODEL<T>::updatePinAssignmentsGridEditors()
wxString modelPinChoicesString = "";
bool isFirst = true;
for( unsigned int i = 0; i < getCurModel().Pins().size(); ++i )
for( int i = 0; i < curModel().GetPinCount(); ++i )
{
const SIM_MODEL::PIN& modelPin = getCurModel().Pins().at( i );
const SIM_MODEL::PIN& modelPin = curModel().GetPin( i );
int modelPinNumber = static_cast<int>( i + 1 );
if( modelPin.symbolPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
@ -329,62 +384,78 @@ void DIALOG_SPICE_MODEL<T>::updatePinAssignmentsGridEditors()
template <typename T>
void DIALOG_SPICE_MODEL<T>::addParamPropertyIfRelevant( const SIM_MODEL::PARAM& aParam )
void DIALOG_SPICE_MODEL<T>::loadLibrary( const wxString& aFilePath )
{
if( aParam.info.dir == SIM_MODEL::PARAM::DIR::OUT )
m_library->ReadFile( aFilePath );
m_libraryFilenameInput->SetValue( aFilePath );
m_libraryModels.clear();
for( const SIM_MODEL& baseModel : m_library->GetModels() )
m_libraryModels.push_back( SIM_MODEL::Create( baseModel ) );
m_modelNameCombobox->Clear();
for( const wxString& name : m_library->GetModelNames() )
m_modelNameCombobox->Append( name );
m_useLibraryModelRadioButton->SetValue( true );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::addParamPropertyIfRelevant( int aParamIndex )
{
if( curModel().GetParam( aParamIndex ).info.dir == SIM_MODEL::PARAM::DIR::OUT )
return;
switch( aParam.info.category )
switch( curModel().GetParam( aParamIndex ).info.category )
{
case CATEGORY::DC:
m_paramGrid->HideProperty( "DC", false );
m_paramGrid->AppendIn( "DC", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "DC", newParamProperty( aParamIndex ) );
break;
case CATEGORY::CAPACITANCE:
m_paramGrid->HideProperty( "Capacitance", false );
m_paramGrid->AppendIn( "Capacitance", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Capacitance", newParamProperty( aParamIndex ) );
break;
case CATEGORY::TEMPERATURE:
m_paramGrid->HideProperty( "Temperature", false );
m_paramGrid->AppendIn( "Temperature", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Temperature", newParamProperty( aParamIndex ) );
break;
case CATEGORY::NOISE:
m_paramGrid->HideProperty( "Noise", false );
m_paramGrid->AppendIn( "Noise", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Noise", newParamProperty( aParamIndex ) );
break;
case CATEGORY::DISTRIBUTED_QUANTITIES:
m_paramGrid->HideProperty( "Distributed Quantities", false );
m_paramGrid->AppendIn( "Distributed Quantities", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Distributed Quantities", newParamProperty( aParamIndex ) );
break;
case CATEGORY::GEOMETRY:
m_paramGrid->HideProperty( "Geometry", false );
m_paramGrid->AppendIn( "Geometry", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Geometry", newParamProperty( aParamIndex ) );
break;
case CATEGORY::LIMITING_VALUES:
m_paramGrid->HideProperty( "Limiting Values", false );
m_paramGrid->AppendIn( "Limiting Values", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Limiting Values", newParamProperty( aParamIndex ) );
break;
case CATEGORY::ADVANCED:
m_paramGrid->HideProperty( "Advanced", false );
m_paramGrid->AppendIn( "Advanced", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Advanced", newParamProperty( aParamIndex ) );
break;
case CATEGORY::FLAGS:
m_paramGrid->HideProperty( "Flags", false );
m_paramGrid->AppendIn( "Flags", newParamProperty( aParam ) );
m_paramGrid->AppendIn( "Flags", newParamProperty( aParamIndex ) );
break;
default:
//m_paramGrid->AppendIn( nullptr, newParamProperty( aParam ) );
m_paramGrid->Insert( m_firstCategory, newParamProperty( aParam ) );
//m_paramGrid->Append( newParamProperty( aParam ) );
m_paramGrid->Insert( m_firstCategory, newParamProperty( aParamIndex ) );
break;
case CATEGORY::INITIAL_CONDITIONS:
@ -394,46 +465,47 @@ void DIALOG_SPICE_MODEL<T>::addParamPropertyIfRelevant( const SIM_MODEL::PARAM&
}
template <typename T>
wxPGProperty* DIALOG_SPICE_MODEL<T>::newParamProperty( const SIM_MODEL::PARAM& aParam ) const
wxPGProperty* DIALOG_SPICE_MODEL<T>::newParamProperty( int aParamIndex ) const
{
const SIM_MODEL::PARAM& param = curModel().GetParam( aParamIndex );
wxString paramDescription = wxString::Format( "%s (%s)",
aParam.info.description,
aParam.info.name );
param.info.description,
param.info.name );
wxPGProperty* prop = nullptr;
switch( aParam.info.type )
switch( param.info.type )
{
case TYPE::INT:
prop = new SIM_PROPERTY( paramDescription,aParam.info.name, *aParam.value,
SIM_VALUE_BASE::TYPE::INT );
prop = new SIM_PROPERTY( paramDescription, param.info.name, m_library, curModelSharedPtr(),
aParamIndex, SIM_VALUE_BASE::TYPE::INT );
break;
case TYPE::FLOAT:
prop = new SIM_PROPERTY( paramDescription,aParam.info.name, *aParam.value,
SIM_VALUE_BASE::TYPE::FLOAT );
prop = new SIM_PROPERTY( paramDescription, param.info.name, m_library, curModelSharedPtr(),
aParamIndex, SIM_VALUE_BASE::TYPE::FLOAT );
break;
case TYPE::BOOL:
prop = new wxBoolProperty( paramDescription, aParam.info.name );
prop = new wxBoolProperty( paramDescription, param.info.name );
prop->SetAttribute( wxPG_BOOL_USE_CHECKBOX, true );
break;
default:
prop = new wxStringProperty( paramDescription, aParam.info.name );
prop = new wxStringProperty( paramDescription, param.info.name );
break;
}
prop->SetAttribute( wxPG_ATTR_UNITS, aParam.info.unit );
prop->SetAttribute( wxPG_ATTR_UNITS, param.info.unit );
// Legacy due to the way we extracted the parameters from Ngspice.
if( aParam.isOtherVariant )
prop->SetCell( 3, aParam.info.defaultValueOfOtherVariant );
if( param.isOtherVariant )
prop->SetCell( 3, param.info.defaultValueOfOtherVariant );
else
prop->SetCell( 3, aParam.info.defaultValue );
prop->SetCell( 3, param.info.defaultValue );
wxString typeStr;
switch( aParam.info.type )
switch( param.info.type )
{
case TYPE::BOOL: typeStr = wxString( "Bool" ); break;
case TYPE::INT: typeStr = wxString( "Int" ); break;
@ -448,14 +520,34 @@ wxPGProperty* DIALOG_SPICE_MODEL<T>::newParamProperty( const SIM_MODEL::PARAM& a
prop->SetCell( static_cast<int>( PARAM_COLUMN::TYPE ), typeStr );
if( m_useLibraryModelRadioButton->GetValue()
&& !m_overrideCheckbox->GetValue()
&& param.info.category != SIM_MODEL::PARAM::CATEGORY::PRINCIPAL )
{
prop->Enable( false );
}
return prop;
}
template <typename T>
SIM_MODEL& DIALOG_SPICE_MODEL<T>::getCurModel() const
SIM_MODEL& DIALOG_SPICE_MODEL<T>::curModel() const
{
return *m_models.at( static_cast<int>( m_curModelType ) );
return *curModelSharedPtr();
}
template <typename T>
std::shared_ptr<SIM_MODEL> DIALOG_SPICE_MODEL<T>::curModelSharedPtr() const
{
if( m_useLibraryModelRadioButton->GetValue()
&& m_modelNameCombobox->GetSelection() != wxNOT_FOUND )
{
return m_libraryModels.at( m_modelNameCombobox->GetSelection() );
}
else
return m_models.at( static_cast<int>( m_curModelType ) );
}
@ -480,7 +572,7 @@ wxString DIALOG_SPICE_MODEL<T>::getSymbolPinString( int symbolPinNumber ) const
template <typename T>
wxString DIALOG_SPICE_MODEL<T>::getModelPinString( int modelPinNumber ) const
{
const wxString& pinName = getCurModel().Pins().at( modelPinNumber - 1 ).name;
const wxString& pinName = curModel().GetPin( modelPinNumber - 1 ).name;
LOCALE_IO toggle;
@ -509,6 +601,39 @@ int DIALOG_SPICE_MODEL<T>::getModelPinNumber( const wxString& aModelPinString )
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onRadioButton( wxCommandEvent& aEvent )
{
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onBrowseButtonClick( wxCommandEvent& aEvent )
{
wxFileDialog dlg( this, _( "Browse Models" ) );
if( dlg.ShowModal() == wxID_CANCEL )
return;
loadLibrary( dlg.GetPath() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onModelNameCombobox( wxCommandEvent& aEvent )
{
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onOverrideCheckbox( wxCommandEvent& aEvent )
{
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onDeviceTypeChoice( wxCommandEvent& aEvent )
{
@ -543,6 +668,13 @@ void DIALOG_SPICE_MODEL<T>::onTypeChoice( wxCommandEvent& aEvent )
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onParamGridChanged( wxPropertyGridEvent& aEvent )
{
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onPinAssignmentsGridCellChange( wxGridEvent& aEvent )
{
@ -552,11 +684,10 @@ void DIALOG_SPICE_MODEL<T>::onPinAssignmentsGridCellChange( wxGridEvent& aEvent
m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() ) );
if( oldModelPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
getCurModel().Pins().at( oldModelPinNumber - 1 ).symbolPinNumber =
SIM_MODEL::PIN::NOT_CONNECTED;
curModel().SetPinSymbolPinNumber( oldModelPinNumber - 1, SIM_MODEL::PIN::NOT_CONNECTED );
if( modelPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
getCurModel().Pins().at( modelPinNumber - 1 ).symbolPinNumber = symbolPinNumber;
curModel().SetPinSymbolPinNumber( modelPinNumber - 1, symbolPinNumber );
updatePinAssignmentsGridEditors();
@ -577,6 +708,48 @@ void DIALOG_SPICE_MODEL<T>::onPinAssignmentsGridSize( wxSizeEvent& aEvent )
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onLibraryFilenameInputUpdate( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_useLibraryModelRadioButton->GetValue() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onBrowseButtonUpdate( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_useLibraryModelRadioButton->GetValue() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onModelNameComboboxUpdate( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_useLibraryModelRadioButton->GetValue() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onOverrideCheckboxUpdate( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_useLibraryModelRadioButton->GetValue() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onDeviceTypeChoiceUpdate( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_useInstanceModelRadioButton->GetValue() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onTypeChoiceUpdate( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( m_useInstanceModelRadioButton->GetValue() );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onSelectionChange( wxPropertyGridEvent& aEvent )
{

View File

@ -30,6 +30,7 @@
#include <scintilla_tricks.h>
#include <sim/sim_model.h>
#include <sim/sim_library.h>
#include <sch_symbol.h>
// Some probable wxWidgets bugs encountered when writing this class:
@ -41,44 +42,68 @@ template <typename T>
class DIALOG_SPICE_MODEL : public DIALOG_SPICE_MODEL_BASE
{
public:
static constexpr auto LIBRARY_FIELD = "Model_Library";
static constexpr auto NAME_FIELD = "Model_Name";
enum class PARAM_COLUMN : int { DESCRIPTION, VALUE, UNIT, DEFAULT, TYPE, END_ };
enum class PIN_COLUMN : int { SYMBOL, MODEL };
DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol, std::vector<T>& aSchFields );
private:
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
void updateWidgets();
void updateModelParamsTab();
void updateModelCodeTab();
void updatePinAssignmentsTab();
void updatePinAssignmentsGridEditors();
void addParamPropertyIfRelevant( const SIM_MODEL::PARAM& aParam );
wxPGProperty* newParamProperty( const SIM_MODEL::PARAM& aParam ) const;
SIM_MODEL& getCurModel() const;
void loadLibrary( const wxString& aFilePath );
void addParamPropertyIfRelevant( int aParamIndex );
wxPGProperty* newParamProperty( int aParamIndex ) const;
SIM_MODEL& curModel() const;
std::shared_ptr<SIM_MODEL> curModelSharedPtr() const;
wxString getSymbolPinString( int aSymbolPinNumber ) const;
wxString getModelPinString( int aModelPinNumber ) const;
int getModelPinNumber( const wxString& aModelPinString ) const;
void onRadioButton( wxCommandEvent& aEvent ) override;
void onBrowseButtonClick( wxCommandEvent& aEvent ) override;
void onModelNameCombobox( wxCommandEvent& aEvent ) override;
void onOverrideCheckbox( wxCommandEvent& aEvent ) override;
void onDeviceTypeChoice( wxCommandEvent& aEvent ) override;
void onTypeChoice( wxCommandEvent& aEvent ) override;
void onParamGridChanged( wxPropertyGridEvent& aEvent ) override;
void onPinAssignmentsGridCellChange( wxGridEvent& aEvent ) override;
void onPinAssignmentsGridSize( wxSizeEvent& aEvent ) override;
void onLibraryFilenameInputUpdate( wxUpdateUIEvent& aEvent ) override;
void onBrowseButtonUpdate( wxUpdateUIEvent& aEvent ) override;
void onModelNameComboboxUpdate( wxUpdateUIEvent& aEvent ) override;
void onOverrideCheckboxUpdate( wxUpdateUIEvent& aEvent ) override;
void onDeviceTypeChoiceUpdate( wxUpdateUIEvent& aEvent ) override;
void onTypeChoiceUpdate( wxUpdateUIEvent& aEvent ) override;
virtual void onSelectionChange( wxPropertyGridEvent& aEvent );
//void onPropertyChanged( wxPropertyGridEvent& aEvent ) override;
SCH_SYMBOL& m_symbol;
std::vector<T>& m_fields;
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
std::vector<std::shared_ptr<SIM_MODEL>> m_models;
std::map<SIM_MODEL::DEVICE_TYPE, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType;
SIM_MODEL::TYPE m_curModelType = SIM_MODEL::TYPE::NONE;
std::shared_ptr<SIM_LIBRARY> m_library;
std::vector<std::shared_ptr<SIM_MODEL>> m_libraryModels;
const SIM_MODEL* m_prevModel;
wxPGProperty* m_firstCategory; // Used to add principal parameters to root (any better ideas?)
std::unique_ptr<SCINTILLA_TRICKS> m_scintillaTricks;
};

View File

@ -24,31 +24,38 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
bSizer9 = new wxBoxSizer( wxVERTICAL );
wxStaticBoxSizer* sbSizer4;
sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_modelPanel, wxID_ANY, wxT("Properties") ), wxVERTICAL );
sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_modelPanel, wxID_ANY, wxT("Source") ), wxVERTICAL );
wxFlexGridSizer* fgSizer15;
fgSizer15 = new wxFlexGridSizer( 0, 3, 0, 0 );
fgSizer15->AddGrowableCol( 1 );
fgSizer15 = new wxFlexGridSizer( 0, 4, 0, 0 );
fgSizer15->AddGrowableCol( 2 );
fgSizer15->SetFlexibleDirection( wxBOTH );
fgSizer15->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText122 = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Model Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText122->Wrap( -1 );
fgSizer15->Add( m_staticText122, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_useInstanceModelRadioButton = new wxRadioButton( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Instance"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
fgSizer15->Add( m_useInstanceModelRadioButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_modelName = new wxTextCtrl( sbSizer4->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer15->Add( m_modelName, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
m_useLibraryModelRadioButton = new wxRadioButton( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Library:"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer15->Add( m_useLibraryModelRadioButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_browseButton = new wxButton( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Browse..."), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer15->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_libraryFilenameInput = new wxTextCtrl( sbSizer4->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer15->Add( m_libraryFilenameInput, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
m_staticText124 = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Location:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText124->Wrap( -1 );
fgSizer15->Add( m_staticText124, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_browseButton = new wxBitmapButton( sbSizer4->GetStaticBox(), wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
fgSizer15->Add( m_browseButton, 0, wxALL, 5 );
m_staticText125 = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, wxT("etc/kicad-sim/diodes.lib"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText125->Wrap( -1 );
fgSizer15->Add( m_staticText125, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
fgSizer15->Add( 0, 0, 1, wxEXPAND, 5 );
m_modelNameLabel = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Model:"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT );
m_modelNameLabel->Wrap( -1 );
fgSizer15->Add( m_modelNameLabel, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
m_modelNameCombobox = new wxComboBox( sbSizer4->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
fgSizer15->Add( m_modelNameCombobox, 0, wxALL|wxEXPAND, 5 );
m_overrideCheckbox = new wxCheckBox( sbSizer4->GetStaticBox(), wxID_ANY, wxT("Override"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer15->Add( m_overrideCheckbox, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
sbSizer4->Add( fgSizer15, 1, wxEXPAND, 5 );
@ -59,9 +66,6 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
wxStaticBoxSizer* sbSizer5;
sbSizer5 = new wxStaticBoxSizer( new wxStaticBox( m_modelPanel, wxID_ANY, wxT("Model") ), wxVERTICAL );
m_checkBox2 = new wxCheckBox( sbSizer5->GetStaticBox(), wxID_ANY, wxT("Change parameters for this symbol"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer5->Add( m_checkBox2, 0, wxALL, 5 );
m_notebook4 = new wxNotebook( sbSizer5->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_parametersPanel = new wxPanel( m_notebook4, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer12;
@ -226,9 +230,20 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
this->Centre( wxBOTH );
// Connect Events
m_useInstanceModelRadioButton->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onRadioButton ), NULL, this );
m_useLibraryModelRadioButton->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onRadioButton ), NULL, this );
m_libraryFilenameInput->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onLibraryFilenameInputUpdate ), NULL, this );
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onBrowseButtonClick ), NULL, this );
m_browseButton->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
m_modelNameCombobox->Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onModelNameCombobox ), NULL, this );
m_modelNameCombobox->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onModelNameComboboxUpdate ), NULL, this );
m_overrideCheckbox->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onOverrideCheckbox ), NULL, this );
m_overrideCheckbox->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onOverrideCheckboxUpdate ), NULL, this );
m_deviceTypeChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onDeviceTypeChoice ), NULL, this );
m_deviceTypeChoice->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onDeviceTypeChoiceUpdate ), NULL, this );
m_typeChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onTypeChoice ), NULL, this );
m_paramGridMgr->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPropertyChanged ), NULL, this );
m_typeChoice->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onTypeChoiceUpdate ), NULL, this );
m_paramGridMgr->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DIALOG_SPICE_MODEL_BASE::onParamGridChanged ), NULL, this );
m_pinAssignmentsGrid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridCellChange ), NULL, this );
m_pinAssignmentsGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridSize ), NULL, this );
}
@ -236,9 +251,20 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
DIALOG_SPICE_MODEL_BASE::~DIALOG_SPICE_MODEL_BASE()
{
// Disconnect Events
m_useInstanceModelRadioButton->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onRadioButton ), NULL, this );
m_useLibraryModelRadioButton->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onRadioButton ), NULL, this );
m_libraryFilenameInput->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onLibraryFilenameInputUpdate ), NULL, this );
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onBrowseButtonClick ), NULL, this );
m_browseButton->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
m_modelNameCombobox->Disconnect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onModelNameCombobox ), NULL, this );
m_modelNameCombobox->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onModelNameComboboxUpdate ), NULL, this );
m_overrideCheckbox->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onOverrideCheckbox ), NULL, this );
m_overrideCheckbox->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onOverrideCheckboxUpdate ), NULL, this );
m_deviceTypeChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onDeviceTypeChoice ), NULL, this );
m_deviceTypeChoice->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onDeviceTypeChoiceUpdate ), NULL, this );
m_typeChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onTypeChoice ), NULL, this );
m_paramGridMgr->Disconnect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPropertyChanged ), NULL, this );
m_typeChoice->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SPICE_MODEL_BASE::onTypeChoiceUpdate ), NULL, this );
m_paramGridMgr->Disconnect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DIALOG_SPICE_MODEL_BASE::onParamGridChanged ), NULL, this );
m_pinAssignmentsGrid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridCellChange ), NULL, this );
m_pinAssignmentsGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridSize ), NULL, this );

View File

@ -184,7 +184,7 @@
<property name="proportion">0</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">Properties</property>
<property name="label">Source</property>
<property name="minimum_size"></property>
<property name="name">sbSizer4</property>
<property name="orient">wxVERTICAL</property>
@ -195,9 +195,9 @@
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">3</property>
<property name="cols">4</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property>
<property name="growablecols">2</property>
<property name="growablerows"></property>
<property name="hgap">0</property>
<property name="minimum_size"></property>
@ -206,11 +206,11 @@
<property name="permission">none</property>
<property name="rows">0</property>
<property name="vgap">0</property>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<object class="wxRadioButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -238,8 +238,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Model Name:</property>
<property name="markup">0</property>
<property name="label">Instance</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
@ -247,7 +246,72 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticText122</property>
<property name="name">m_useInstanceModelRadioButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxRB_GROUP</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnRadioButton">onRadioButton</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="proportion">0</property>
<object class="wxRadioButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Library:</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_useLibraryModelRadioButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -261,10 +325,15 @@
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnRadioButton">onRadioButton</event>
</object>
</object>
<object class="sizeritem" expanded="0">
@ -307,7 +376,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_modelName</property>
<property name="name">m_libraryFilenameInput</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -329,13 +398,14 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnUpdateUI">onLibraryFilenameInputUpdate</event>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="0">
<object class="wxBitmapButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -369,7 +439,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Browse...</property>
<property name="label">MyButton</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
@ -402,11 +472,23 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">onBrowseButtonClick</event>
<event name="OnUpdateUI">onBrowseButtonUpdate</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
@ -436,7 +518,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Location:</property>
<property name="label">Model:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
@ -445,7 +527,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticText124</property>
<property name="name">m_modelNameLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -455,7 +537,7 @@
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="style">wxALIGN_RIGHT</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
@ -465,11 +547,11 @@
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<object class="wxComboBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -483,6 +565,7 @@
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices"></property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
@ -497,8 +580,6 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">etc/kicad-sim/diodes.lib</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
@ -506,7 +587,75 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticText125</property>
<property name="name">m_modelNameCombobox</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnCombobox">onModelNameCombobox</event>
<event name="OnUpdateUI">onModelNameComboboxUpdate</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Override</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_overrideCheckbox</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -520,10 +669,15 @@
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnCheckBox">onOverrideCheckbox</event>
<event name="OnUpdateUI">onOverrideCheckboxUpdate</event>
</object>
</object>
</object>
@ -542,70 +696,6 @@
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Change parameters for this symbol</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_checkBox2</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND | wxALL</property>
@ -863,6 +953,7 @@
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChoice">onDeviceTypeChoice</event>
<event name="OnUpdateUI">onDeviceTypeChoiceUpdate</event>
</object>
</object>
<object class="sizeritem" expanded="1">
@ -989,6 +1080,7 @@
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChoice">onTypeChoice</event>
<event name="OnUpdateUI">onTypeChoiceUpdate</event>
</object>
</object>
</object>
@ -1051,7 +1143,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnPropertyGridChanged">onPropertyChanged</event>
<event name="OnPropertyGridChanged">onParamGridChanged</event>
<object class="propGridPage" expanded="1">
<property name="bitmap"></property>
<property name="label">Page</property>

View File

@ -12,19 +12,22 @@
class WX_GRID;
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/radiobut.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/combobox.h>
#include <wx/checkbox.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/manager.h>
@ -49,12 +52,13 @@ class DIALOG_SPICE_MODEL_BASE : public wxDialog
protected:
wxNotebook* m_notebook;
wxPanel* m_modelPanel;
wxStaticText* m_staticText122;
wxTextCtrl* m_modelName;
wxButton* m_browseButton;
wxStaticText* m_staticText124;
wxStaticText* m_staticText125;
wxCheckBox* m_checkBox2;
wxRadioButton* m_useInstanceModelRadioButton;
wxRadioButton* m_useLibraryModelRadioButton;
wxTextCtrl* m_libraryFilenameInput;
wxBitmapButton* m_browseButton;
wxStaticText* m_modelNameLabel;
wxComboBox* m_modelNameCombobox;
wxCheckBox* m_overrideCheckbox;
wxNotebook* m_notebook4;
wxPanel* m_parametersPanel;
wxStaticText* m_staticText127;
@ -74,9 +78,19 @@ class DIALOG_SPICE_MODEL_BASE : public wxDialog
wxButton* m_sdbSizer1Cancel;
// Virtual event handlers, override them in your derived class
virtual void onRadioButton( wxCommandEvent& event ) { event.Skip(); }
virtual void onLibraryFilenameInputUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onBrowseButtonClick( wxCommandEvent& event ) { event.Skip(); }
virtual void onBrowseButtonUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onModelNameCombobox( wxCommandEvent& event ) { event.Skip(); }
virtual void onModelNameComboboxUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onOverrideCheckbox( wxCommandEvent& event ) { event.Skip(); }
virtual void onOverrideCheckboxUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onDeviceTypeChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onDeviceTypeChoiceUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onTypeChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onPropertyChanged( wxPropertyGridEvent& event ) { event.Skip(); }
virtual void onTypeChoiceUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onParamGridChanged( wxPropertyGridEvent& event ) { event.Skip(); }
virtual void onPinAssignmentsGridCellChange( wxGridEvent& event ) { event.Skip(); }
virtual void onPinAssignmentsGridSize( wxSizeEvent& event ) { event.Skip(); }

View File

@ -148,6 +148,7 @@ LIB_SYMBOL::LIB_SYMBOL( const LIB_SYMBOL& aSymbol, SYMBOL_LIB* aLibrary ) :
catch( ... )
{
wxFAIL_MSG( "Failed to clone LIB_ITEM." );
return;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <sim/sim_library.h>
bool SIM_LIBRARY::ReadFile( const wxString& aFilename )
{
m_filename = aFilename;
return true;
}
std::vector<std::reference_wrapper<SIM_MODEL>> SIM_LIBRARY::GetModels()
{
std::vector<std::reference_wrapper<SIM_MODEL>> ret;
for( const std::unique_ptr<SIM_MODEL>& model : m_models )
ret.emplace_back( *model );
return ret;
}

View File

@ -0,0 +1,56 @@
/*
* 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.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef SIM_LIBRARY_H
#define SIM_LIBRARY_H
#include <sim/sim_model.h>
class SIM_LIBRARY
{
public:
virtual ~SIM_LIBRARY() = default;
SIM_LIBRARY() = default;
virtual bool ReadFile( const wxString& aFilename ) = 0;
virtual void WriteFile( const wxString& aFilename ) = 0;
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels();
const std::vector<wxString>& GetModelNames() { return m_modelNames; }
wxString GetFilename() const { return m_filename; }
wxString GetErrorMessage() const { return m_errorMessage; }
protected:
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
std::vector<wxString> m_modelNames;
wxString m_filename;
wxString m_errorMessage;
};
#endif // SIM_LIBRARY_H

View File

@ -0,0 +1,111 @@
/*
* 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.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <sim/sim_library_spice.h>
#include <sim/spice_grammar.h>
#include <locale_io.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
namespace SIM_LIBRARY_SPICE_PARSER
{
using namespace SPICE_GRAMMAR;
struct unknownLine : until<newline> {};
struct library : star<sor<spiceUnit,
unknownLine>> {};
struct libraryGrammar : must<library, eof> {};
template <typename Rule> struct librarySelector : std::false_type {};
template <> struct librarySelector<modelUnit> : std::true_type {};
template <> struct librarySelector<modelName> : std::true_type {};
// For debugging.
template <> struct librarySelector<unknownLine> : std::true_type {};
};
bool SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilename )
{
if( !SIM_LIBRARY::ReadFile( aFilename ) )
return false;
LOCALE_IO toggle;
tao::pegtl::file_input in( aFilename.ToStdString() );
std::unique_ptr<tao::pegtl::parse_tree::node> root;
try
{
root = tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
SIM_LIBRARY_SPICE_PARSER::librarySelector>
( in );
}
catch( tao::pegtl::parse_error& e )
{
m_errorMessage = wxString::Format( "Parsing failed: %s", e.what() );
return false;
}
wxASSERT( root );
for( const auto& node : root->children )
{
if( node->is_type<SIM_LIBRARY_SPICE_PARSER::modelUnit>() )
{
m_models.push_back( SIM_MODEL::Create( node->string() ) );
if( node->children.size() != 1 )
{
m_errorMessage = wxString::Format(
"Captured %d name tokens, expected one", node->children.size() );
return false;
}
m_modelNames.emplace_back( node->children.at( 0 )->string() );
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::unknownLine>() )
{
// Do nothing.
}
else
{
m_errorMessage = wxString::Format( "Unhandled parse tree node: '%s'", node->string() );
return false;
}
}
return true;
}
void SIM_LIBRARY_SPICE::WriteFile( const wxString& aFileName )
{
}

View File

@ -0,0 +1,40 @@
/*
* 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.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef SIM_LIBRARY_SPICE_H
#define SIM_LIBRARY_SPICE_H
#include <sim/sim_library.h>
class SIM_LIBRARY_SPICE : public SIM_LIBRARY
{
// We'll make SIM_LIBRARY have no subclasses probably.
public:
bool ReadFile( const wxString& aFilename ) override;
void WriteFile( const wxString& aFilename ) override;
};
#endif // SIM_LIBRARY_SPICE_H

File diff suppressed because it is too large Load Diff

View File

@ -25,22 +25,46 @@
#ifndef SIM_MODEL_H
#define SIM_MODEL_H
#include <sim/spice_grammar.h>
#include <enum_vector.h>
#include <sch_field.h>
#include <lib_field.h>
#include <sim/sim_value.h>
#include <wx/string.h>
#include <map>
#include <stdexcept>
class SIM_LIBRARY;
namespace SIM_MODEL_GRAMMAR
{
using namespace SPICE_GRAMMAR;
struct pinNumber : sor<digits, one<'X'>> {};
struct pinSequence : seq<opt<pinNumber,
star<sep,
pinNumber>>> {};
struct pinSequenceGrammar : must<opt<sep>,
pinSequence,
opt<sep>,
eof> {};
template <NOTATION Notation>
struct paramValuePairsGrammar : must<opt<sep>,
paramValuePairs<Notation>,
opt<sep>,
eof> {};
}
class SIM_MODEL
{
public:
static constexpr auto DEVICE_TYPE_FIELD = "Model_Device";
static constexpr auto TYPE_FIELD = "Model_Type";
static constexpr auto FILE_FIELD = "Model_File";
static constexpr auto PIN_SEQUENCE_FIELD = "Model_Pin_Sequence";
static constexpr auto PINS_FIELD = "Model_Pins";
static constexpr auto PARAMS_FIELD = "Model_Params";
@ -238,6 +262,17 @@ public:
};
struct SPICE_INFO
{
wxString itemType;
wxString typeString = "";
wxString inlineTypeString = "";
int level = 0;
bool hasExpression = false;
wxString version = "";
};
struct PIN
{
static constexpr auto NOT_CONNECTED = 0;
@ -278,41 +313,52 @@ public:
{
wxString name;
unsigned int id = 0; // Legacy.
DIR dir;
DIR dir = DIR::INOUT;
SIM_VALUE_BASE::TYPE type;
FLAGS flags = {}; // Legacy
wxString unit;
CATEGORY category;
wxString unit = "";
CATEGORY category = CATEGORY::PRINCIPAL;
wxString defaultValue = "";
wxString defaultValueOfOtherVariant = ""; // Legacy.
wxString description;
wxString description = "";
};
std::unique_ptr<SIM_VALUE_BASE> value;
const INFO& info;
bool isOtherVariant = false; // Legacy.
PARAM( const INFO& aInfo ) :
value( SIM_VALUE_BASE::Create( aInfo.type ) ),
info( aInfo )
PARAM( const INFO& aInfo, bool aIsOtherVariant = false )
: value( SIM_VALUE_BASE::Create( aInfo.type ) ),
info( aInfo ),
isOtherVariant( aIsOtherVariant )
{}
};
static DEVICE_INFO DeviceTypeInfo( DEVICE_TYPE aDeviceType );
static INFO TypeInfo( TYPE aType );
static SPICE_INFO SpiceInfo( TYPE aType );
static TYPE ReadTypeFromSpiceCode( const std::string& aSpiceCode );
template <typename T>
static TYPE ReadTypeFromFields( const std::vector<T>& aFields );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( int symbolPinCount, const std::vector<T>& aFields );
static std::unique_ptr<SIM_MODEL> Create( TYPE aType, int aSymbolPinCount = 0 );
static std::unique_ptr<SIM_MODEL> Create( const std::string& aSpiceCode );
static std::unique_ptr<SIM_MODEL> Create( const SIM_MODEL& aBaseModel );
template <typename T = void>
static std::unique_ptr<SIM_MODEL> Create( TYPE aType,
int symbolPinCount,
const std::vector<T>* aFields = nullptr );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( int aSymbolPinCount, const std::vector<T>& aFields );
template <typename T>
static wxString GetFieldValue( const std::vector<T>* aFields, const wxString& aFieldName );
template <typename T>
static void SetFieldValue( std::vector<T>& aFields, const wxString& aFieldName,
const wxString& aValue );
// Move semantics.
@ -321,17 +367,17 @@ public:
SIM_MODEL() = delete;
SIM_MODEL( const SIM_MODEL& aOther ) = delete;
SIM_MODEL( SIM_MODEL&& aOther ) = default;
SIM_MODEL& operator=(SIM_MODEL&& aOther ) = default;
SIM_MODEL& operator=(SIM_MODEL&& aOther ) = delete;
SIM_MODEL( TYPE aType );
virtual bool ReadSpiceCode( const std::string& aSpiceCode );
template <typename T>
void ReadDataFields( int symbolPinCount, const std::vector<T>* aFields );
void ReadDataFields( int aSymbolPinCount, const std::vector<T>* aFields );
// C++ doesn't allow virtual template methods, so we do this:
virtual void ReadDataSchFields( int symbolPinCount, const std::vector<SCH_FIELD>* aFields );
virtual void ReadDataLibFields( int symbolPinCount, const std::vector<LIB_FIELD>* aFields );
virtual void ReadDataSchFields( int aSymbolPinCount, const std::vector<SCH_FIELD>* aFields );
virtual void ReadDataLibFields( int aSymbolPinCount, const std::vector<LIB_FIELD>* aFields );
template <typename T>
@ -341,46 +387,83 @@ public:
virtual void WriteDataSchFields( std::vector<SCH_FIELD>& aFields );
virtual void WriteDataLibFields( std::vector<LIB_FIELD>& aFields );
virtual void WriteCode( wxString& aCode ) = 0;
virtual wxString GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const;
virtual wxString GenerateSpiceModelLine( const wxString& aModelName ) const;
virtual SPICE_INFO GetSpiceInfo() const;
wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName ) const;
virtual wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const;
virtual wxString GenerateSpicePreview( const wxString& aModelName ) const;
TYPE GetType() { return m_type; }
void AddParam( const PARAM::INFO& aInfo, bool aIsOtherVariant = false );
virtual wxString GetFile() { return m_file; }
virtual void SetFile( const wxString& aFile ) { m_file = aFile; }
TYPE GetType() const { return m_type; }
std::vector<PIN>& Pins() { return m_pins; }
std::vector<PARAM>& Params() { return m_params; }
const SIM_MODEL* GetBaseModel() const { return m_baseModel; }
void SetBaseModel( const SIM_MODEL& aBaseModel ) { m_baseModel = &aBaseModel; }
int GetPinCount() const { return static_cast<int>( m_pins.size() ); }
const PIN& GetPin( int aIndex ) const { return m_pins.at( aIndex ); }
void SetPinSymbolPinNumber( int aIndex, int aSymbolPinNumber )
{
m_pins.at( aIndex ).symbolPinNumber = aSymbolPinNumber;
}
int GetParamCount() const { return static_cast<int>( m_params.size() ); }
const PARAM& GetParam( int aParamIndex ) const; // Return base parameter unless it's overridden.
const PARAM& GetUnderlyingParam( int aParamIndex ) const; // Return the actual parameter.
const PARAM& GetBaseParam( int aParamIndex ) const; // Always return base parameter if it exists.
virtual bool SetParamValue( int aParamIndex, const wxString& aValue );
bool HasOverrides() const;
bool HasNonPrincipalOverrides() const;
// Can modifying a model parameter also modify other parameters?
virtual bool HasAutofill() const { return false; }
protected:
SIM_MODEL( TYPE aType );
private:
TYPE m_type;
wxString m_file;
static std::unique_ptr<SIM_MODEL> create( TYPE aType );
static TYPE readTypeFromSpiceTypeString( const std::string& aTypeString );
wxString m_spiceCode;
const SIM_MODEL* m_baseModel;
const TYPE m_type;
std::vector<PIN> m_pins;
std::vector<PARAM> m_params;
template <typename T>
void doReadDataFields( int symbolPinCount, const std::vector<T>* aFields );
void doReadDataFields( int aSymbolPinCount, const std::vector<T>* aFields );
template <typename T>
void doWriteFields( std::vector<T>& aFields );
template <typename T>
static wxString getFieldValue( const std::vector<T>* aFields, const wxString& aFieldName );
virtual std::vector<wxString> getPinNames() const { return {}; }
template <typename T>
static void setFieldValue( std::vector<T>& aFields, const wxString& aFieldName,
const wxString& aValue );
wxString generateDeviceTypeField() const;
wxString generateTypeField() const;
virtual std::vector<wxString> getPinNames() { return {}; }
wxString generatePinsField() const;
void parsePinsField( int aSymbolPinCount, const wxString& aPinsField );
wxString generatePinSequence();
void parsePinSequence( int symbolPinCount, const wxString& aPinSequence );
wxString generateParamsField( const wxString& aPairSeparator ) const;
void parseParamsField( const wxString& aParamsField );
virtual wxString generateParamValuePairs();
virtual void parseParamValuePairs( const wxString& aParamValuePairs );
virtual bool setParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue );
};
#endif // SIM_MODEL_H

View File

@ -23,18 +23,10 @@
*/
#include <sim/sim_model_behavioral.h>
#include <locale_io.h>
template SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType )
: SIM_MODEL( aType )
{
static PARAM::INFO resistor = makeParamInfo( "r", "Expression for resistance", "ohm" );
@ -45,22 +37,62 @@ SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
switch( aType )
{
case TYPE::RESISTOR_BEHAVIORAL: Params().emplace_back( resistor ); break;
case TYPE::CAPACITOR_BEHAVIORAL: Params().emplace_back( capacitor ); break;
case TYPE::INDUCTOR_BEHAVIORAL: Params().emplace_back( inductor ); break;
case TYPE::VSOURCE_BEHAVIORAL: Params().emplace_back( vsource ); break;
case TYPE::ISOURCE_BEHAVIORAL: Params().emplace_back( isource ); break;
case TYPE::RESISTOR_BEHAVIORAL: AddParam( resistor ); break;
case TYPE::CAPACITOR_BEHAVIORAL: AddParam( capacitor ); break;
case TYPE::INDUCTOR_BEHAVIORAL: AddParam( inductor ); break;
case TYPE::VSOURCE_BEHAVIORAL: AddParam( vsource ); break;
case TYPE::ISOURCE_BEHAVIORAL: AddParam( isource ); break;
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_IDEAL" );
}
ReadDataFields( symbolPinCount, aFields );
}
void SIM_MODEL_BEHAVIORAL::WriteCode( wxString& aCode )
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const
{
// TODO
return "";
}
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const
{
LOCALE_IO toggle;
switch( GetType() )
{
case TYPE::RESISTOR_BEHAVIORAL:
case TYPE::CAPACITOR_BEHAVIORAL:
case TYPE::INDUCTOR_BEHAVIORAL:
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
GetParam( 0 ).value->ToString(),
aPinNetNames );
case TYPE::VSOURCE_BEHAVIORAL:
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
wxString::Format( "V=%s", GetParam( 0 ).value->ToString() ), aPinNetNames );
case TYPE::ISOURCE_BEHAVIORAL:
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
wxString::Format( "I=%s", GetParam( 0 ).value->ToString() ), aPinNetNames );
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_BEHAVIORAL" );
return "";
}
}
std::vector<wxString> SIM_MODEL_BEHAVIORAL::getPinNames() const
{
return { "+", "-" };
}

View File

@ -31,12 +31,17 @@
class SIM_MODEL_BEHAVIORAL : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
SIM_MODEL_BEHAVIORAL( TYPE aType );
void WriteCode( wxString& aCode ) override;
wxString GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const override;
private:
std::vector<wxString> getPinNames() const override;
static PARAM::INFO makeParamInfo( wxString name, wxString description, wxString unit );
};

View File

@ -25,22 +25,7 @@
#include <sim/sim_model_codemodel.h>
template SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType )
: SIM_MODEL( aType )
{
}
void SIM_MODEL_CODEMODEL::WriteCode( wxString& aCode )
{
// TODO
}

View File

@ -31,10 +31,7 @@
class SIM_MODEL_CODEMODEL : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
SIM_MODEL_CODEMODEL( TYPE aType );
};
#endif // SIM_MODEL_CODEMODEL_H

View File

@ -27,16 +27,7 @@
using PARAM = SIM_MODEL::PARAM;
template SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType )
: SIM_MODEL( aType )
{
static PARAM::INFO resistor = makeParamInfo( "r", "Resistance", "ohm" );
@ -45,24 +36,37 @@ SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
switch( aType )
{
case TYPE::RESISTOR_IDEAL: Params().emplace_back( resistor ); break;
case TYPE::CAPACITOR_IDEAL: Params().emplace_back( capacitor ); break;
case TYPE::INDUCTOR_IDEAL: Params().emplace_back( inductor ); break;
case TYPE::RESISTOR_IDEAL: AddParam( resistor ); break;
case TYPE::CAPACITOR_IDEAL: AddParam( capacitor ); break;
case TYPE::INDUCTOR_IDEAL: AddParam( inductor ); break;
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_IDEAL" );
}
ReadDataFields( symbolPinCount, aFields );
}
void SIM_MODEL_IDEAL::WriteCode( wxString& aCode )
wxString SIM_MODEL_IDEAL::GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const
{
// TODO
return "";
}
std::vector<wxString> SIM_MODEL_IDEAL::getPinNames()
wxString SIM_MODEL_IDEAL::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_IDEAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const
{
return SIM_MODEL::GenerateSpiceItemLine( aRefName, GetParam( 0 ).value->ToString(),
aPinNetNames );
}
std::vector<wxString> SIM_MODEL_IDEAL::getPinNames() const
{
return { "+", "-" };
}

View File

@ -31,13 +31,16 @@
class SIM_MODEL_IDEAL : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
SIM_MODEL_IDEAL( TYPE aType );
void WriteCode( wxString& aCode ) override;
wxString GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const override;
private:
std::vector<wxString> getPinNames() override;
std::vector<wxString> getPinNames() const override;
static PARAM::INFO makeParamInfo( wxString aName, wxString aDescription, wxString aUnit );
};

View File

@ -27,49 +27,26 @@
using TYPE = SIM_MODEL::TYPE;
template SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType )
: SIM_MODEL( aType )
{
const NGSPICE::MODEL_INFO& modelInfo = NGSPICE::ModelInfo( getModelType() );
for( const SIM_MODEL::PARAM::INFO& paramInfo : modelInfo.modelParams )
{
Params().emplace_back( paramInfo );
Params().back().isOtherVariant = getIsOtherVariant();
}
AddParam( paramInfo, getIsOtherVariant() );
for( const SIM_MODEL::PARAM::INFO& paramInfo : modelInfo.instanceParams )
{
Params().emplace_back( paramInfo );
Params().back().isOtherVariant = getIsOtherVariant();
}
ReadDataFields( symbolPinCount, aFields );
AddParam( paramInfo, getIsOtherVariant() );
}
void SIM_MODEL_NGSPICE::WriteCode( wxString& aCode )
{
// TODO
}
std::vector<wxString> SIM_MODEL_NGSPICE::getPinNames()
std::vector<wxString> SIM_MODEL_NGSPICE::getPinNames() const
{
return NGSPICE::ModelInfo( getModelType() ).pinNames;
}
NGSPICE::MODEL_TYPE SIM_MODEL_NGSPICE::getModelType()
NGSPICE::MODEL_TYPE SIM_MODEL_NGSPICE::getModelType() const
{
switch( GetType() )
{

View File

@ -32,15 +32,12 @@
class SIM_MODEL_NGSPICE : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
SIM_MODEL_NGSPICE( TYPE aType );
private:
std::vector<wxString> getPinNames() override;
std::vector<wxString> getPinNames() const override;
NGSPICE::MODEL_TYPE getModelType();
NGSPICE::MODEL_TYPE getModelType() const;
bool getIsOtherVariant();
};

View File

@ -23,25 +23,49 @@
*/
#include <sim/sim_model_rawspice.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
template SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType )
: SIM_MODEL( aType )
{
ReadDataFields( symbolPinCount, aFields );
}
void SIM_MODEL_RAWSPICE::WriteCode( wxString& aCode )
bool SIM_MODEL_RAWSPICE::setParamFromSpiceCode( const wxString& aParamName,
const wxString& aParamValue )
{
// TODO
int i = 0;
for(; i < GetParamCount(); ++i )
{
if( GetParam( i ).info.name == aParamName.Lower() )
break;
}
if( i == GetParamCount() )
{
// No parameter with this name found. Create a new one.
std::unique_ptr<PARAM::INFO> paramInfo = std::make_unique<PARAM::INFO>();
paramInfo->name = aParamName.Lower();
paramInfo->type = SIM_VALUE_BASE::TYPE::STRING;
m_paramInfos.push_back( std::move( paramInfo ) );
AddParam( *m_paramInfos.back() );
}
try
{
GetParam( i ).value->FromString( wxString( aParamValue ) );
}
catch( KI_PARAM_ERROR& e )
{
// Shouldn't happen since it's TYPE::STRING.
return false;
}
return true;
}

View File

@ -31,10 +31,14 @@
class SIM_MODEL_RAWSPICE : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
SIM_MODEL_RAWSPICE( TYPE aType );
void WriteCode( wxString& aCode ) override;
//bool ReadSpiceCode( const std::string& aSpiceCode ) override;
private:
bool setParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue ) override;
std::vector<std::unique_ptr<PARAM::INFO>> m_paramInfos;
};
#endif // SIM_MODEL_RAWSPICE_H

View File

@ -27,21 +27,38 @@
using PARAM = SIM_MODEL::PARAM;
template SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields )
SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType )
: SIM_MODEL( aType )
{
for( const PARAM::INFO& paramInfo : makeParams( aType ) )
Params().emplace_back( paramInfo );
AddParam( paramInfo );
}
ReadDataFields( symbolPinCount, aFields );
wxString SIM_MODEL_SOURCE::GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const
{
return "";
}
wxString SIM_MODEL_SOURCE::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const
{
wxString argList = "";
for( int i = 0; i < GetParamCount(); ++i )
argList << GetParam( i ).value->ToString() << " ";
wxString model = wxString::Format( GetSpiceInfo().inlineTypeString + "( %s)", argList );
return SIM_MODEL::GenerateSpiceItemLine( aRefName, model, aPinNetNames );
}
@ -122,9 +139,31 @@ const std::vector<PARAM::INFO>& SIM_MODEL_SOURCE::makeParams( TYPE aType )
}
void SIM_MODEL_SOURCE::WriteCode( wxString& aCode )
bool SIM_MODEL_SOURCE::SetParamValue( int aParamIndex, const wxString& aValue )
{
// TODO
// Sources are special. All preceding parameter values must be filled. If they are not, fill
// them out automatically. If a value is nulled, delete everything after it.
if( aValue.IsEmpty() )
{
for( int i = aParamIndex; i < GetParamCount(); ++i )
SIM_MODEL::SetParamValue( i, "" );
}
else
{
for( int i = 0; i < aParamIndex; ++i )
{
if( GetParam( i ).value->ToString().IsEmpty() )
SIM_MODEL::SetParamValue( i, "0" );
}
}
return SIM_MODEL::SetParamValue( aParamIndex, aValue );
}
std::vector<wxString> SIM_MODEL_SOURCE::getPinNames() const
{
return { "+", "-" };
}

View File

@ -31,12 +31,21 @@
class SIM_MODEL_SOURCE : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
SIM_MODEL_SOURCE( TYPE aType );
void WriteCode( wxString& aCode ) override;
wxString GenerateSpiceIncludeLine( const wxString& aLibraryFilename ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const override;
bool SetParamValue( int aParamIndex, const wxString& aValue ) override;
bool HasAutofill() const override { return true; }
private:
std::vector<wxString> getPinNames() const override;
static const std::vector<PARAM::INFO>& makeParams( TYPE aType );
static std::vector<PARAM::INFO> makePulse( wxString aPrefix, wxString aUnit );

View File

@ -25,23 +25,7 @@
#include <sim/sim_model_subcircuit.h>
template SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType )
: SIM_MODEL( aType )
{
ReadDataFields( symbolPinCount, aFields );
}
void SIM_MODEL_SUBCIRCUIT::WriteCode( wxString& aCode )
{
// TODO
}

View File

@ -31,10 +31,7 @@
class SIM_MODEL_SUBCIRCUIT : public SIM_MODEL
{
public:
template <typename T = void>
SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
SIM_MODEL_SUBCIRCUIT( TYPE aType );
};
#endif // SIM_MODEL_SUBCIRCUIT_H

View File

@ -38,7 +38,7 @@ wxEND_EVENT_TABLE()
SIM_VALIDATOR::SIM_VALIDATOR( SIM_VALUE_BASE::TYPE aValueType,
SIM_VALUE_PARSER::NOTATION aNotation )
SIM_VALUE_GRAMMAR::NOTATION aNotation )
: wxValidator(),
m_valueType( aValueType ),
m_notation( aNotation )
@ -85,7 +85,7 @@ bool SIM_VALIDATOR::TransferFromWindow()
bool SIM_VALIDATOR::isValid( const wxString& aString )
{
return SIM_VALUE_PARSER::IsValid( aString, m_valueType, m_notation );
return SIM_VALUE_GRAMMAR::IsValid( aString, m_valueType, m_notation );
}
@ -151,14 +151,19 @@ void SIM_VALIDATOR::onMouse( wxMouseEvent& aEvent )
SIM_PROPERTY::SIM_PROPERTY( const wxString& aLabel, const wxString& aName,
SIM_VALUE_BASE& aValue,
std::shared_ptr<SIM_LIBRARY> aLibrary,
std::shared_ptr<SIM_MODEL> aModel,
int aParamIndex,
SIM_VALUE_BASE::TYPE aValueType,
SIM_VALUE_PARSER::NOTATION aNotation )
: wxStringProperty( aLabel, aName, aValue.ToString() ),
SIM_VALUE_GRAMMAR::NOTATION aNotation )
: wxStringProperty( aLabel, aName ),
m_valueType( aValueType ),
m_notation( aNotation ),
m_value( aValue )
m_library( aLibrary ),
m_model( aModel ),
m_paramIndex( aParamIndex )
{
SetValueFromString( GetParam().value->ToString() );
}
@ -172,7 +177,19 @@ bool SIM_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aText, in
{
try
{
m_value.FromString( aText );
wxString paramValueStr = m_model->GetBaseParam( m_paramIndex ).value->ToString();
// TODO: Don't use string comparison.
if( m_model->GetBaseModel() && ( aText.IsEmpty() || aText == paramValueStr ) )
{
m_model->SetParamValue( m_paramIndex, "" ); // Nullify.
aVariant = paramValueStr; // Use the inherited value (if it exists) if null.
}
else
{
m_model->SetParamValue( m_paramIndex, aText );
aVariant = GetParam().value->ToString();
}
}
catch( KI_PARAM_ERROR& e )
{
@ -180,6 +197,5 @@ bool SIM_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aText, in
return false;
}
aVariant = m_value.ToString();
return true;
}

View File

@ -25,14 +25,14 @@
#ifndef SIM_PROPERTY_H
#define SIM_PROPERTY_H
#include <sim/sim_value.h>
#include <sim/sim_model.h>
#include <wx/propgrid/props.h>
class SIM_VALIDATOR : public wxValidator
{
public:
SIM_VALIDATOR( SIM_VALUE_BASE::TYPE aValueType, SIM_VALUE_PARSER::NOTATION aNotation );
SIM_VALIDATOR( SIM_VALUE_BASE::TYPE aValueType, SIM_VALUE_GRAMMAR::NOTATION aNotation );
SIM_VALIDATOR( const SIM_VALIDATOR& aValidator ) = default;
wxObject* Clone() const override;
@ -51,7 +51,7 @@ private:
void onMouse( wxMouseEvent& aEvent );
SIM_VALUE_BASE::TYPE m_valueType;
SIM_VALUE_PARSER::NOTATION m_notation;
SIM_VALUE_GRAMMAR::NOTATION m_notation;
wxString m_prevText;
long m_prevInsertionPoint;
@ -62,19 +62,28 @@ private:
class SIM_PROPERTY : public wxStringProperty
{
public:
SIM_PROPERTY( const wxString& aLabel, const wxString& aName, SIM_VALUE_BASE& aValue,
// We pass shared_ptrs because we need to make sure they are destroyed only after the last time
// SIM_PROPERTY uses them.
SIM_PROPERTY( const wxString& aLabel, const wxString& aName,
std::shared_ptr<SIM_LIBRARY> aLibrary,
std::shared_ptr<SIM_MODEL> aModel,
int aParamIndex,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
SIM_VALUE_PARSER::NOTATION aNotation = SIM_VALUE_PARSER::NOTATION::SI );
SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI );
wxValidator* DoGetValidator() const override;
bool StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 )
const override;
const SIM_MODEL::PARAM& GetParam() const { return m_model->GetParam( m_paramIndex ); }
protected:
SIM_VALUE_BASE::TYPE m_valueType;
SIM_VALUE_PARSER::NOTATION m_notation;
SIM_VALUE_BASE& m_value;
SIM_VALUE_BASE::TYPE m_valueType;
SIM_VALUE_GRAMMAR::NOTATION m_notation;
std::shared_ptr<SIM_LIBRARY> m_library;
std::shared_ptr<SIM_MODEL> m_model;
int m_paramIndex;
};
#endif // SIM_PROPERTY_H

View File

@ -71,13 +71,56 @@
}
namespace SIM_VALUE_PARSER
{
using namespace SIM_VALUE_GRAMMAR;
template <typename Rule>
struct numberSelector : std::false_type {};
template <> struct numberSelector<SIM_VALUE_GRAMMAR::significand<SIM_VALUE_BASE::TYPE::INT>>
: std::true_type {};
template <> struct numberSelector<SIM_VALUE_GRAMMAR::significand<SIM_VALUE_BASE::TYPE::FLOAT>>
: std::true_type {};
template <> struct numberSelector<intPart> : std::true_type {};
template <> struct numberSelector<fracPart> : std::true_type {};
template <> struct numberSelector<exponent> : std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SI>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SPICE>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SI>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SPICE>>
: std::true_type {};
struct PARSE_RESULT
{
bool isEmpty = true;
std::string significand;
OPT<long> intPart;
OPT<long> fracPart;
OPT<long> exponent;
OPT<long> metricSuffixExponent;
};
PARSE_RESULT Parse( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
NOTATION aNotation = NOTATION::SI );
long MetricSuffixToExponent( std::string aMetricSuffix, NOTATION aNotation = NOTATION::SI );
wxString ExponentToMetricSuffix( double aExponent, long& aReductionExponent,
NOTATION aNotation = NOTATION::SI );
}
template <SIM_VALUE_BASE::TYPE ValueType, SIM_VALUE_PARSER::NOTATION Notation>
static inline void doIsValid( tao::pegtl::string_input<>& aIn )
{
tao::pegtl::parse<SIM_VALUE_PARSER::numberGrammar<ValueType, Notation>>( aIn );
}
bool SIM_VALUE_PARSER::IsValid( const wxString& aString,
bool SIM_VALUE_GRAMMAR::IsValid( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType,
NOTATION aNotation )
{
@ -163,7 +206,9 @@ SIM_VALUE_PARSER::PARSE_RESULT SIM_VALUE_PARSER::Parse( const wxString& aString,
try
{
for( const auto& node : root->children )
{
CALL_INSTANCE( aValueType, aNotation, handleNodeForParse, *node, result );
}
}
catch( std::invalid_argument& e )
{
@ -482,14 +527,19 @@ wxString SIM_VALUE<long>::ToString() const
if( m_value.has_value() )
{
double exponent = std::log10( *m_value );
long reductionExponent = 0;
long value = *m_value;
long exponent = 0;
wxString metricSuffix = SIM_VALUE_PARSER::ExponentToMetricSuffix( exponent,
reductionExponent );
long reducedValue = *m_value / static_cast<long>( std::pow( 10, reductionExponent ) );
while( value % 1000 == 0 )
{
exponent += 3;
value /= 1000;
}
return wxString::Format( "%d%s", reducedValue, metricSuffix );
long dummy = 0;
wxString metricSuffix = SIM_VALUE_PARSER::ExponentToMetricSuffix(
static_cast<double>( exponent ), dummy );
return wxString::Format( "%d%s", value, metricSuffix );
}
return "";

View File

@ -86,7 +86,7 @@ private:
};
namespace SIM_VALUE_PARSER
namespace SIM_VALUE_GRAMMAR
{
using namespace tao::pegtl;
@ -100,7 +100,6 @@ namespace SIM_VALUE_PARSER
wxString allowedIntChars;
struct spaces : plus<space> {};
struct digits : plus<tao::pegtl::digit> {}; // For some reason it fails on just "digit".
struct sign : one<'+', '-'> {};
@ -165,43 +164,9 @@ namespace SIM_VALUE_PARSER
struct numberGrammar : must<opt<number<ValueType, Notation>>, eof> {};
template <typename Rule>
struct numberSelector : std::false_type {};
template <> struct numberSelector<significand<SIM_VALUE_BASE::TYPE::INT>> : std::true_type {};
template <> struct numberSelector<significand<SIM_VALUE_BASE::TYPE::FLOAT>> : std::true_type {};
template <> struct numberSelector<intPart> : std::true_type {};
template <> struct numberSelector<fracPart> : std::true_type {};
template <> struct numberSelector<exponent> : std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SI>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SPICE>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SI>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SPICE>>
: std::true_type {};
struct PARSE_RESULT
{
bool isEmpty = true;
std::string significand;
OPT<long> intPart;
OPT<long> fracPart;
OPT<long> exponent;
OPT<long> metricSuffixExponent;
};
bool IsValid( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
NOTATION aNotation = NOTATION::SI );
PARSE_RESULT Parse( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
NOTATION aNotation = NOTATION::SI );
long MetricSuffixToExponent( std::string aMetricSuffix, NOTATION aNotation = NOTATION::SI );
wxString ExponentToMetricSuffix( double aExponent, long& aReductionExponent,
NOTATION aNotation = NOTATION::SI );
}
#endif // SIM_VALUE_H

View File

@ -0,0 +1,156 @@
/*
* 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.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef SPICE_GRAMMAR_H
#define SPICE_GRAMMAR_H
#include <sim/sim_value.h>
namespace SPICE_GRAMMAR
{
using namespace SIM_VALUE_GRAMMAR;
struct eolComment : seq<one<';'>, until<eol>> {};
struct commentLine : seq<one<'*', ';'>, until<eol>> {};
struct linespaces : plus<not_at<eol>,
space> {};
struct newline : seq<sor<eol,
eolComment>,
not_at<one<'+'>>> {};
struct continuation : seq<opt<linespaces>,
sor<eol,
eolComment>,
star<commentLine>,
one<'+'>,
opt<linespaces>> {};
struct sep : sor<continuation,
linespaces> {};
struct param : plus<alnum> {};
template <SIM_VALUE_BASE::TYPE Type, NOTATION Notation>
struct paramValuePair : seq<param,
opt<sep>,
one<'='>,
opt<sep>,
number<Type, Notation>> {};
template <NOTATION Notation>
struct paramValuePairs : seq<opt<paramValuePair<SIM_VALUE_BASE::TYPE::FLOAT,
Notation>,
star<sep,
paramValuePair<SIM_VALUE_BASE::TYPE::FLOAT,
Notation>>>> {};
struct modelName : plus<alnum,
star<sor<alnum,
one<'!', '#', '$', '%', '[', ']', '_'>>>> {};
/*seq<alpha,
star<sor<alnum,
one<'!', '#', '$', '%', '[', ']', '_'>>>> {};*/
struct dotModelType : sor<TAO_PEGTL_ISTRING( "R" ),
TAO_PEGTL_ISTRING( "C" ),
TAO_PEGTL_ISTRING( "L" ),
TAO_PEGTL_ISTRING( "SW" ),
TAO_PEGTL_ISTRING( "CSW" ),
TAO_PEGTL_ISTRING( "URC" ),
TAO_PEGTL_ISTRING( "LTRA" ),
TAO_PEGTL_ISTRING( "D" ),
TAO_PEGTL_ISTRING( "NPN" ),
TAO_PEGTL_ISTRING( "PNP" ),
TAO_PEGTL_ISTRING( "NJF" ),
TAO_PEGTL_ISTRING( "PJF" ),
TAO_PEGTL_ISTRING( "NMOS" ),
TAO_PEGTL_ISTRING( "PMOS" ),
TAO_PEGTL_ISTRING( "NMF" ),
TAO_PEGTL_ISTRING( "PMF" ),
TAO_PEGTL_ISTRING( "VDMOS" )> {};
struct dotModel : seq<opt<sep>,
TAO_PEGTL_ISTRING( ".model" ),
sep,
modelName,
sep,
dotModelType,
sor<seq<opt<sep>,
one<'('>,
opt<sep>,
paramValuePairs<NOTATION::SPICE>,
opt<sep>,
// Ngspice doesn't require the parentheses to match, though.
one<')'>>,
seq<sep,
paramValuePairs<NOTATION::SPICE>>>,
opt<sep>,
newline> {};
struct dotSubcktPinNumber : digits {};
struct dotSubcktPinSequence : seq<opt<sep>,
opt<dotSubcktPinNumber,
star<sep,
dotSubcktPinNumber>>,
opt<sep>> {};
struct dotSubcktEnd : seq<TAO_PEGTL_ISTRING( ".ends" ),
opt<sep>,
newline> {};
struct dotSubckt : seq<opt<sep>,
TAO_PEGTL_ISTRING( ".subckt" ),
sep,
modelName,
sep,
dotSubcktPinSequence,
opt<sep>,
newline,
until<dotSubcktEnd>> {};
struct modelUnit : sor<dotModel,
dotSubckt> {};
struct dotLine : seq<opt<sep>,
one<'.'>,
until<newline>> {};
struct unknownLine : until<newline> {};
struct spiceUnit : sor<modelUnit,
dotLine,
unknownLine> {};
struct spiceUnitGrammar : must<spiceUnit, eof> {};
}
#endif // SPICE_GRAMMAR_H