7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-21 18:23:45 +00:00

Allow sim models to reference embedded files

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20024
This commit is contained in:
Seth Hillbrand 2025-02-22 13:33:22 -08:00
parent b02a449be8
commit 157c7422b0
21 changed files with 87 additions and 71 deletions

View File

@ -78,7 +78,7 @@ bool FILENAME_RESOLVER::Set3DConfigDir( const wxString& aConfigDir )
}
bool FILENAME_RESOLVER::SetProject( PROJECT* aProject, bool* flgChanged )
bool FILENAME_RESOLVER::SetProject( const PROJECT* aProject, bool* flgChanged )
{
m_project = aProject;

View File

@ -44,6 +44,8 @@
#include <sch_edit_frame.h>
#include <sim/sim_model_l_mutual.h>
#include <sim/spice_circuit_model.h>
#include <widgets/filedlg_open_embed_file.h>
#include <wx/filedlg.h>
#include <wx/log.h>
using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
@ -67,8 +69,8 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame
m_frame( aFrame ),
m_symbol( aSymbol ),
m_fields( aFields ),
m_libraryModelsMgr( &Prj() ),
m_builtinModelsMgr( &Prj() ),
m_libraryModelsMgr( &Prj(), nullptr ),
m_builtinModelsMgr( &Prj(), nullptr ),
m_prevModel( nullptr ),
m_curModelType( SIM_MODEL::TYPE::NONE ),
m_scintillaTricksCode( nullptr ),
@ -80,6 +82,14 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame
m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
m_infoBar->AddCloseButton();
if constexpr (std::is_same_v<T, SCH_SYMBOL>)
m_files = aSymbol.Schematic();
else
m_files = &aSymbol;
m_libraryModelsMgr.SetFiles( m_files );
m_builtinModelsMgr.SetFiles( m_files );
for( SCH_PIN* pin : aSymbol.GetPins() )
{
// De Morgan conversions are equivalences, not additional items to simulate
@ -104,10 +114,7 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
wxPropertyGrid* grid = m_paramGrid->GetGrid();
// In wx 3.0 the color will be wrong sometimes.
grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
grid->Bind( wxEVT_SET_FOCUS, &DIALOG_SIM_MODEL::onParamGridSetFocus, this );
grid->Bind( wxEVT_UPDATE_UI, &DIALOG_SIM_MODEL::onUpdateUI, this );
@ -132,8 +139,6 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame
m_pinAssignmentsGrid->PushEventHandler( new GRID_TRICKS( m_pinAssignmentsGrid ) );
m_subcktLabel->SetFont( KIUI::GetInfoFont( m_subcktLabel ) );
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
}
@ -368,8 +373,11 @@ bool DIALOG_SIM_MODEL<T>::TransferDataFromWindow()
path = m_libraryPathText->GetValue();
wxFileName fn( path );
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
if( !path.starts_with( FILEEXT::KiCadUriPrefix ) && fn.MakeRelativeTo( Prj().GetProjectPath() )
&& !fn.GetFullPath().StartsWith( ".." ) )
{
path = fn.GetFullPath();
}
if( m_modelListBox->GetSelection() >= 0 )
name = m_modelListBox->GetStringSelection().ToStdString();
@ -1249,8 +1257,11 @@ void DIALOG_SIM_MODEL<T>::onBrowseButtonClick( wxCommandEvent& aEvent )
{
static wxString s_mruPath;
wxString path = s_mruPath.IsEmpty() ? Prj().GetProjectPath() : s_mruPath;
wxFileDialog dlg( this, _( "Browse Models" ), path );
wxString path = s_mruPath.IsEmpty() ? Prj().GetProjectPath() : s_mruPath;
wxFileDialog dlg( this, _( "Browse Models" ), path );
FILEDLG_OPEN_EMBED_FILE customize( false );
dlg.SetCustomizeHook( customize );
if( dlg.ShowModal() == wxID_CANCEL )
return;
@ -1259,10 +1270,14 @@ void DIALOG_SIM_MODEL<T>::onBrowseButtonClick( wxCommandEvent& aEvent )
path = dlg.GetPath();
wxFileName fn( path );
s_mruPath = fn.GetPath();
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( wxS( ".." ) ) )
if( customize.GetEmbed() )
{
EMBEDDED_FILES::EMBEDDED_FILE* result = m_files->AddFile( fn, false );
path = result->GetLink();
}
else if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( wxS( ".." ) ) )
path = fn.GetFullPath();
WX_STRING_REPORTER reporter;

