KiCad PCB EDA Suite
Loading...
Searching...
No Matches
simulator_frame.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) 2016-2023 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 * @author Maciej Suminski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 3
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <wx/debug.h>
24
25// For some obscure reason, needed on msys2 with some wxWidgets versions (3.0) to avoid
26// undefined symbol at link stage (due to use of #include <pegtl.hpp>)
27// Should not create issues on other platforms
28#include <wx/menu.h>
29
31#include <sch_edit_frame.h>
32#include <widgets/wx_infobar.h>
33#include <kiway.h>
34#include <confirm.h>
35#include <bitmaps.h>
39#include <widgets/wx_grid.h>
40#include <tool/tool_manager.h>
42#include <tool/action_manager.h>
43#include <tool/action_toolbar.h>
44#include <tool/common_control.h>
46#include <tools/sch_actions.h>
47#include <string_utils.h>
48#include <pgm_base.h>
49#include "ngspice.h"
50#include <sim/simulator_frame.h>
52#include <sim/sim_plot_tab.h>
53#include <sim/spice_simulator.h>
55#include <eeschema_settings.h>
56#include <advanced_config.h>
59
60#include <memory>
61
62
63// Reporter is stored by pointer in KIBIS, so keep this here to avoid crashes
65
66
68{
69public:
71 m_parent( aParent )
72 {
73 }
74
75 REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
76 {
77 wxCommandEvent* event = new wxCommandEvent( EVT_SIM_REPORT );
78 event->SetString( aText );
79 wxQueueEvent( m_parent, event );
80 return *this;
81 }
82
83 bool HasMessage() const override
84 {
85 return false; // Technically "indeterminate" rather than false.
86 }
87
88 void OnSimStateChange( SIMULATOR* aObject, SIM_STATE aNewState ) override
89 {
90 wxCommandEvent* event = nullptr;
91
92 switch( aNewState )
93 {
94 case SIM_IDLE: event = new wxCommandEvent( EVT_SIM_FINISHED ); break;
95 case SIM_RUNNING: event = new wxCommandEvent( EVT_SIM_STARTED ); break;
96 default: wxFAIL; return;
97 }
98
99 wxQueueEvent( m_parent, event );
100 }
101
102private:
104};
105
106
107BEGIN_EVENT_TABLE( SIMULATOR_FRAME, KIWAY_PLAYER )
109 EVT_MENU( wxID_CLOSE, SIMULATOR_FRAME::onExit )
110END_EVENT_TABLE()
111
112
113SIMULATOR_FRAME::SIMULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
114 KIWAY_PLAYER( aKiway, aParent, FRAME_SIMULATOR, _( "Simulator" ), wxDefaultPosition,
115 wxDefaultSize, wxDEFAULT_FRAME_STYLE, wxT( "simulator" ), unityScale ),
116 m_schematicFrame( nullptr ),
117 m_toolBar( nullptr ),
118 m_ui( nullptr ),
119 m_simFinished( false ),
120 m_workbookModified( false )
121{
122 m_schematicFrame = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
123 wxASSERT( m_schematicFrame );
124
125 // Give an icon
126 wxIcon icon;
127 icon.CopyFromBitmap( KiBitmap( BITMAPS::simulator ) );
128 SetIcon( icon );
129
130 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
131 SetSizer( mainSizer );
132
133 m_infoBar = new WX_INFOBAR( this );
134 mainSizer->Add( m_infoBar, 0, wxEXPAND, 0 );
135
136 m_tbTopMain = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
137 wxAUI_TB_DEFAULT_STYLE|wxAUI_TB_HORZ_LAYOUT|wxAUI_TB_PLAIN_BACKGROUND );
138 m_tbTopMain->Realize();
139 mainSizer->Add( m_tbTopMain, 0, wxEXPAND, 5 );
140
142 mainSizer->Add( m_ui, 1, wxEXPAND, 5 );
143
145
146 if( !m_simulator )
147 throw SIMULATOR_INIT_ERR( "Failed to create simulator instance" );
148
149 LoadSettings( config() );
150
151 std::shared_ptr<NGSPICE_SETTINGS> cfg = Prj().GetProjectFile().m_SchematicSettings->m_NgspiceSettings;
152
153 if( cfg->GetWorkbookFilename().IsEmpty() )
154 cfg->SetCompatibilityMode( NGSPICE_COMPATIBILITY_MODE::LT_PSPICE );
155
156 m_simulator->Init();
157
158 m_reporter = new SIM_THREAD_REPORTER( this );
159 m_simulator->SetReporter( m_reporter );
160
161 m_circuitModel = std::make_shared<SPICE_CIRCUIT_MODEL>( &m_schematicFrame->Schematic() );
162
163 setupTools();
165
166 // Set the tool manager for the toolbar here, since the tool manager didn't exist when the toolbar
167 // was created.
168 m_tbTopMain->SetToolManager( m_toolManager );
169
174
175 Bind( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIMULATOR_FRAME::onExit ), this, wxID_EXIT );
176
177 Bind( EVT_SIM_UPDATE, &SIMULATOR_FRAME::onUpdateSim, this );
178 Bind( EVT_SIM_REPORT, &SIMULATOR_FRAME::onSimReport, this );
179 Bind( EVT_SIM_STARTED, &SIMULATOR_FRAME::onSimStarted, this );
180 Bind( EVT_SIM_FINISHED, &SIMULATOR_FRAME::onSimFinished, this );
181
182 // Ensure new items are taken in account by sizers:
183 Layout();
184
185 // resize the subwindows size. At least on Windows, calling wxSafeYield before
186 // resizing the subwindows forces the wxSplitWindows size events automatically generated
187 // by wxWidgets to be executed before our resize code.
188 // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
189 // events
190 wxSafeYield();
191 m_ui->SetSubWindowsSashSize();
192
193 // Ensure the window is on top
194 Raise();
195
196 m_ui->InitWorkbook();
197 UpdateTitle();
198}
199
200
202{
203 NULL_REPORTER devnull;
204
205 m_simulator->Attach( nullptr, wxEmptyString, 0, wxEmptyString, devnull );
206 m_simulator->SetReporter( nullptr );
207 delete m_reporter;
208}
209
210
212{
213 // Create the manager
215 m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
216
218
219 // Attach the events to the tool dispatcher
221 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
222
223 // Register tools
224 m_toolManager->RegisterTool( new COMMON_CONTROL );
225 m_toolManager->RegisterTool( new SIMULATOR_CONTROL );
226 m_toolManager->InitTools();
227}
228
229
231{
233
234 UpdateTitle();
235
236 m_ui->ShowChangedLanguage();
237}
238
239
241{
242 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg ) )
243 {
245 m_ui->LoadSettings( cfg );
246 }
247
248 if( m_simulator )
250}
251
252
254{
255 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg ) )
256 {
258 m_ui->SaveSettings( cfg );
259 }
260
262
263 if( m_schematicFrame && modified )
264 m_schematicFrame->OnModify();
265}
266
267
269{
271
273 m_ui->ApplyPreferences( cfg->m_Simulator.preferences );
274}
275
276
278{
280 return &cfg->m_Simulator.window;
281
282 wxFAIL_MSG( wxT( "SIMULATOR not running with EESCHEMA_SETTINGS" ) );
283 return &aCfg->m_Window; // non-null fail-safe
284}
285
286
288{
289 if( m_ui->GetCurrentSimTab() )
290 return m_ui->GetCurrentSimTab()->GetSimCommand();
291 else
292 return m_circuitModel->GetSchTextSimCommand();
293}
294
295
300
301
303{
304 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
305 return simTab->GetSimOptions();
306 else
308}
309
310
312{
313 bool unsaved = true;
314 bool readOnly = false;
315 wxString title;
316 std::shared_ptr<NGSPICE_SETTINGS> cfg = Prj().GetProjectFile().m_SchematicSettings->m_NgspiceSettings;
317 wxFileName filename = Prj().AbsolutePath( cfg->GetWorkbookFilename() );
318
319 if( filename.IsOk() && filename.FileExists() )
320 {
321 unsaved = false;
322 readOnly = !filename.IsFileWritable();
323 }
324
326 title = wxT( "*" ) + filename.GetName();
327 else
328 title = filename.GetName();
329
330 if( readOnly )
331 title += wxS( " " ) + _( "[Read Only]" );
332
333 if( unsaved )
334 title += wxS( " " ) + _( "[Unsaved]" );
335
336 title += wxT( " \u2014 " ) + _( "SPICE Simulator" );
337
338 SetTitle( title );
339}
340
341
342// Don't let the dialog grow too tall: you may not be able to get to the OK button
343#define MAX_MESSAGES 20
344
346{
347 if( !aReporter.HasMessage() )
348 return;
349
350 wxArrayString lines = wxSplit( aReporter.GetMessages(), '\n' );
351
352 if( lines.size() > MAX_MESSAGES )
353 {
354 lines.RemoveAt( MAX_MESSAGES, lines.size() - MAX_MESSAGES );
355 lines.Add( wxS( "..." ) );
356 }
357
359 {
360 DisplayErrorMessage( this, _( "Errors during netlist generation." ),
361 wxJoin( lines, '\n' ) );
362 }
363 else if( aReporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) )
364 {
365 DisplayInfoMessage( this, _( "Warnings during netlist generation." ),
366 wxJoin( lines, '\n' ) );
367 }
368}
369
370
371bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
372{
373 s_reporter.Clear();
374
375 if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) ) )
376 return false;
377
378 // If we are using the new connectivity, make sure that we do a full-rebuild
379 if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
380 m_schematicFrame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
381
382 bool success = m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions,
383 Prj().GetProjectPath(), s_reporter );
384
386
387 return success;
388}
389
390
391void SIMULATOR_FRAME::ReloadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
392{
393 s_reporter.Clear();
394
395 m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, Prj().GetProjectPath(),
396 s_reporter );
397
399}
400
401
403{
404 wxString oldPlotName = aSimTab->GetSpicePlotName();
405
406 if( oldPlotName.IsEmpty() )
407 return;
408
409 // A run may report a plot that another tab still owns (e.g. an FFT deriving from a TRAN plot,
410 // or an aborted run that produced nothing new). Never destroy such a shared plot; just forget
411 // this tab's reference to it.
412 if( m_ui->IsPlotOwnedByOtherTab( aSimTab, oldPlotName ) )
413 {
414 aSimTab->SetSpicePlotName( wxEmptyString );
415 return;
416 }
417
418 // A noise run produces a pair of plots (odd spectral density noiseN, even integrated noiseN+1).
419 // Destroy both regardless of which of the pair the tab happened to record.
420 long noiseNumber = 0;
421
422 if( oldPlotName.StartsWith( wxS( "noise" ) ) && oldPlotName.Mid( 5 ).ToLong( &noiseNumber ) )
423 {
424 long spectral = ( noiseNumber % 2 == 0 ) ? noiseNumber - 1 : noiseNumber;
425
426 m_simulator->Command( wxString::Format( wxT( "destroy noise%ld" ), spectral ).ToStdString() );
427 m_simulator->Command(
428 wxString::Format( wxT( "destroy noise%ld" ), spectral + 1 ).ToStdString() );
429 }
430 else
431 {
432 m_simulator->Command( "destroy " + oldPlotName.ToStdString() );
433 }
434
435 aSimTab->SetSpicePlotName( wxEmptyString );
436}
437
438
440{
441 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
442
443 if( !simTab )
444 return;
445
446 if( simTab->GetSimCommand().Upper().StartsWith( wxT( "FFT" ) )
447 || simTab->GetSimCommand().Upper().Contains( wxT( "\nFFT" ) ) )
448 {
449 wxString tranSpicePlot;
450
451 if( SIM_TAB* tranPlotTab = m_ui->GetSimTab( ST_TRAN ) )
452 tranSpicePlot = tranPlotTab->GetSpicePlotName();
453
454 if( tranSpicePlot.IsEmpty() )
455 {
456 DisplayErrorMessage( this, _( "You must run a TRAN simulation first; its results "
457 "will be used for the fast Fourier transform." ) );
458 }
459 else
460 {
461 // Free the tab's previous FFT plot before recomputing; destroyTabPlot() leaves the
462 // shared TRAN plot it derives from untouched.
463 destroyTabPlot( simTab );
464
465 m_simulator->Command( "setplot " + tranSpicePlot.ToStdString() );
466
467 wxArrayString commands = wxSplit( simTab->GetSimCommand(), '\n' );
468
469 for( const wxString& command : commands )
470 {
471 wxBusyCursor wait;
472 m_simulator->Command( command.ToStdString() );
473 }
474
475 simTab->SetSpicePlotName( m_simulator->CurrentPlotName() );
476 m_ui->OnSimRefresh( true );
477
478#if 0
479 m_simulator->Command( "setplot" ); // Print available plots to console
480 m_simulator->Command( "display" ); // Print vectors in current plot to console
481#endif
482 }
483
484 return;
485 }
486 else
487 {
488 if( m_ui->GetSimTabIndex( simTab ) == 0
489 && m_circuitModel->GetSchTextSimCommand() != simTab->GetLastSchTextSimCommand() )
490 {
491 if( simTab->GetLastSchTextSimCommand().IsEmpty()
492 || IsOK( this, _( "Schematic sheet simulation command directive has changed. "
493 "Do you wish to update the Simulation Command?" ) ) )
494 {
495 simTab->SetSimCommand( m_circuitModel->GetSchTextSimCommand() );
496 simTab->SetLastSchTextSimCommand( simTab->GetSimCommand() );
497 OnModify();
498 }
499 }
500 }
501
502 if( !LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() ) )
503 return;
504
505 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
506
507 if( simulatorLock.owns_lock() )
508 {
509 m_simFinished = false;
510
511 // Free this tab's previous plot only once the rerun is committed, so a failed netlist or
512 // a busy simulator leaves the existing results intact. Other tabs' plots must survive
513 // (e.g. an FFT consumes a prior TRAN plot).
514 destroyTabPlot( simTab );
515
516 m_ui->OnSimUpdate();
517 m_simulator->Run();
518
519 // Netlist from schematic may have changed; update signals list, measurements list,
520 // etc.
521 m_ui->OnPlotSettingsChanged();
522 }
523 else
524 {
525 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
526 }
527}
528
529
530SIM_TAB* SIMULATOR_FRAME::NewSimTab( const wxString& aSimCommand )
531{
532 return m_ui->NewSimTab( aSimCommand );
533}
534
535
536const std::vector<wxString> SIMULATOR_FRAME::SimPlotVectors()
537{
538 return m_ui->SimPlotVectors();
539}
540
541
542const std::vector<wxString> SIMULATOR_FRAME::Signals()
543{
544 return m_ui->Signals();
545}
546
547
548const std::map<int, wxString>& SIMULATOR_FRAME::UserDefinedSignals()
549{
550 return m_ui->UserDefinedSignals();
551}
552
553
554void SIMULATOR_FRAME::SetUserDefinedSignals( const std::map<int, wxString>& aSignals )
555{
556 m_ui->SetUserDefinedSignals( aSignals );
557}
558
559
560void SIMULATOR_FRAME::AddVoltageTrace( const wxString& aNetName )
561{
562 m_ui->AddTrace( aNetName, SPT_VOLTAGE );
563}
564
565
566void SIMULATOR_FRAME::AddCurrentTrace( const wxString& aDeviceName )
567{
568 m_ui->AddTrace( aDeviceName, SPT_CURRENT );
569}
570
571
572void SIMULATOR_FRAME::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol )
573{
574 m_ui->AddTuner( aSheetPath, aSymbol );
575}
576
577
579{
580 return m_ui->GetCurrentSimTab();
581}
582
583
584bool SIMULATOR_FRAME::LoadWorkbook( const wxString& aPath )
585{
586 if( m_ui->LoadWorkbook( aPath ) )
587 {
588 UpdateTitle();
589
590 // Successfully loading a workbook does not count as modifying it. Clear the modified
591 // flag after all the EVT_WORKBOOK_MODIFIED events have been processed.
592 CallAfter( [this]()
593 {
594 m_workbookModified = false;
595 } );
596
597 return true;
598 }
599
600 DisplayErrorMessage( this, wxString::Format( _( "Unable to load or parse file %s" ), aPath ) );
601 return false;
602}
603
604
605bool SIMULATOR_FRAME::SaveWorkbook( const wxString& aPath )
606{
607 if( m_ui->SaveWorkbook( aPath ) )
608 {
609 m_workbookModified = false;
610 UpdateTitle();
611
612 return true;
613 }
614
615 return false;
616}
617
618
620{
621 m_ui->ToggleSimConsole();
622}
623
624
626{
627 m_ui->ToggleSimSidePanel();
628}
629
630
632{
633 m_ui->ToggleDarkModePlots();
634}
635
636
638{
639 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
640 DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() );
641
642 s_reporter.Clear();
643
644 if( !simTab )
645 return false;
646
648 s_reporter );
649
651
652 dlg.SetSimCommand( simTab->GetSimCommand() );
653 dlg.SetSimOptions( simTab->GetSimOptions() );
654 dlg.SetPlotSettings( simTab );
655
656 if( dlg.ShowModal() == wxID_OK )
657 {
658 simTab->SetSimCommand( dlg.GetSimCommand() );
659 dlg.ApplySettings( simTab );
660 m_ui->OnPlotSettingsChanged();
661 OnModify();
662 return true;
663 }
664
665 return false;
666}
667
668
669bool SIMULATOR_FRAME::canCloseWindow( wxCloseEvent& aEvent )
670{
672 {
673 wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
674
675 if( filename.GetName().IsEmpty() )
676 {
677 if( Prj().GetProjectName().IsEmpty() )
678 filename.SetFullName( wxT( "noname.wbk" ) );
679 else
680 filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
681 }
682
683 return HandleUnsavedChanges( this, _( "Save changes to workbook?" ),
684 [&]() -> bool
685 {
686 return SaveWorkbook( Prj().AbsolutePath( filename.GetFullName() ) );
687 } );
688 }
689
690 return true;
691}
692
693
695{
696 if( m_simulator->IsRunning() )
697 m_simulator->Stop();
698
699 // Prevent memory leak on exit by deleting all simulation vectors
700 m_simulator->Clean();
701
702 // Cancel a running simProbe or simTune tool
703 m_schematicFrame->GetToolManager()->PostAction( ACTIONS::cancelInteractive );
704
705 SaveSettings( config() );
706
707 m_simulator->Settings().reset();
708
709 Destroy();
710}
711
712
714{
716
717 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
718 wxASSERT( mgr );
719
720 auto showGridCondition =
721 [this]( const SELECTION& aSel )
722 {
723 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
724 return plotTab && plotTab->IsGridShown();
725 };
726
727 auto showLegendCondition =
728 [this]( const SELECTION& aSel )
729 {
730 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
731 return plotTab && plotTab->IsLegendShown();
732 };
733
734 auto showDottedCondition =
735 [this]( const SELECTION& aSel )
736 {
737 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
738 return plotTab && plotTab->GetDottedSecondary();
739 };
740
741 auto darkModePlotCondition =
742 [this]( const SELECTION& aSel )
743 {
744 return m_ui->DarkModePlots();
745 };
746
747 auto simRunning =
748 [this]( const SELECTION& aSel )
749 {
750 return m_simulator && m_simulator->IsRunning();
751 };
752
753 auto simFinished =
754 [this]( const SELECTION& aSel )
755 {
756 return m_simFinished;
757 };
758
759 auto haveSim =
760 [this]( const SELECTION& aSel )
761 {
762 return GetCurrentSimTab() != nullptr;
763 };
764
765 auto havePlot =
766 [this]( const SELECTION& aSel )
767 {
768 return dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() ) != nullptr;
769 };
770
771 auto haveZoomUndo =
772 [this]( const SELECTION& aSel )
773 {
774 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
775 return plotTab && plotTab->GetPlotWin()->UndoZoomStackSize() > 0;
776 };
777
778 auto haveZoomRedo =
779 [this]( const SELECTION& aSel )
780 {
781 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
782 return plotTab && plotTab->GetPlotWin()->RedoZoomStackSize() > 0;
783 };
784
785 // clang-format off
786 auto isSimConsoleShown =
787 [this]( const SELECTION& aSel )
788 {
789 bool aBool = false;
790
791 if( m_simulator )
792 return m_ui->IsSimConsoleShown();
793
794 return aBool;
795 };
796
797 auto isSimSidePanelShown =
798 [this]( const SELECTION& aSel )
799 {
800 bool aBool = false;
801
802 if( m_simulator )
803 return m_ui->IsSimSidePanelShown();
804
805 return aBool;
806 };
807 // clang-format on
808
809#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
810#define CHECK( x ) ACTION_CONDITIONS().Check( x )
811 // clang-format off
815
820
821 mgr->SetConditions( SCH_ACTIONS::toggleSimSidePanel, CHECK( isSimSidePanelShown ) );
822 mgr->SetConditions( SCH_ACTIONS::toggleSimConsole, CHECK( isSimConsoleShown ) );
823
824 mgr->SetConditions( ACTIONS::zoomUndo, ENABLE( haveZoomUndo ) );
825 mgr->SetConditions( ACTIONS::zoomRedo, ENABLE( haveZoomRedo ) );
826 mgr->SetConditions( SCH_ACTIONS::toggleGrid, CHECK( showGridCondition ) );
827 mgr->SetConditions( SCH_ACTIONS::toggleLegend, CHECK( showLegendCondition ) );
828 mgr->SetConditions( SCH_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) );
829 mgr->SetConditions( SCH_ACTIONS::toggleDarkModePlots, CHECK( darkModePlotCondition ) );
830
833 mgr->SetConditions( SCH_ACTIONS::runSimulation, ENABLE( !simRunning ) );
834 mgr->SetConditions( SCH_ACTIONS::stopSimulation, ENABLE( simRunning ) );
835 mgr->SetConditions( SCH_ACTIONS::simProbe, ENABLE( simFinished ) );
836 mgr->SetConditions( SCH_ACTIONS::simTune, ENABLE( simFinished ) );
838 // clang-format on
839#undef CHECK
840#undef ENABLE
841}
842
843
844void SIMULATOR_FRAME::onSimStarted( wxCommandEvent& aEvent )
845{
846 SetCursor( wxCURSOR_ARROWWAIT );
847}
848
849
850void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
851{
852 // Sometimes (for instance with a directive like wrdata my_file.csv "my_signal")
853 // the simulator is in idle state (simulation is finished), but still running, during
854 // the time the file is written. So gives a slice of time to fully finish the work:
855 if( m_simulator->IsRunning() )
856 {
857 int max_time = 40; // For a max timeout = 2s
858
859 do
860 {
861 wxMilliSleep( 50 );
862 wxYield();
863
864 if( max_time )
865 max_time--;
866
867 } while( max_time && m_simulator->IsRunning() );
868 }
869
870 // ensure the shown cursor is the default cursor, not the wxCURSOR_ARROWWAIT set when
871 // staring the simulator in onSimStarted:
872 SetCursor( wxNullCursor );
873
874 // Is a warning message useful if the simulatior is still running?
875 SCHEMATIC& schematic = m_schematicFrame->Schematic();
876 schematic.ClearOperatingPoints();
877
878 m_simFinished = true;
879
880 m_ui->OnSimRefresh( true );
881
882 m_schematicFrame->RefreshOperatingPointDisplay();
883 m_schematicFrame->GetCanvas()->Refresh();
884}
885
886
887void SIMULATOR_FRAME::onUpdateSim( wxCommandEvent& aEvent )
888{
889 static bool updateInProgress = false;
890
891 // skip update when events are triggered too often and previous call didn't end yet
892 if( updateInProgress )
893 return;
894
895 updateInProgress = true;
896
897 if( m_simulator->IsRunning() )
898 m_simulator->Stop();
899
900 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
901
902 if( simulatorLock.owns_lock() )
903 {
904 // Tuner drags and multi-run steps rerun through here without going through
905 // StartSimulation(), so free the prior plot to keep repeated updates from leaking. A
906 // multi-run step's data is already copied into m_multiRunState before the next step.
907 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
908 destroyTabPlot( simTab );
909
910 m_ui->OnSimUpdate();
911 m_simulator->Run();
912 }
913 else
914 {
915 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
916 }
917
918 updateInProgress = false;
919}
920
921
922void SIMULATOR_FRAME::onSimReport( wxCommandEvent& aEvent )
923{
924 m_ui->OnSimReport( aEvent.GetString() );
925}
926
927
928void SIMULATOR_FRAME::onExit( wxCommandEvent& aEvent )
929{
930 if( aEvent.GetId() == wxID_EXIT )
931 Kiway().OnKiCadExit();
932
933 if( aEvent.GetId() == wxID_CLOSE )
934 Close( false );
935}
936
937
944
945
946wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
947wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
948
949wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
950wxDEFINE_EVENT( EVT_SIM_FINISHED, wxCommandEvent );
constexpr EDA_IU_SCALE unityScale
Definition base_units.h:124
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:100
static TOOL_ACTION toggleGrid
Definition actions.h:194
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION zoomRedo
Definition actions.h:144
static TOOL_ACTION zoomUndo
Definition actions.h:143
Manage TOOL_ACTION objects.
void SetConditions(const TOOL_ACTION &aAction, const ACTION_CONDITIONS &aConditions)
Set the conditions the UI elements for activating a specific tool action should use for determining t...
Define the structure of a toolbar with buttons that invoke ACTIONs.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
WINDOW_SETTINGS m_Window
Handle actions that are shared between different applications.
int ShowModal() override
void SetPlotSettings(const SIM_TAB *aSimTab)
void SetSimCommand(const wxString &aCommand)
void ApplySettings(SIM_TAB *aTab)
void SetSimOptions(int aOptions)
const wxString & GetSimCommand() const
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
virtual void setupUIConditions()
Setup the UI conditions for the various actions and their controls in this frame.
virtual void OnModify()
Must be called after a model change in order to set the "modify" flag and do other frame-specific pro...
WX_INFOBAR * m_infoBar
TOOLBAR_SETTINGS * m_toolbarSettings
virtual void configureToolbars()
virtual void RecreateToolbars()
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Save common frame parameters to a configuration data file.
ACTION_TOOLBAR * m_tbTopMain
void ReCreateMenuBar()
Recreate the menu bar.
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.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
KIWAY_PLAYER(KIWAY *aKiway, wxWindow *aParent, FRAME_T aFrameType, const wxString &aTitle, const wxPoint &aPos, const wxSize &aSize, long aStyle, const wxString &aFrameName, const EDA_IU_SCALE &aIuScale)
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:311
void OnKiCadExit()
Definition kiway.cpp:796
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then saves the JSON document contents into the parent JSON_SETTINGS.
A singleton reporter that reports to nowhere.
Definition reporter.h:214
SCHEMATIC_SETTINGS * m_SchematicSettings
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:200
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:407
virtual bool HasMessageOfSeverity(int aSeverityMask) const
Returns true if the reporter has one or more messages matching the specified severity mask.
Definition reporter.h:141
REPORTER()
Definition reporter.h:73
virtual bool HasMessage() const
Returns true if any messages were reported.
Definition reporter.h:132
std::shared_ptr< NGSPICE_SETTINGS > m_NgspiceSettings
Ngspice simulator settings.
Holds all the data relating to one schematic.
Definition schematic.h:90
static TOOL_ACTION toggleSimConsole
static TOOL_ACTION exportPlotToClipboard
static TOOL_ACTION saveWorkbookAs
static TOOL_ACTION toggleSimSidePanel
static TOOL_ACTION exportPlotAsCSV
static TOOL_ACTION simAnalysisProperties
static TOOL_ACTION toggleDottedSecondary
static TOOL_ACTION simTune
static TOOL_ACTION toggleDarkModePlots
static TOOL_ACTION exportPlotAsPNG
static TOOL_ACTION exportPlotToSchematic
static TOOL_ACTION runSimulation
static TOOL_ACTION newAnalysisTab
static TOOL_ACTION simProbe
static TOOL_ACTION showNetlist
static TOOL_ACTION openWorkbook
static TOOL_ACTION saveWorkbook
static TOOL_ACTION toggleLegend
static TOOL_ACTION stopSimulation
Schematic editor (Eeschema) main window.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Schematic symbol object.
Definition sch_symbol.h:69
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
Handle actions for the various symbol editor and viewers.
The SIMULATOR_FRAME_UI holds the main user-interface for running simulations.
The SIMULATOR_FRAME holds the main user-interface for running simulations.
SIMULATOR_FRAME(KIWAY *aKiway, wxWindow *aParent)
SIM_TAB * GetCurrentSimTab() const
Return the current tab (or NULL if there is none).
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
bool canCloseWindow(wxCloseEvent &aEvent) override
void onSimFinished(wxCommandEvent &aEvent)
bool LoadSimulator(const wxString &aSimCommand, unsigned aSimOptions)
Check and load the current netlist into the simulator.
void onSimReport(wxCommandEvent &aEvent)
wxString GetCurrentSimCommand() const
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
void showNetlistErrors(const WX_STRING_REPORTER &aReporter)
void onExit(wxCommandEvent &event)
void destroyTabPlot(SIM_TAB *aSimTab)
Free a tab's previous ngspice plot (and its noise companion) so reruns don't leak.
std::shared_ptr< SPICE_SIMULATOR > m_simulator
SIM_TYPE GetCurrentSimType() const
void setupUIConditions() override
Setup the UI conditions for the various actions and their controls in this frame.
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
ACTION_TOOLBAR * m_toolBar
void AddCurrentTrace(const wxString &aDeviceName)
Add a current trace for a given device to the current plot.
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.
const std::vector< wxString > Signals()
void doCloseWindow() override
const std::vector< wxString > SimPlotVectors()
void AddVoltageTrace(const wxString &aNetName)
Add a voltage trace for a given net to the current plot.
void ToggleDarkModePlots()
Toggle dark-mode of the plot tabs.
SIM_THREAD_REPORTER * m_reporter
void AddTuner(const SCH_SHEET_PATH &aSheetPath, SCH_SYMBOL *aSymbol)
Add a tuner for a symbol.
void onSimStarted(wxCommandEvent &aEvent)
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
std::shared_ptr< SPICE_CIRCUIT_MODEL > m_circuitModel
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.
WINDOW_SETTINGS * GetWindowSettings(APP_SETTINGS_BASE *aCfg) override
Return a pointer to the window settings for this frame.
void onUpdateSim(wxCommandEvent &aEvent)
void UpdateTitle()
Set the main window title bar text.
const std::map< int, wxString > & UserDefinedSignals()
void SetUserDefinedSignals(const std::map< int, wxString > &aSignals)
void ReloadSimulator(const wxString &aSimCommand, unsigned aSimOptions)
Re-send the current command and settings to the simulator.
SCH_EDIT_FRAME * m_schematicFrame
SIMULATOR_FRAME_UI * m_ui
Simple error container for failure to init the simulation engine and ultimately abort the frame const...
Interface to receive simulation updates from SPICE_SIMULATOR class.
static std::shared_ptr< SPICE_SIMULATOR > CreateInstance(const std::string &aName)
mpWindow * GetPlotWin() const
bool IsGridShown() const
bool GetDottedSecondary() const
Turn on/off the cursor for a particular trace.
bool IsLegendShown() const
int GetSimOptions() const
Definition sim_tab.h:51
const wxString & GetSpicePlotName() const
Definition sim_tab.h:57
void SetLastSchTextSimCommand(const wxString &aCmd)
Definition sim_tab.h:55
void SetSimCommand(const wxString &aSimCommand)
Definition sim_tab.h:49
const wxString & GetSimCommand() const
Definition sim_tab.h:48
wxString GetLastSchTextSimCommand() const
Definition sim_tab.h:54
void SetSpicePlotName(const wxString &aPlotName)
Definition sim_tab.h:58
SIMULATOR_FRAME * m_parent
SIM_THREAD_REPORTER(SIMULATOR_FRAME *aParent)
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
bool HasMessage() const override
Returns true if any messages were reported.
void OnSimStateChange(SIMULATOR *aObject, SIM_STATE aNewState) override
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Return simulation type basing on a simulation command directive.
TOOL_MANAGER * m_toolManager
TOOL_DISPATCHER * m_toolDispatcher
virtual void DispatchWxEvent(wxEvent &aEvent)
Process wxEvents (mostly UI events), translate them to TOOL_EVENTs, and make tools handle those.
Master controller class:
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:77
A wrapper for reporting to a wxString object.
Definition reporter.h:189
const wxString & GetMessages() const
Definition reporter.cpp:101
int RedoZoomStackSize() const
Definition mathplot.h:1271
int UndoZoomStackSize() const
Definition mathplot.h:1270
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:146
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
#define CHECK(x)
#define ENABLE(x)
#define _(s)
@ FRAME_SCH
Definition frame_type.h:30
@ FRAME_SIMULATOR
Definition frame_type.h:34
PROJECT & Prj()
Definition kicad.cpp:728
EVT_MENU(ID_COMPARE_PROJECT_BRANCHES, KICAD_MANAGER_FRAME::OnCompareProjectBranches) KICAD_MANAGER_FRAME
see class PGM_BASE
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
@ GLOBAL_CLEANUP
Definition schematic.h:79
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
@ SPT_VOLTAGE
Definition sim_types.h:48
@ SPT_CURRENT
Definition sim_types.h:49
SIM_TYPE
< Possible simulation types
Definition sim_types.h:28
@ ST_TRAN
Definition sim_types.h:38
wxDEFINE_EVENT(EVT_SIM_UPDATE, wxCommandEvent)
#define MAX_MESSAGES
static WX_STRING_REPORTER s_reporter
@ SIM_IDLE
@ SIM_RUNNING
KIWAY Kiway(KFCTL_STANDALONE)
Store the common settings that are saved and loaded for each window / frame.
Definition of file extensions used in Kicad.