KiCad PCB EDA Suite
Loading...
Searching...
No Matches
simulator_control.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <wx/ffile.h>
25#include <wx/filedlg.h>
26#include <wx_filename.h>
27#include <wx/stc/stc.h>
28
29#include <kiway.h>
30#include <confirm.h>
34#include <sch_edit_frame.h>
35#include <sim/simulator_frame.h>
36#include <sim/sim_plot_tab.h>
37#include <tool/tool_manager.h>
38#include <tools/ee_actions.h>
40#include <scintilla_tricks.h>
43
44
46{
48 return true;
49}
50
51
53{
54 m_simulatorFrame = getEditFrame<SIMULATOR_FRAME>();
55
57 {
61 }
62}
63
64
66{
68 wxString errors;
69 WX_STRING_REPORTER reporter( &errors );
70
71 if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS,
72 reporter ) )
73 {
75 _( "Errors during netlist generation.\n\n" ) + errors );
76 }
77
78 dlg.SetSimCommand( wxS( "*" ) );
80
81 if( dlg.ShowModal() == wxID_OK )
82 {
84 dlg.ApplySettings( tab );
86 }
87
88 return 0;
89}
90
91
93{
94 wxFileDialog openDlg( m_simulatorFrame, _( "Open Simulation Workbook" ), getDefaultPath(), "",
95 FILEEXT::WorkbookFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
96
97 if( openDlg.ShowModal() == wxID_CANCEL )
98 return -1;
99
100 m_simulatorFrame->LoadWorkbook( openDlg.GetPath() );
101 return 0;
102}
103
104
106{
107 wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
108
109 if( filename.GetName().IsEmpty() )
110 {
111 if( m_simulatorFrame->Prj().GetProjectName().IsEmpty() )
112 {
113 filename.SetName( _( "noname" ) );
114 filename.SetExt( FILEEXT::WorkbookFileExtension );
115 }
116 else
117 {
118 filename.SetName( m_simulatorFrame->Prj().GetProjectName() );
119 filename.SetExt( FILEEXT::WorkbookFileExtension );
120 }
121 }
122
123 return filename.GetFullName();
124}
125
126
128{
129 wxFileName path = m_simulator->Settings()->GetWorkbookFilename();
130
131 path.Normalize( FN_NORMALIZE_FLAGS|wxPATH_NORM_ENV_VARS,
133 return path.GetPath();
134}
135
136
138{
139 wxString filename;
140
141 if( aEvent.IsAction( &EE_ACTIONS::saveWorkbook ) )
142 filename = m_simulator->Settings()->GetWorkbookFilename();
143
144 if( filename.IsEmpty() )
145 {
146 wxFileDialog saveAsDlg( m_simulatorFrame, _( "Save Simulation Workbook As" ),
149 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
150
151 if( saveAsDlg.ShowModal() == wxID_CANCEL )
152 return -1;
153
154 filename = saveAsDlg.GetPath();
155 }
156
158 return 0;
159}
160
161
163{
164 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
165 {
166 wxFileDialog saveDlg( m_simulatorFrame, _( "Save Plot as Image" ), "", "",
167 FILEEXT::PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
168
169 if( saveDlg.ShowModal() == wxID_CANCEL )
170 return -1;
171
172 plotTab->GetPlotWin()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
173 }
174
175 return 0;
176}
177
178
180{
182}
183
184
186{
187 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
188 {
189 const wxChar SEPARATOR = ';';
190
191 wxFileDialog saveDlg( m_simulatorFrame, _( "Save Plot Data" ), "", "",
193 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
194
195 if( saveDlg.ShowModal() == wxID_CANCEL )
196 return -1;
197
198 wxFFile out( saveDlg.GetPath(), "wb" );
199
200 std::map<wxString, TRACE*> traces = plotTab->GetTraces();
201
202 if( traces.size() == 0 )
203 return -1;
204
205 SIM_TYPE simType = plotTab->GetSimType();
206
207 std::size_t rowCount = traces.begin()->second->GetDataX().size();
208
209 // write column header names on the first row
210 wxString xAxisName( m_simulator->GetXAxis( simType ) );
211 out.Write( wxString::Format( wxT( "%s%c" ), xAxisName, SEPARATOR ) );
212
213 for( const auto& [name, trace] : traces )
214 out.Write( wxString::Format( wxT( "%s%c" ), name, SEPARATOR ) );
215
216 out.Write( wxS( "\r\n" ) );
217
218 // write each row's numerical value
219 for ( std::size_t curRow=0; curRow < rowCount; curRow++ )
220 {
221 double xAxisValue = traces.begin()->second->GetDataX().at( curRow );
222 out.Write( wxString::Format( wxT( "%g%c" ), xAxisValue, SEPARATOR ) );
223
224 for( const auto& [name, trace] : traces )
225 {
226 double yAxisValue = trace->GetDataY().at( curRow );
227 out.Write( wxString::Format( wxT( "%g%c" ), yAxisValue, SEPARATOR ) );
228 }
229
230 out.Write( wxS( "\r\n" ) );
231 }
232
233 out.Close();
234 }
235
236 return 0;
237}
238
239
241{
242 m_simulatorFrame->Close();
243 return 0;
244}
245
246
248{
249 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
250 {
251 if( aEvent.IsAction( &ACTIONS::zoomInCenter ) )
252 {
253 plotTab->GetPlotWin()->ZoomIn();
254 }
255 else if( aEvent.IsAction( &ACTIONS::zoomOutCenter ) )
256 {
257 plotTab->GetPlotWin()->ZoomOut();
258 }
259 else if( aEvent.IsAction( &ACTIONS::zoomFitScreen ) )
260 {
261 wxCommandEvent dummy;
262 plotTab->GetPlotWin()->OnFit( dummy );
263 }
264 }
265
266 return 0;
267}
268
269
271{
272 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
273 plotTab->GetPlotWin()->ZoomUndo();
274
275 return 0;
276}
277
278
280{
281 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
282 plotTab->GetPlotWin()->ZoomRedo();
283
284 return 0;
285}
286
287
289{
290 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
291 {
292 plotTab->ShowGrid( !plotTab->IsGridShown() );
294 }
295
296 return 0;
297}
298
299
301{
302 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
303 {
304 plotTab->ShowLegend( !plotTab->IsLegendShown() );
306 }
307
308 return 0;
309}
310
311
313{
314 if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
315 {
316 plotTab->SetDottedSecondary( !plotTab->GetDottedSecondary() );
318 }
319
320 return 0;
321}
322
323
325{
327 return 0;
328}
329
330
332{
334 return 0;
335}
336
337
339{
340 if( m_simulator->IsRunning() )
341 {
342 m_simulator->Stop();
343 return 0;
344 }
345
346 if( !getCurrentSimTab() )
347 NewAnalysisTab( aEvent );
348
349 if( !getCurrentSimTab() )
350 return 0;
351
353
354 return 0;
355}
356
357
359{
360 if( m_schematicFrame == nullptr )
361 return -1;
362
363 wxWindow* blocking_dialog = m_schematicFrame->Kiway().GetBlockingDialog();
364
365 if( blocking_dialog )
366 blocking_dialog->Close( true );
367
369 m_schematicFrame->Raise();
370
371 return 0;
372}
373
374
376{
377 if( m_schematicFrame == nullptr )
378 return -1;
379
380 wxWindow* blocking_dialog = m_schematicFrame->Kiway().GetBlockingDialog();
381
382 if( blocking_dialog )
383 blocking_dialog->Close( true );
384
386 m_schematicFrame->Raise();
387
388 return 0;
389}
390
391
393{
394public:
395 enum
396 {
398 };
399
400 void onClose( wxCloseEvent& evt )
401 {
402 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL ) );
403 }
404
405 NETLIST_VIEW_DIALOG( wxWindow* parent ) :
406 DIALOG_SHIM( parent, wxID_ANY, _( "SPICE Netlist" ), wxDefaultPosition,
407 wxSize( 800, 800 ), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
408 m_textCtrl( nullptr ),
409 m_reporter( nullptr )
410 {
411 m_splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
412 wxSP_LIVE_UPDATE | wxSP_NOBORDER | wxSP_3DSASH );
413
414 //Avoid the splitter window being assigned as the Parent to additional windows
415 m_splitter->SetExtraStyle( wxWS_EX_TRANSIENT );
416
417 m_textCtrl = new wxStyledTextCtrl( m_splitter, wxID_ANY );
418
419 m_textCtrl->SetMarginWidth( MARGIN_LINE_NUMBERS, 50 );
420 m_textCtrl->StyleSetForeground( wxSTC_STYLE_LINENUMBER, wxColour( 75, 75, 75 ) );
421 m_textCtrl->StyleSetBackground( wxSTC_STYLE_LINENUMBER, wxColour( 220, 220, 220 ) );
422 m_textCtrl->SetMarginType( MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER );
423
424 wxFont fixedFont = KIUI::GetMonospacedUIFont();
425
426 for( int i = 0; i < wxSTC_STYLE_MAX; ++i )
427 m_textCtrl->StyleSetFont( i, fixedFont );
428
429 m_textCtrl->StyleClearAll(); // Addresses a bug in wx3.0 where styles are not correctly set
430
431 m_textCtrl->SetWrapMode( wxSTC_WRAP_WORD );
432 m_textCtrl->SetLexer( wxSTC_LEX_SPICE );
433 m_textCtrl->SetMinSize( wxSize( 40, 40 ) );
434 m_textCtrl->SetSize( wxSize( 40, 40 ) );
435
436 m_reporter = new WX_HTML_REPORT_BOX( m_splitter, wxID_ANY );
437 m_reporter->SetMinSize( wxSize( 40, 40 ) );
438 m_reporter->SetSize( wxSize( 40, 40 ) );
439
440 m_splitter->SetMinimumPaneSize( 40 );
441 m_splitter->SetSashPosition( 760 );
442 m_splitter->SetSashGravity( 0.9 );
443 m_splitter->SplitHorizontally( m_textCtrl, m_reporter );
444
445 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
446 sizer->Add( m_splitter, 1, wxEXPAND | wxALL, 5 );
447 SetSizer( sizer );
448 Layout();
449
450 Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( NETLIST_VIEW_DIALOG::onClose ),
451 nullptr, this );
452
453 m_scintillaTricks = std::make_unique<SCINTILLA_TRICKS>( m_textCtrl, wxT( "{}" ), false );
454
456 }
457
458 void SetNetlist( const wxString& aSource )
459 {
460 m_textCtrl->SetText( aSource );
461 m_textCtrl->SetEditable( false );
462
463 m_reporter->Flush();
464 }
465
467
468private:
469 wxSplitterWindow* m_splitter;
470 wxStyledTextCtrl* m_textCtrl;
472
473 std::unique_ptr<SCINTILLA_TRICKS> m_scintillaTricks;
474};
475
476
478{
479 std::map<int, wxString> userSignals = m_simulatorFrame->UserDefinedSignals();
480
482
483 if( dlg.ShowQuasiModal() == wxID_OK )
485
486 return 0;
487}
488
489
491{
492 if( m_schematicFrame == nullptr || m_simulator == nullptr )
493 return -1;
494
495 STRING_FORMATTER formatter;
497
500 &formatter, *dlg.GetReporter() );
501
502 dlg.SetNetlist( wxString( formatter.GetString() ) );
503 dlg.ShowModal();
504
505 return 0;
506}
507
508
510{
518
528
534
537}
const char * name
Definition: DXF_plotter.cpp:57
static TOOL_ACTION toggleGrid
Definition: actions.h:149
static TOOL_ACTION zoomOutCenter
Definition: actions.h:99
static TOOL_ACTION zoomRedo
Definition: actions.h:106
static TOOL_ACTION quit
Definition: actions.h:59
static TOOL_ACTION zoomFitScreen
Definition: actions.h:101
static TOOL_ACTION zoomInCenter
Definition: actions.h:98
static TOOL_ACTION zoomUndo
Definition: actions.h:105
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
int ShowQuasiModal()
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetSimCommand(const wxString &aCommand)
void ApplySettings(SIM_TAB *aTab)
void SetSimOptions(int aOptions)
const wxString & GetSimCommand() const
static TOOL_ACTION simAnalysisProperties
Definition: ee_actions.h:271
static TOOL_ACTION editUserDefinedSignals
Definition: ee_actions.h:274
static TOOL_ACTION openWorkbook
Definition: ee_actions.h:260
static TOOL_ACTION stopSimulation
Definition: ee_actions.h:273
static TOOL_ACTION toggleLegend
Definition: ee_actions.h:268
static TOOL_ACTION saveWorkbook
Definition: ee_actions.h:261
static TOOL_ACTION saveWorkbookAs
Definition: ee_actions.h:262
static TOOL_ACTION exportPlotAsCSV
Definition: ee_actions.h:264
static TOOL_ACTION simTune
Definition: ee_actions.h:267
static TOOL_ACTION toggleDarkModePlots
Definition: ee_actions.h:270
static TOOL_ACTION exportPlotAsPNG
Definition: ee_actions.h:263
static TOOL_ACTION showNetlist
Definition: ee_actions.h:275
static TOOL_ACTION simProbe
Definition: ee_actions.h:266
static TOOL_ACTION toggleDottedSecondary
Definition: ee_actions.h:269
static TOOL_ACTION runSimulation
Definition: ee_actions.h:272
static TOOL_ACTION newAnalysisTab
Definition: ee_actions.h:259
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:53
wxWindow * GetBlockingDialog()
Gets the window pointer to the blocking dialog (to send it signals)
Definition: kiway.cpp:689
WX_HTML_REPORT_BOX * m_reporter
void SetNetlist(const wxString &aSource)
std::unique_ptr< SCINTILLA_TRICKS > m_scintillaTricks
void onClose(wxCloseEvent &evt)
wxStyledTextCtrl * m_textCtrl
NETLIST_VIEW_DIALOG(wxWindow *parent)
wxSplitterWindow * m_splitter
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:147
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:320
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
int ExportPlotAsPNG(const TOOL_EVENT &aEvent)
wxString getDefaultPath()
Return the default path to be used in file browser dialog.
SCH_EDIT_FRAME * m_schematicFrame
void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
int ToggleLegend(const TOOL_EVENT &aEvent)
int RedoZoom(const TOOL_EVENT &aEvent)
int ShowNetlist(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int ToggleDarkModePlots(const TOOL_EVENT &aEvent)
int Tune(const TOOL_EVENT &aEvent)
wxString getDefaultFilename()
Return the default filename (with extension) to be used in file browser dialog.
SIMULATOR_FRAME * m_simulatorFrame
bool Init() override
Init() is called once upon a registration of the tool.
int SaveWorkbook(const TOOL_EVENT &aEvent)
int RunSimulation(const TOOL_EVENT &aEvent)
SIM_TAB * getCurrentSimTab()
Set up handlers for various events.
int OpenWorkbook(const TOOL_EVENT &aEvent)
int EditUserDefinedSignals(const TOOL_EVENT &aEvent)
std::shared_ptr< SPICE_CIRCUIT_MODEL > m_circuitModel
int ToggleGrid(const TOOL_EVENT &aEvent)
int Zoom(const TOOL_EVENT &aEvent)
int EditAnalysisTab(const TOOL_EVENT &aEvent)
int ToggleDottedSecondary(const TOOL_EVENT &aEvent)
std::shared_ptr< SPICE_SIMULATOR > m_simulator
int ExportPlotAsCSV(const TOOL_EVENT &aEvent)
int UndoZoom(const TOOL_EVENT &aEvent)
int Probe(const TOOL_EVENT &aEvent)
int NewAnalysisTab(const TOOL_EVENT &aEvent)
int Close(const TOOL_EVENT &aEvent)
SIM_TAB * GetCurrentSimTab() const
Return the current tab (or NULL if there is none).
wxString GetCurrentSimCommand() const
std::shared_ptr< SPICE_CIRCUIT_MODEL > GetCircuitModel() const
void OnModify() override
Must be called after a model change in order to set the "modify" flag and do other frame-specific pro...
bool SaveWorkbook(const wxString &aPath)
Save plot, signal, cursor, measurement, etc.
SCH_EDIT_FRAME * GetSchematicFrame() const
void ToggleDarkModePlots()
Toggle dark-mode of the plot tabs.
SIM_TAB * NewSimTab(const wxString &aSimCommand)
Create a new plot tab for a given simulation type.
bool EditAnalysis()
Shows a dialog for editing the current tab's simulation command, or creating a new tab with a differe...
int GetCurrentOptions() const
bool LoadWorkbook(const wxString &aPath)
Load plot, signal, cursor, measurement, etc.
const std::map< int, wxString > & UserDefinedSignals()
std::shared_ptr< SPICE_SIMULATOR > GetSimulator() const
void SetUserDefinedSignals(const std::map< int, wxString > &aSignals)
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:433
const std::string & GetString()
Definition: richio.h:456
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition: tool_base.h:80
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:230
A slimmed down version of WX_HTML_REPORT_PANEL.
void Flush()
Build the HTML messages page.
A wrapper for reporting to a wxString object.
Definition: reporter.h:164
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:305
This file is part of the common library.
#define _(s)
void Reset() override
static const std::string WorkbookFileExtension
static wxString PngFileWildcard()
static wxString CsvFileWildcard()
static wxString WorkbookFileWildcard()
wxFont GetMonospacedUIFont()
Definition: ui_common.cpp:89
SIM_TYPE
< Possible simulation types
Definition: sim_types.h:32
std::vector< FAB_LAYER_COLOR > dummy
Definition of file extensions used in Kicad.
#define SEPARATOR
Definition: wx_combobox.cpp:27
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:39