Support env variables in spice library paths.
Also removes a bunch of std::string stuff from the file handling in the simulator. All our file handling, env variable expansion, project path, etc. stuff is wxString based, and jumping through std::string in between just makes it more complex and increases the potential bug surface. Also fixes a bug where you'd get two error messages when a spice model library wasn't found. Also fixes a bug where you'd get a spice model library not found error when the text field was empty. Also fixes a bug where we'd try to absolutize a path starting with an unresolved text or environment variable. If the path starts with a variable it's probably absolute, and tacking on the project path in the error message just obfuscates things. Fixes https://gitlab.com/kicad/code/kicad/issues/13082
This commit is contained in:
parent
5aa204e194
commit
b15913bd53
|
@ -264,7 +264,7 @@ wxString KIwxExpandEnvVars( const wxString& str, const PROJECT* aProject )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const wxString ExpandEnvVarSubstitutions( const wxString& aString, PROJECT* aProject )
|
const wxString ExpandEnvVarSubstitutions( const wxString& aString, const PROJECT* aProject )
|
||||||
{
|
{
|
||||||
// wxGetenv( wchar_t* ) is not re-entrant on linux.
|
// wxGetenv( wchar_t* ) is not re-entrant on linux.
|
||||||
// Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
|
// Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
|
||||||
|
|
|
@ -306,6 +306,11 @@ const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const
|
||||||
{
|
{
|
||||||
wxFileName fn = aFileName;
|
wxFileName fn = aFileName;
|
||||||
|
|
||||||
|
// Paths which start with an unresolved variable reference are more likely to be
|
||||||
|
// absolute than relative.
|
||||||
|
if( aFileName.StartsWith( wxT( "${" ) ) )
|
||||||
|
return aFileName;
|
||||||
|
|
||||||
if( !fn.IsAbsolute() )
|
if( !fn.IsAbsolute() )
|
||||||
{
|
{
|
||||||
wxString pro_dir = wxPathOnly( GetProjectFullName() );
|
wxString pro_dir = wxPathOnly( GetProjectFullName() );
|
||||||
|
|
|
@ -55,7 +55,8 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
|
||||||
m_scintillaTricks( nullptr ),
|
m_scintillaTricks( nullptr ),
|
||||||
m_wasCodePreviewUpdated( true ),
|
m_wasCodePreviewUpdated( true ),
|
||||||
m_firstCategory( nullptr ),
|
m_firstCategory( nullptr ),
|
||||||
m_prevParamGridSelection( nullptr )
|
m_prevParamGridSelection( nullptr ),
|
||||||
|
m_inKillFocus( false )
|
||||||
{
|
{
|
||||||
m_modelNameCombobox->SetValidator( m_modelNameValidator );
|
m_modelNameCombobox->SetValidator( m_modelNameValidator );
|
||||||
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
|
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
|
||||||
|
@ -262,7 +263,7 @@ bool DIALOG_SIM_MODEL<T>::TransferDataFromWindow()
|
||||||
|
|
||||||
if( ( library() && m_useLibraryModelRadioButton->GetValue() ) || isIbisLoaded() )
|
if( ( library() && m_useLibraryModelRadioButton->GetValue() ) || isIbisLoaded() )
|
||||||
{
|
{
|
||||||
path = library()->GetFilePath();
|
path = m_libraryPathText->GetValue();
|
||||||
wxFileName fn( path );
|
wxFileName fn( path );
|
||||||
|
|
||||||
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
|
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
|
||||||
|
@ -618,23 +619,16 @@ void DIALOG_SIM_MODEL<T>::loadLibrary( const wxString& aLibraryPath, bool aForce
|
||||||
if( !aForceReload && libraries.size() >= 1 && libraries.begin()->first == aLibraryPath )
|
if( !aForceReload && libraries.size() >= 1 && libraries.begin()->first == aLibraryPath )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
DIALOG_IBIS_PARSER_REPORTER dlg( this );
|
DIALOG_IBIS_PARSER_REPORTER dlg( this );
|
||||||
dlg.m_messagePanel->Clear();
|
dlg.m_messagePanel->Clear();
|
||||||
|
|
||||||
bool tryingToLoadIbis = false;
|
|
||||||
|
|
||||||
if( aLibraryPath.EndsWith( ".ibs" ) )
|
|
||||||
tryingToLoadIbis = true;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_libraryModelsMgr.SetLibrary( std::string( aLibraryPath.ToUTF8() ),
|
m_libraryModelsMgr.CreateLibrary( aLibraryPath, &dlg.m_messagePanel->Reporter() );
|
||||||
&dlg.m_messagePanel->Reporter() );
|
|
||||||
}
|
}
|
||||||
catch( const IO_ERROR& e )
|
catch( const IO_ERROR& e )
|
||||||
{
|
{
|
||||||
if( tryingToLoadIbis )
|
if( dlg.m_messagePanel->Reporter().HasMessage() )
|
||||||
{
|
{
|
||||||
dlg.m_messagePanel->Flush();
|
dlg.m_messagePanel->Flush();
|
||||||
dlg.ShowQuasiModal();
|
dlg.ShowQuasiModal();
|
||||||
|
@ -976,29 +970,47 @@ void DIALOG_SIM_MODEL<T>::onLibraryPathTextEnter( wxCommandEvent& aEvent )
|
||||||
if( m_useLibraryModelRadioButton->GetValue() )
|
if( m_useLibraryModelRadioButton->GetValue() )
|
||||||
{
|
{
|
||||||
wxString path = m_libraryPathText->GetValue();
|
wxString path = m_libraryPathText->GetValue();
|
||||||
wxFileName fn( path );
|
|
||||||
|
|
||||||
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
|
if( !path.IsEmpty() )
|
||||||
path = fn.GetFullPath();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
loadLibrary( path );
|
try
|
||||||
updateWidgets();
|
{
|
||||||
}
|
loadLibrary( path );
|
||||||
catch( const IO_ERROR& )
|
updateWidgets();
|
||||||
{
|
}
|
||||||
// TODO: Add an infobar to report the error?
|
catch( const IO_ERROR& )
|
||||||
|
{
|
||||||
|
// TODO: Add an infobar to report the error?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void DIALOG_SIM_MODEL<T>::onLibraryPathText( wxCommandEvent& aEvent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void DIALOG_SIM_MODEL<T>::onLibraryPathTextSetFocus( wxFocusEvent& aEvent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void DIALOG_SIM_MODEL<T>::onLibraryPathTextKillFocus( wxFocusEvent& aEvent )
|
void DIALOG_SIM_MODEL<T>::onLibraryPathTextKillFocus( wxFocusEvent& aEvent )
|
||||||
{
|
{
|
||||||
wxCommandEvent dummy;
|
if( !m_inKillFocus )
|
||||||
onLibraryPathTextEnter( dummy );
|
{
|
||||||
|
m_inKillFocus = true;
|
||||||
|
|
||||||
|
wxCommandEvent dummy;
|
||||||
|
onLibraryPathTextEnter( dummy );
|
||||||
|
|
||||||
|
m_inKillFocus = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -114,8 +114,10 @@ private:
|
||||||
int getModelPinIndex( const wxString& aModelPinString ) const;
|
int getModelPinIndex( const wxString& aModelPinString ) const;
|
||||||
|
|
||||||
void onRadioButton( wxCommandEvent& aEvent ) override;
|
void onRadioButton( wxCommandEvent& aEvent ) override;
|
||||||
|
void onLibraryPathText( wxCommandEvent& aEvent ) override;
|
||||||
void onLibraryPathTextEnter( wxCommandEvent& aEvent ) override;
|
void onLibraryPathTextEnter( wxCommandEvent& aEvent ) override;
|
||||||
void onLibraryPathTextKillFocus( wxFocusEvent& aEvent ) override;
|
void onLibraryPathTextKillFocus( wxFocusEvent& aEvent ) override;
|
||||||
|
void onLibraryPathTextSetFocus( wxFocusEvent& aEvent ) override;
|
||||||
void onBrowseButtonClick( wxCommandEvent& aEvent ) override;
|
void onBrowseButtonClick( wxCommandEvent& aEvent ) override;
|
||||||
void onModelNameCombobox( wxCommandEvent& aEvent ) override;
|
void onModelNameCombobox( wxCommandEvent& aEvent ) override;
|
||||||
void onModelNameComboboxKillFocus( wxFocusEvent& event ) override;
|
void onModelNameComboboxKillFocus( wxFocusEvent& event ) override;
|
||||||
|
@ -157,6 +159,8 @@ private:
|
||||||
|
|
||||||
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
|
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
|
||||||
wxPGProperty* m_prevParamGridSelection;
|
wxPGProperty* m_prevParamGridSelection;
|
||||||
|
|
||||||
|
bool m_inKillFocus;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DIALOG_SIM_MODEL_H */
|
#endif /* DIALOG_SIM_MODEL_H */
|
||||||
|
|
|
@ -281,8 +281,9 @@ DIALOG_SIM_MODEL_BASE::DIALOG_SIM_MODEL_BASE( wxWindow* parent, wxWindowID id, c
|
||||||
m_useLibraryModelRadioButton->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onRadioButton ), NULL, this );
|
m_useLibraryModelRadioButton->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onRadioButton ), NULL, this );
|
||||||
m_pathLabel->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathLabelUpdate ), NULL, this );
|
m_pathLabel->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathLabelUpdate ), NULL, this );
|
||||||
m_libraryPathText->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextKillFocus ), NULL, this );
|
m_libraryPathText->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextKillFocus ), NULL, this );
|
||||||
|
m_libraryPathText->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextSetFocus ), NULL, this );
|
||||||
|
m_libraryPathText->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathText ), NULL, this );
|
||||||
m_libraryPathText->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextEnter ), NULL, this );
|
m_libraryPathText->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextEnter ), NULL, this );
|
||||||
m_libraryPathText->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathUpdate ), NULL, this );
|
|
||||||
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonClick ), NULL, this );
|
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonClick ), NULL, this );
|
||||||
m_browseButton->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
|
m_browseButton->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
|
||||||
m_modelNameLabel->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onModelNameLabelUpdate ), NULL, this );
|
m_modelNameLabel->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onModelNameLabelUpdate ), NULL, this );
|
||||||
|
@ -322,8 +323,9 @@ DIALOG_SIM_MODEL_BASE::~DIALOG_SIM_MODEL_BASE()
|
||||||
m_useLibraryModelRadioButton->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onRadioButton ), NULL, this );
|
m_useLibraryModelRadioButton->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onRadioButton ), NULL, this );
|
||||||
m_pathLabel->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathLabelUpdate ), NULL, this );
|
m_pathLabel->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathLabelUpdate ), NULL, this );
|
||||||
m_libraryPathText->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextKillFocus ), NULL, this );
|
m_libraryPathText->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextKillFocus ), NULL, this );
|
||||||
|
m_libraryPathText->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextSetFocus ), NULL, this );
|
||||||
|
m_libraryPathText->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathText ), NULL, this );
|
||||||
m_libraryPathText->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextEnter ), NULL, this );
|
m_libraryPathText->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextEnter ), NULL, this );
|
||||||
m_libraryPathText->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathUpdate ), NULL, this );
|
|
||||||
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonClick ), NULL, this );
|
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonClick ), NULL, this );
|
||||||
m_browseButton->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
|
m_browseButton->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
|
||||||
m_modelNameLabel->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onModelNameLabelUpdate ), NULL, this );
|
m_modelNameLabel->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onModelNameLabelUpdate ), NULL, this );
|
||||||
|
|
|
@ -407,8 +407,9 @@
|
||||||
<property name="window_name"></property>
|
<property name="window_name"></property>
|
||||||
<property name="window_style"></property>
|
<property name="window_style"></property>
|
||||||
<event name="OnKillFocus">onLibraryPathTextKillFocus</event>
|
<event name="OnKillFocus">onLibraryPathTextKillFocus</event>
|
||||||
|
<event name="OnSetFocus">onLibraryPathTextSetFocus</event>
|
||||||
|
<event name="OnText">onLibraryPathText</event>
|
||||||
<event name="OnTextEnter">onLibraryPathTextEnter</event>
|
<event name="OnTextEnter">onLibraryPathTextEnter</event>
|
||||||
<event name="OnUpdateUI">onLibraryPathUpdate</event>
|
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="sizeritem" expanded="1">
|
<object class="sizeritem" expanded="1">
|
||||||
|
|
|
@ -87,8 +87,9 @@ class DIALOG_SIM_MODEL_BASE : public DIALOG_SHIM
|
||||||
virtual void onRadioButton( wxCommandEvent& event ) { event.Skip(); }
|
virtual void onRadioButton( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void onLibraryPathLabelUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
virtual void onLibraryPathLabelUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||||
virtual void onLibraryPathTextKillFocus( wxFocusEvent& event ) { event.Skip(); }
|
virtual void onLibraryPathTextKillFocus( wxFocusEvent& event ) { event.Skip(); }
|
||||||
|
virtual void onLibraryPathTextSetFocus( wxFocusEvent& event ) { event.Skip(); }
|
||||||
|
virtual void onLibraryPathText( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void onLibraryPathTextEnter( wxCommandEvent& event ) { event.Skip(); }
|
virtual void onLibraryPathTextEnter( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void onLibraryPathUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
|
||||||
virtual void onBrowseButtonClick( wxCommandEvent& event ) { event.Skip(); }
|
virtual void onBrowseButtonClick( wxCommandEvent& event ) { event.Skip(); }
|
||||||
virtual void onBrowseButtonUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
virtual void onBrowseButtonUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||||
virtual void onModelNameLabelUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
virtual void onModelNameLabelUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||||
|
|
|
@ -359,7 +359,7 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER&
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_libMgr.CreateLibrary( path );
|
m_libMgr.CreateLibrary( path, &aReporter );
|
||||||
}
|
}
|
||||||
catch( const IO_ERROR& e )
|
catch( const IO_ERROR& e )
|
||||||
{
|
{
|
||||||
|
@ -407,37 +407,34 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
|
||||||
// FIXME: Don't have special cases for raw Spice models and KIBIS.
|
// FIXME: Don't have special cases for raw Spice models and KIBIS.
|
||||||
if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
|
if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
|
||||||
{
|
{
|
||||||
int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
|
int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
|
||||||
std::string path = rawSpiceModel->GetParam( libParamIndex ).value->ToString();
|
wxString path = rawSpiceModel->GetParam( libParamIndex ).value->ToString();
|
||||||
|
|
||||||
if( path != "" )
|
if( !path.IsEmpty() )
|
||||||
m_rawIncludes.insert( path );
|
m_rawIncludes.insert( path );
|
||||||
}
|
}
|
||||||
else if( auto kibisModel = dynamic_cast<const SIM_MODEL_KIBIS*>( aItem.model ) )
|
else if( auto kibisModel = dynamic_cast<const SIM_MODEL_KIBIS*>( aItem.model ) )
|
||||||
{
|
{
|
||||||
wxFileName cacheDir;
|
wxFileName cacheFn;
|
||||||
cacheDir.AssignDir( PATHS::GetUserCachePath() );
|
cacheFn.AssignDir( PATHS::GetUserCachePath() );
|
||||||
cacheDir.AppendDir( wxT( "ibis" ) );
|
cacheFn.AppendDir( wxT( "ibis" ) );
|
||||||
|
cacheFn.SetFullName( aSymbol.GetRef( &aSheet ) + wxT( ".cache" ) );
|
||||||
|
|
||||||
std::string libraryPath = fmt::format( "{}/{}.cache",
|
wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
|
||||||
std::string( cacheDir.GetPath() ),
|
|
||||||
std::string( aSymbol.GetRef( &aSheet ) ) );
|
|
||||||
wxFile cacheFile( libraryPath, wxFile::write );
|
|
||||||
|
|
||||||
if( !cacheFile.IsOpened() )
|
if( !cacheFile.IsOpened() )
|
||||||
{
|
{
|
||||||
DisplayErrorMessage( nullptr,
|
DisplayErrorMessage( nullptr, wxString::Format( _( "Could not open file '%s' to write "
|
||||||
wxString::Format( _( "Could not open file '%s' to write IBIS model" ),
|
"IBIS model" ),
|
||||||
libraryPath ) );
|
cacheFn.GetFullPath() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto spiceGenerator = static_cast<const SPICE_GENERATOR_KIBIS&>( kibisModel->SpiceGenerator() );
|
auto spiceGenerator = static_cast<const SPICE_GENERATOR_KIBIS&>( kibisModel->SpiceGenerator() );
|
||||||
std::string modelData = spiceGenerator.IbisDevice(
|
std::string modelData = spiceGenerator.IbisDevice( aItem, m_schematic->Prj(),
|
||||||
aItem, std::string( m_schematic->Prj().GetProjectPath().c_str() ),
|
cacheFn.GetPath( wxPATH_GET_SEPARATOR ) );
|
||||||
std::string( cacheDir.GetPath( wxPATH_GET_SEPARATOR ) ).c_str() );
|
|
||||||
|
|
||||||
cacheFile.Write( wxString( modelData ) );
|
cacheFile.Write( wxString( modelData ) );
|
||||||
m_rawIncludes.insert( libraryPath );
|
m_rawIncludes.insert( cacheFn.GetFullPath() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +461,7 @@ void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& a
|
||||||
|
|
||||||
|
|
||||||
void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
|
void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
|
||||||
const std::string& aPath )
|
const wxString& aPath )
|
||||||
{
|
{
|
||||||
// First, expand env vars, if any.
|
// First, expand env vars, if any.
|
||||||
wxString expandedPath = ExpandEnvVarSubstitutions( aPath, &m_schematic->Prj() );
|
wxString expandedPath = ExpandEnvVarSubstitutions( aPath, &m_schematic->Prj() );
|
||||||
|
@ -495,13 +492,13 @@ void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned
|
||||||
|
|
||||||
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
|
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
|
||||||
{
|
{
|
||||||
for( auto&& [path, library] : m_libMgr.GetLibraries() )
|
for( auto& [path, library] : m_libMgr.GetLibraries() )
|
||||||
{
|
{
|
||||||
if( dynamic_cast<const SIM_LIBRARY_SPICE*>( &library.get() ) )
|
if( dynamic_cast<const SIM_LIBRARY_SPICE*>( &library.get() ) )
|
||||||
writeInclude( aFormatter, aNetlistOptions, path );
|
writeInclude( aFormatter, aNetlistOptions, path );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( const std::string& path : m_rawIncludes )
|
for( const wxString& path : m_rawIncludes )
|
||||||
writeInclude( aFormatter, aNetlistOptions, path );
|
writeInclude( aFormatter, aNetlistOptions, path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ private:
|
||||||
void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& aNcCounter );
|
void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& aNcCounter );
|
||||||
|
|
||||||
void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
|
void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
|
||||||
const std::string& aPath );
|
const wxString& aPath );
|
||||||
|
|
||||||
void writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions );
|
void writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions );
|
||||||
void writeModels( OUTPUTFORMATTER& aFormatter );
|
void writeModels( OUTPUTFORMATTER& aFormatter );
|
||||||
|
@ -156,7 +156,7 @@ private:
|
||||||
std::string m_title; ///< Spice simulation title found in the schematic sheet
|
std::string m_title; ///< Spice simulation title found in the schematic sheet
|
||||||
std::vector<std::string> m_directives; ///< Spice directives found in the schematic sheet
|
std::vector<std::string> m_directives; ///< Spice directives found in the schematic sheet
|
||||||
//std::map<std::string, std::unique_ptr<SIM_LIBRARY>> m_libraries; ///< Spice libraries
|
//std::map<std::string, std::unique_ptr<SIM_LIBRARY>> m_libraries; ///< Spice libraries
|
||||||
std::set<std::string> m_rawIncludes; ///< include directives found in symbols
|
std::set<wxString> m_rawIncludes; ///< include directives found in symbols
|
||||||
std::set<std::string> m_nets;
|
std::set<std::string> m_nets;
|
||||||
std::list<SPICE_ITEM> m_items; ///< Items representing schematic symbols in Spice world
|
std::list<SPICE_ITEM> m_items; ///< Items representing schematic symbols in Spice world
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <pgm_base.h>
|
#include <pgm_base.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <common.h>
|
||||||
#include <sch_symbol.h>
|
#include <sch_symbol.h>
|
||||||
|
|
||||||
// Include simulator headers after wxWidgets headers to avoid conflicts with Windows headers
|
// Include simulator headers after wxWidgets headers to avoid conflicts with Windows headers
|
||||||
|
@ -33,7 +34,6 @@
|
||||||
#include <sim/sim_model.h>
|
#include <sim/sim_model.h>
|
||||||
#include <sim/sim_model_ideal.h>
|
#include <sim/sim_model_ideal.h>
|
||||||
|
|
||||||
|
|
||||||
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT& aPrj ) : m_project( aPrj )
|
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT& aPrj ) : m_project( aPrj )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -46,26 +46,18 @@ void SIM_LIB_MGR::Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SIM_LIBRARY& SIM_LIB_MGR::CreateLibrary( const std::string& aLibraryPath, REPORTER* aReporter )
|
SIM_LIBRARY& SIM_LIB_MGR::CreateLibrary( const wxString& aLibraryPath, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
std::string absolutePath = std::string( m_project.AbsolutePath( aLibraryPath ).ToUTF8() );
|
wxString path = ExpandEnvVarSubstitutions( aLibraryPath, &m_project );
|
||||||
|
wxString absolutePath = m_project.AbsolutePath( path );
|
||||||
auto it =
|
|
||||||
m_libraries.try_emplace( aLibraryPath, SIM_LIBRARY::Create( absolutePath, aReporter ) )
|
|
||||||
.first;
|
|
||||||
return *it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
SIM_LIBRARY& SIM_LIB_MGR::SetLibrary( const std::string& aLibraryPath, REPORTER* aReporter )
|
|
||||||
{
|
|
||||||
std::string absolutePath = std::string( m_project.AbsolutePath( aLibraryPath ).ToUTF8() );
|
|
||||||
|
|
||||||
// May throw an exception.
|
// May throw an exception.
|
||||||
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( absolutePath, aReporter );
|
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( m_project.AbsolutePath( path ),
|
||||||
|
aReporter );
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
m_libraries[aLibraryPath] = std::move( library );
|
m_libraries[path] = std::move( library );
|
||||||
return *m_libraries.at( aLibraryPath );
|
return *m_libraries.at( path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,18 +145,18 @@ template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<LIB_FIEL
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::string& aLibraryPath,
|
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
|
||||||
const std::string& aBaseModelName,
|
const std::string& aBaseModelName,
|
||||||
const std::vector<T>& aFields,
|
const std::vector<T>& aFields,
|
||||||
int aSymbolPinCount )
|
int aSymbolPinCount )
|
||||||
{
|
{
|
||||||
std::string absolutePath = std::string( m_project.AbsolutePath( aLibraryPath ).ToUTF8() );
|
wxString path = ExpandEnvVarSubstitutions( aLibraryPath, &m_project );
|
||||||
|
wxString absolutePath = m_project.AbsolutePath( path );
|
||||||
SIM_LIBRARY* library = nullptr;
|
SIM_LIBRARY* library = nullptr;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto it = m_libraries.try_emplace( aLibraryPath,
|
auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( absolutePath ) ).first;
|
||||||
SIM_LIBRARY::Create( absolutePath ) ).first;
|
|
||||||
library = &*it->second;
|
library = &*it->second;
|
||||||
}
|
}
|
||||||
catch( const IO_ERROR& e )
|
catch( const IO_ERROR& e )
|
||||||
|
@ -203,9 +195,9 @@ void SIM_LIB_MGR::SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::map<std::string, std::reference_wrapper<const SIM_LIBRARY>> SIM_LIB_MGR::GetLibraries() const
|
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> SIM_LIB_MGR::GetLibraries() const
|
||||||
{
|
{
|
||||||
std::map<std::string, std::reference_wrapper<const SIM_LIBRARY>> libraries;
|
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> libraries;
|
||||||
|
|
||||||
for( auto& [path, library] : m_libraries )
|
for( auto& [path, library] : m_libraries )
|
||||||
libraries.try_emplace( path, *library );
|
libraries.try_emplace( path, *library );
|
||||||
|
|
|
@ -45,8 +45,7 @@ public:
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
SIM_LIBRARY& CreateLibrary( const std::string& aLibraryPath, REPORTER* aReporter = nullptr );
|
SIM_LIBRARY& CreateLibrary( const wxString& aLibraryPath, REPORTER* aReporter );
|
||||||
SIM_LIBRARY& SetLibrary( const std::string& aLibraryPath, REPORTER* aReporter = nullptr );
|
|
||||||
|
|
||||||
SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, int aSymbolPinCount );
|
SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, int aSymbolPinCount );
|
||||||
|
|
||||||
|
@ -63,20 +62,18 @@ public:
|
||||||
SIM_LIBRARY::MODEL CreateModel( const std::vector<T>& aFields, int aSymbolPinCount );
|
SIM_LIBRARY::MODEL CreateModel( const std::vector<T>& aFields, int aSymbolPinCount );
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
SIM_LIBRARY::MODEL CreateModel( const std::string& aLibraryPath,
|
SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath, const std::string& aBaseModelName,
|
||||||
const std::string& aBaseModelName,
|
const std::vector<T>& aFields, int aSymbolPinCount );
|
||||||
const std::vector<T>& aFields,
|
|
||||||
int aSymbolPinCount );
|
|
||||||
|
|
||||||
void SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel );
|
void SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel );
|
||||||
|
|
||||||
std::map<std::string, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
|
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
|
||||||
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
|
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PROJECT& m_project;
|
const PROJECT& m_project;
|
||||||
std::map<std::string, std::unique_ptr<SIM_LIBRARY>> m_libraries;
|
std::map<wxString, std::unique_ptr<SIM_LIBRARY>> m_libraries;
|
||||||
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
|
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,18 +27,17 @@
|
||||||
#include <sim/sim_library_spice.h>
|
#include <sim/sim_library_spice.h>
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( std::string aFilePath, REPORTER* aReporter )
|
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter )
|
||||||
{
|
{
|
||||||
std::unique_ptr<SIM_LIBRARY> library;
|
std::unique_ptr<SIM_LIBRARY> library;
|
||||||
wxString wxaFilePath( aFilePath );
|
|
||||||
|
|
||||||
if( wxaFilePath.EndsWith( ".ibs" ) )
|
if( aFilePath.EndsWith( ".ibs" ) )
|
||||||
library = std::make_unique<SIM_LIBRARY_KIBIS>();
|
library = std::make_unique<SIM_LIBRARY_KIBIS>();
|
||||||
else
|
else
|
||||||
library = std::make_unique<SIM_LIBRARY_SPICE>();
|
library = std::make_unique<SIM_LIBRARY_SPICE>();
|
||||||
|
|
||||||
library->m_reporter = aReporter;
|
library->m_reporter = aReporter;
|
||||||
library->ReadFile( aFilePath );
|
library->ReadFile( std::string( aFilePath.c_str() ) );
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@ public:
|
||||||
* @param aReporter The reporter the library reports to
|
* @param aReporter The reporter the library reports to
|
||||||
* @return The library loaded in a newly constructed object.
|
* @return The library loaded in a newly constructed object.
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<SIM_LIBRARY> Create( std::string aFilePath,
|
static std::unique_ptr<SIM_LIBRARY> Create( const wxString& aFilePath,
|
||||||
REPORTER* aReporter = nullptr );
|
REPORTER* aReporter = nullptr );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read library from a source file. Must be in the format appropriate to the subclass, e.g.
|
* Read library from a source file. Must be in the format appropriate to the subclass, e.g.
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <sim/kibis/kibis.h>
|
#include <sim/kibis/kibis.h>
|
||||||
#include <sim/sim_model_kibis.h>
|
#include <sim/sim_model_kibis.h>
|
||||||
#include <sim/sim_library_kibis.h>
|
#include <sim/sim_library_kibis.h>
|
||||||
#include <paths.h>
|
#include <common.h>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#include <kiway.h>
|
#include <kiway.h>
|
||||||
|
@ -58,22 +58,20 @@ std::vector<std::string> SPICE_GENERATOR_KIBIS::CurrentNames( const SPICE_ITEM&
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const std::string aCwd,
|
std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
|
||||||
const std::string aCacheDir ) const
|
const wxString& aCacheDir ) const
|
||||||
{
|
{
|
||||||
std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::LIBRARY_FIELD );
|
std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::LIBRARY_FIELD );
|
||||||
std::string ibisCompName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::NAME_FIELD );
|
std::string ibisCompName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::NAME_FIELD );
|
||||||
std::string ibisPinName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::PIN_FIELD );
|
std::string ibisPinName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::PIN_FIELD );
|
||||||
std::string ibisModelName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::MODEL_FIELD );
|
std::string ibisModelName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::MODEL_FIELD );
|
||||||
bool diffMode = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
|
bool diffMode = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
|
||||||
|
|
||||||
wxFileName libPath = wxFileName( wxString( ibisLibFilename ) );
|
wxString path = ExpandEnvVarSubstitutions( ibisLibFilename, &aProject );
|
||||||
|
wxString absolutePath = aProject.AbsolutePath( path );
|
||||||
|
|
||||||
if( !libPath.IsAbsolute() )
|
KIBIS kibis( std::string( absolutePath.c_str() ) );
|
||||||
libPath.MakeAbsolute( aCwd );
|
kibis.m_cacheDir = std::string( aCacheDir.c_str() );
|
||||||
|
|
||||||
KIBIS kibis( std::string( libPath.GetFullPath().c_str() ) );
|
|
||||||
kibis.m_cacheDir = aCacheDir;
|
|
||||||
|
|
||||||
if( !kibis.m_valid )
|
if( !kibis.m_valid )
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,8 +41,8 @@ public:
|
||||||
std::string ModelLine( const SPICE_ITEM& aItem ) const override;
|
std::string ModelLine( const SPICE_ITEM& aItem ) const override;
|
||||||
std::vector<std::string> CurrentNames( const SPICE_ITEM& aItem ) const override;
|
std::vector<std::string> CurrentNames( const SPICE_ITEM& aItem ) const override;
|
||||||
|
|
||||||
std::string IbisDevice( const SPICE_ITEM& aItem, const std::string aCwd,
|
std::string IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
|
||||||
const std::string aCacheDir ) const;
|
const wxString& aCacheDir ) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> GetInstanceParams() const override;
|
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> GetInstanceParams() const override;
|
||||||
|
|
|
@ -76,7 +76,7 @@ bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
|
||||||
* @param aString a string containing (perhaps) references to env var
|
* @param aString a string containing (perhaps) references to env var
|
||||||
* @return the expanded environment variable.
|
* @return the expanded environment variable.
|
||||||
*/
|
*/
|
||||||
const wxString ExpandEnvVarSubstitutions( const wxString& aString, PROJECT* aProject );
|
const wxString ExpandEnvVarSubstitutions( const wxString& aString, const PROJECT* aProject );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand '${var-name}' templates in text. The LocalResolver is given first crack at it,
|
* Expand '${var-name}' templates in text. The LocalResolver is given first crack at it,
|
||||||
|
|
Loading…
Reference in New Issue