View File

@ -35,6 +35,7 @@
#include <sim/sim_library_ibis.h>
#include <sch_symbol.h>
class EMBEDDED_FILES;
// Some probable wxWidgets bugs encountered when writing this class:
// 1. There are rendering problems with wxPropertyGrid on Linux, GTK, Xorg when
@ -128,6 +129,7 @@ private:
T& m_symbol;
std::vector<SCH_FIELD>& m_fields;
EMBEDDED_FILES* m_files;
SIM_LIB_MGR m_libraryModelsMgr;
SIM_LIB_MGR m_builtinModelsMgr;
wxString m_prevLibrary;

View File

@ -1735,7 +1735,7 @@ int ERC_TESTER::TestSimModelIssues()
{
WX_STRING_REPORTER reporter;
int err_count = 0;
SIM_LIB_MGR libMgr( &m_schematic->Prj() );
SIM_LIB_MGR libMgr( &m_schematic->Prj(), m_schematic );
for( SCH_SHEET_PATH& sheet : m_sheetList )
{

View File

@ -87,7 +87,7 @@ struct PIN_INFO
class NETLIST_EXPORTER_BASE
{
public:
NETLIST_EXPORTER_BASE( SCHEMATIC_IFACE* aSchematic ) :
NETLIST_EXPORTER_BASE( SCHEMATIC* aSchematic ) :
m_schematic( aSchematic )
{
wxASSERT( aSchematic );
@ -192,7 +192,7 @@ protected:
std::set<LIB_SYMBOL*, LIB_SYMBOL_LESS_THAN> m_libParts;
/// The schematic we're generating a netlist for
SCHEMATIC_IFACE* m_schematic;
SCHEMATIC* m_schematic;
};
#endif

View File

@ -61,9 +61,9 @@ std::string NAME_GENERATOR::Generate( const std::string& aProposedName )
}
NETLIST_EXPORTER_SPICE::NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic ) :
NETLIST_EXPORTER_SPICE::NETLIST_EXPORTER_SPICE( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER_BASE( aSchematic ),
m_libMgr( &aSchematic->Prj() )
m_libMgr( &aSchematic->Prj(), aSchematic )
{
}
@ -455,7 +455,7 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
auto spiceGenerator = static_cast<const SPICE_GENERATOR_IBIS&>( ibisModel->SpiceGenerator() );
wxString cacheFilepath = cacheFn.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
std::string modelData = spiceGenerator.IbisDevice( aItem, m_schematic->Prj(),
std::string modelData = spiceGenerator.IbisDevice( aItem, m_schematic,
cacheFilepath, aReporter );
cacheFile.Write( wxString( modelData ) );

View File

@ -67,7 +67,7 @@ public:
| OPTION_SAVE_ALL_EVENTS
};
NETLIST_EXPORTER_SPICE( SCHEMATIC_IFACE* aSchematic );
NETLIST_EXPORTER_SPICE( SCHEMATIC* aSchematic );
/**
* Write to specified output file.

View File

@ -33,7 +33,7 @@ enum LABEL_FLAG_SHAPE : unsigned int;
class NETLIST_EXPORTER_SPICE_MODEL : public NETLIST_EXPORTER_SPICE
{
public:
NETLIST_EXPORTER_SPICE_MODEL( SCHEMATIC_IFACE* aSchematic )
NETLIST_EXPORTER_SPICE_MODEL( SCHEMATIC* aSchematic )
: NETLIST_EXPORTER_SPICE( aSchematic )
{
}

View File

@ -1528,7 +1528,7 @@ void SCH_EDIT_FRAME::PrintPage( const RENDER_SETTINGS* aSettings )
void SCH_EDIT_FRAME::RefreshOperatingPointDisplay()
{
SCHEMATIC_SETTINGS& settings = m_schematic->Settings();
SIM_LIB_MGR simLibMgr( &Prj() );
SIM_LIB_MGR simLibMgr( &Prj(), &Schematic() );
NULL_REPORTER devnull;
// Patch for bug early in V7.99 dev

View File

@ -858,7 +858,7 @@ void SCH_FIELD::OnScintillaCharAdded( SCINTILLA_TRICKS* aScintillaTricks,
{
NULL_REPORTER devnull;
SCH_SHEET_PATH& sheet = schematic->CurrentSheet();
SIM_LIB_MGR mgr( &schematic->Prj() );
SIM_LIB_MGR mgr( &schematic->Prj(), schematic );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol, devnull ).model;
for( wxString pin : model.GetPinNames() )

View File

@ -1421,7 +1421,7 @@ bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, i
if( range.IsEmpty() )
range = wxS( "~A" );
SIM_LIB_MGR simLibMgr( &schematic->Prj() );
SIM_LIB_MGR simLibMgr( &schematic->Prj(), schematic );
NULL_REPORTER devnull;
SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ),
devnull ).model;

View File

@ -42,21 +42,6 @@ class OUTLINE_FONT;
}
class SCHEMATIC_IFACE
{
public:
SCHEMATIC_IFACE() {};
virtual ~SCHEMATIC_IFACE() {};
virtual CONNECTION_GRAPH* ConnectionGraph() const = 0;
virtual SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const = 0;
virtual void SetCurrentSheet( const SCH_SHEET_PATH& aPath ) = 0;
virtual SCH_SHEET_PATH& CurrentSheet() const = 0;
virtual wxString GetFileName() const = 0;
virtual PROJECT& Prj() const = 0;
virtual SCH_SHEET_LIST Hierarchy() const = 0;
};
class SCHEMATIC;
class SCHEMATIC_LISTENER
@ -79,7 +64,7 @@ public:
* Right now, Eeschema can have only one schematic open at a time, but this could change.
* Please keep this possibility in mind when adding to this object.
*/
class SCHEMATIC : public SCHEMATIC_IFACE, public EDA_ITEM, public EMBEDDED_FILES
class SCHEMATIC : public EDA_ITEM, public EMBEDDED_FILES
{
public:
SCHEMATIC( PROJECT* aPrj );
@ -95,12 +80,12 @@ public:
void Reset();
/// Return a reference to the project this schematic is part of
PROJECT& Prj() const override { return *m_project; }
PROJECT& Prj() const { return *m_project; }
void SetProject( PROJECT* aPrj );
const std::map<wxString, wxString>* GetProperties() { return &m_properties; }
SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const override
SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const
{
SCH_SHEET_LIST hierarchy( m_rootSheet );
@ -119,7 +104,7 @@ public:
/**
* Return the full schematic flattened hierarchical sheet list.
*/
SCH_SHEET_LIST Hierarchy() const override;
SCH_SHEET_LIST Hierarchy() const;
void RefreshHierarchy();
@ -157,19 +142,19 @@ public:
bool ResolveTextVar( const SCH_SHEET_PATH* aSheetPath, wxString* token, int aDepth ) const;
/// Helper to retrieve the filename from the root sheet screen
wxString GetFileName() const override;
wxString GetFileName() const;
SCH_SHEET_PATH& CurrentSheet() const override
SCH_SHEET_PATH& CurrentSheet() const
{
return *m_currentSheet;
}
void SetCurrentSheet( const SCH_SHEET_PATH& aPath ) override
void SetCurrentSheet( const SCH_SHEET_PATH& aPath )
{
*m_currentSheet = aPath;
}
CONNECTION_GRAPH* ConnectionGraph() const override
CONNECTION_GRAPH* ConnectionGraph() const
{
return m_connectionGraph;
}

View File

@ -22,12 +22,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <filename_resolver.h>
#include <pgm_base.h>
#include <string>
#include <string_utils.h>
#include <common.h>
#include <functional>
#include <sch_symbol.h>
#include <schematic.h>
// Include simulator headers after wxWidgets headers to avoid conflicts with Windows headers
// (especially on msys2 + wxWidgets 3.0.x)
@ -39,7 +41,8 @@
using namespace std::placeholders;
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj ) :
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT* aPrj, EMBEDDED_FILES* aFiles ) :
m_files( aFiles ),
m_project( aPrj ),
m_forceFullParse( false )
{
@ -53,20 +56,20 @@ void SIM_LIB_MGR::Clear()
}
wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject,
REPORTER& aReporter )
wxString SIM_LIB_MGR::ResolveLibraryPath( const wxString& aLibraryPath, REPORTER& aReporter )
{
wxString expandedPath = ExpandEnvVarSubstitutions( aLibraryPath, aProject );
FILENAME_RESOLVER resolver;
// Convert it to UNIX format
expandedPath.Replace( '\\', '/' );
resolver.SetProject( m_project );
wxString expandedPath = resolver.ResolvePath( aLibraryPath, wxEmptyString, m_files );
wxFileName fn( expandedPath );
if( fn.IsAbsolute() )
return fn.GetFullPath();
wxFileName projectFn( aProject ? aProject->AbsolutePath( expandedPath ) : expandedPath );
wxFileName projectFn( m_project ? m_project->AbsolutePath( expandedPath ) : expandedPath );
if( projectFn.Exists() )
return projectFn.GetFullPath();
@ -106,7 +109,7 @@ wxString SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const wxString& aLibPath,
{
wxString relLib( aRelativeLib );
relLib = ResolveLibraryPath( relLib, m_project, aReporter );
relLib = ResolveLibraryPath( relLib, aReporter );
wxFileName fn( relLib );
@ -119,7 +122,7 @@ wxString SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const wxString& aLibPath,
if( !fn.Exists() )
fullPath = aLibPath;
fullPath = ResolveLibraryPath( fullPath, m_project, aReporter );
fullPath = ResolveLibraryPath( fullPath, aReporter );
return fullPath;
}
@ -127,7 +130,7 @@ wxString SIM_LIB_MGR::ResolveEmbeddedLibraryPath( const wxString& aLibPath,
void SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath, REPORTER& aReporter )
{
wxString path = ResolveLibraryPath( aLibraryPath, m_project, aReporter );
wxString path = ResolveLibraryPath( aLibraryPath, aReporter );
if( aReporter.HasMessageOfSeverity( RPT_SEVERITY_UNDEFINED | RPT_SEVERITY_ERROR ) )
return;
@ -280,7 +283,7 @@ SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
SIM_LIBRARY* library = nullptr;
SIM_MODEL* baseModel = nullptr;
std::string modelName;
wxString path = ResolveLibraryPath( aLibraryPath, m_project, aReporter );
wxString path = ResolveLibraryPath( aLibraryPath, aReporter );
auto it = m_libraries.find( path );

View File

@ -31,6 +31,7 @@
#include <sim/sim_library.h>
#include <sim/sim_model.h>
class EMBEDDED_FILES;
class PROJECT;
class SCH_SYMBOL;
@ -38,13 +39,16 @@ class SCH_SYMBOL;
class SIM_LIB_MGR
{
public:
SIM_LIB_MGR( const PROJECT* aPrj );
SIM_LIB_MGR( const PROJECT* aPrj, EMBEDDED_FILES* aFiles );
virtual ~SIM_LIB_MGR() = default;
void SetForceFullParse() { m_forceFullParse = true; }
void Clear();
void SetFiles( EMBEDDED_FILES* aFiles ) { m_files = aFiles; }
void SetLibrary( const wxString& aLibraryPath, REPORTER& aReporter );
SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, const std::vector<SCH_PIN*>& aPins,
@ -74,12 +78,12 @@ public:
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
static wxString ResolveLibraryPath( const wxString& aLibraryPath, const PROJECT* aProject,
REPORTER& aReporter );
wxString ResolveLibraryPath( const wxString& aLibraryPath, REPORTER& aReporter );
wxString ResolveEmbeddedLibraryPath( const wxString& aLibPath, const wxString& aRelativeLib,
REPORTER& aReporter );
private:
EMBEDDED_FILES* m_files;
const PROJECT* m_project;
bool m_forceFullParse;
std::map<wxString, std::unique_ptr<SIM_LIBRARY>> m_libraries;

View File

@ -1736,9 +1736,14 @@ void SIM_MODEL::MigrateSimModel( T& aSymbol, const PROJECT* aProject )
if( !lib.IsEmpty() )
{
WX_STRING_REPORTER reporter;
SIM_LIB_MGR libMgr( aProject );
SIM_LIB_MGR libMgr( aProject, nullptr );
std::vector<SCH_FIELD> emptyFields;
if constexpr (std::is_same_v<T, SCH_SYMBOL>)
libMgr.SetFiles( aSymbol.Schematic() );
else
libMgr.SetFiles( &aSymbol );
// Pull out any following parameters from model name
model = model.BeforeFirst( ' ', &modelLineParams );
modelInfo.m_Text = model;

View File

@ -27,6 +27,7 @@
#include <fmt/core.h>
#include <wx/filename.h>
#include <kiway.h>
#include <schematic.h>
#include "sim_lib_mgr.h"
std::string SPICE_GENERATOR_IBIS::ModelName( const SPICE_ITEM& aItem ) const
@ -51,7 +52,7 @@ std::vector<std::string> SPICE_GENERATOR_IBIS::CurrentNames( const SPICE_ITEM& a
}
std::string SPICE_GENERATOR_IBIS::IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
std::string SPICE_GENERATOR_IBIS::IbisDevice( const SPICE_ITEM& aItem, SCHEMATIC* aSchematic,
const wxString& aCacheDir,
REPORTER& aReporter ) const
{
@ -62,7 +63,8 @@ std::string SPICE_GENERATOR_IBIS::IbisDevice( const SPICE_ITEM& aItem, const PRO
bool diffMode = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_IBIS::DIFF_FIELD ) == "1";
WX_STRING_REPORTER reporter;
wxString path = SIM_LIB_MGR::ResolveLibraryPath( ibisLibFilename, &aProject, reporter );
SIM_LIB_MGR mgr( &aSchematic->Prj(), aSchematic );
wxString path = mgr.ResolveLibraryPath( ibisLibFilename, reporter );
if( reporter.HasMessage() )
THROW_IO_ERROR( reporter.GetMessages() );

View File

@ -31,7 +31,7 @@
class SIM_LIBRARY_IBIS;
class REPORTER;
class SCHEMATIC;
class SPICE_GENERATOR_IBIS : public SPICE_GENERATOR
{
@ -42,7 +42,7 @@ public:
std::string ModelLine( 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 PROJECT& aProject,
std::string IbisDevice( const SPICE_ITEM& aItem, SCHEMATIC* aSchematic,
const wxString& aCacheDir, REPORTER& aReporter ) const;
};

View File

@ -1478,7 +1478,7 @@ void SIMULATOR_FRAME_UI::UpdateTunerValue( const SCH_SHEET_PATH& aSheetPath, con
}
NULL_REPORTER devnull;
SIM_LIB_MGR mgr( &m_schematicFrame->Prj() );
SIM_LIB_MGR mgr( &m_schematicFrame->Prj(), &m_schematicFrame->Schematic() );
SIM_MODEL& model = mgr.CreateModel( &aSheetPath, *symbol, devnull ).model;
const SIM_MODEL::PARAM* tunerParam = model.GetTunerParam();

View File

@ -54,7 +54,7 @@ struct SPICE_PZ_ANALYSES
class SPICE_CIRCUIT_MODEL : public NETLIST_EXPORTER_SPICE, public SIMULATION_MODEL
{
public:
SPICE_CIRCUIT_MODEL( SCHEMATIC_IFACE* aSchematic ) :
SPICE_CIRCUIT_MODEL( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER_SPICE( aSchematic )
{}

View File

@ -587,7 +587,7 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item->GetParent() );
WX_STRING_REPORTER reporter;
SIM_LIB_MGR mgr( &m_frame->Prj() );
SIM_LIB_MGR mgr( &m_frame->Prj(), &m_frame->Schematic() );
SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol, reporter ).model;

View File

@ -75,7 +75,7 @@ public:
* @retval true success.
* @retval false failure.
*/
bool SetProject( PROJECT* aProject, bool* flgChanged = nullptr );
bool SetProject( const PROJECT* aProject, bool* flgChanged = nullptr );
wxString GetProjectDir() const;
@ -172,7 +172,7 @@ private:
std::list<SEARCH_PATH> m_paths; ///< List of base paths to search from.
int m_errflags;
PGM_BASE* m_pgm;
PROJECT* m_project;
const PROJECT* m_project;
wxString m_curProjDir;
};