KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <tomasz.wlostowski@cern.ch>
7 * @author Maciej Suminski <maciej.suminski@cern.ch>
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, you may find one here:
21 * https://www.gnu.org/licenses/gpl-3.0.html
22 * or you may search the http://www.gnu.org website for the version 3 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <wx/debug.h>
28
29// For some obscure reason, needed on msys2 with some wxWidgets versions (3.0) to avoid
30// undefined symbol at link stage (due to use of #include <pegtl.hpp>)
31// Should not create issues on other platforms
32#include <wx/menu.h>
33
35#include <sch_edit_frame.h>
36#include <kiway.h>
37#include <confirm.h>
38#include <bitmaps.h>
42#include <widgets/wx_grid.h>
43#include <tool/tool_manager.h>
45#include <tool/action_manager.h>
46#include <tool/action_toolbar.h>
47#include <tool/common_control.h>
49#include <tools/sch_actions.h>
50#include <string_utils.h>
51#include <pgm_base.h>
52#include "ngspice.h"
53#include <sim/simulator_frame.h>
55#include <sim/sim_plot_tab.h>
56#include <sim/spice_simulator.h>
58#include <eeschema_settings.h>
59#include <advanced_config.h>
62
63#include <memory>
64
65
66// Reporter is stored by pointer in KIBIS, so keep this here to avoid crashes
68
69
71{
72public:
74 m_parent( aParent )
75 {
76 }
77
78 REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
79 {
80 wxCommandEvent* event = new wxCommandEvent( EVT_SIM_REPORT );
81 event->SetString( aText );
82 wxQueueEvent( m_parent, event );
83 return *this;
84 }
85
86 bool HasMessage() const override
87 {
88 return false; // Technically "indeterminate" rather than false.
89 }
90
91 void OnSimStateChange( SIMULATOR* aObject, SIM_STATE aNewState ) override
92 {
93 wxCommandEvent* event = nullptr;
94
95 switch( aNewState )
96 {
97 case SIM_IDLE: event = new wxCommandEvent( EVT_SIM_FINISHED ); break;
98 case SIM_RUNNING: event = new wxCommandEvent( EVT_SIM_STARTED ); break;
99 default: wxFAIL; return;
100 }
101
102 wxQueueEvent( m_parent, event );
103 }
104
105private:
107};
108
109
110BEGIN_EVENT_TABLE( SIMULATOR_FRAME, KIWAY_PLAYER )
111 EVT_MENU( wxID_EXIT, SIMULATOR_FRAME::onExit )
112 EVT_MENU( wxID_CLOSE, SIMULATOR_FRAME::onExit )
113END_EVENT_TABLE()
114
115
116SIMULATOR_FRAME::SIMULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
117 KIWAY_PLAYER( aKiway, aParent, FRAME_SIMULATOR, _( "Simulator" ), wxDefaultPosition,
118 wxDefaultSize, wxDEFAULT_FRAME_STYLE, wxT( "simulator" ), unityScale ),
119 m_schematicFrame( nullptr ),
120 m_toolBar( nullptr ),
121 m_ui( nullptr ),
122 m_simFinished( false ),
123 m_workbookModified( false )
124{
125 m_schematicFrame = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
126 wxASSERT( m_schematicFrame );
127
128 // Give an icon
129 wxIcon icon;
130 icon.CopyFromBitmap( KiBitmap( BITMAPS::simulator ) );
131 SetIcon( icon );
132
133 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
134 SetSizer( mainSizer );
135
136 m_infoBar = new WX_INFOBAR( this );
137 mainSizer->Add( m_infoBar, 0, wxEXPAND, 0 );
138
139 m_tbTopMain = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
140 wxAUI_TB_DEFAULT_STYLE|wxAUI_TB_HORZ_LAYOUT|wxAUI_TB_PLAIN_BACKGROUND );
141 m_tbTopMain->Realize();
142 mainSizer->Add( m_tbTopMain, 0, wxEXPAND, 5 );
143
144 m_ui = new SIMULATOR_FRAME_UI( this, m_schematicFrame );
145 mainSizer->Add( m_ui, 1, wxEXPAND, 5 );
146
147 m_simulator = SIMULATOR::CreateInstance( "ngspice" );
148 wxASSERT( m_simulator );
149
150 LoadSettings( config() );
151
152 NGSPICE_SETTINGS* settings = dynamic_cast<NGSPICE_SETTINGS*>( m_simulator->Settings().get() );
153
154 wxCHECK2( settings, /* do nothing in release builds*/ );
155
156 if( settings && settings->GetWorkbookFilename().IsEmpty() )
158
159 m_simulator->Init();
160
161 m_reporter = new SIM_THREAD_REPORTER( this );
162 m_simulator->SetReporter( m_reporter );
163
164 m_circuitModel = std::make_shared<SPICE_CIRCUIT_MODEL>( &m_schematicFrame->Schematic() );
165
166 setupTools();
167 setupUIConditions();
168
169 // Set the tool manager for the toolbar here, since the tool manager didn't exist when the toolbar
170 // was created.
171 m_tbTopMain->SetToolManager( m_toolManager );
172
173 m_toolbarSettings = Pgm().GetSettingsManager().GetToolbarSettings<SIMULATOR_TOOLBAR_SETTINGS>( "sim-toolbars" );
174 configureToolbars();
175 RecreateToolbars();
176 ReCreateMenuBar();
177
178 Bind( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIMULATOR_FRAME::onExit ), this,
179 wxID_EXIT );
180
181 Bind( EVT_SIM_UPDATE, &SIMULATOR_FRAME::onUpdateSim, this );
182 Bind( EVT_SIM_REPORT, &SIMULATOR_FRAME::onSimReport, this );
183 Bind( EVT_SIM_STARTED, &SIMULATOR_FRAME::onSimStarted, this );
184 Bind( EVT_SIM_FINISHED, &SIMULATOR_FRAME::onSimFinished, this );
185
186 // Ensure new items are taken in account by sizers:
187 Layout();
188
189 // resize the subwindows size. At least on Windows, calling wxSafeYield before
190 // resizing the subwindows forces the wxSplitWindows size events automatically generated
191 // by wxWidgets to be executed before our resize code.
192 // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
193 // events
194 wxSafeYield();
195 m_ui->SetSubWindowsSashSize();
196
197 // Ensure the window is on top
198 Raise();
199
200 m_ui->InitWorkbook();
201 UpdateTitle();
202}
203
204
206{
207 NULL_REPORTER devnull;
208
209 m_simulator->Attach( nullptr, wxEmptyString, 0, wxEmptyString, devnull );
210 m_simulator->SetReporter( nullptr );
211 delete m_reporter;
212}
213
214
216{
217 // Create the manager
219 m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
220
222
223 // Attach the events to the tool dispatcher
225 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
226
227 // Register tools
231}
232
233
235{
237
238 UpdateTitle();
239
241}
242
243
245{
246 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
247 wxASSERT( cfg );
248
249 if( cfg )
250 {
252 m_ui->LoadSettings( cfg );
253 }
254
256
257 NGSPICE* currentSim = dynamic_cast<NGSPICE*>( m_simulator.get() );
258
259 if( currentSim )
260 m_simulator->Settings() = project.m_SchematicSettings->m_NgspiceSettings;
261}
262
263
265{
266 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
267 wxASSERT( cfg );
268
269 if( cfg )
270 {
272 m_ui->SaveSettings( cfg );
273 }
274
276
277 if( project.m_SchematicSettings )
278 {
279 bool modified = project.m_SchematicSettings->m_NgspiceSettings->SaveToFile();
280
281 if( m_schematicFrame && modified )
283 }
284}
285
286
288{
290
291 auto* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( m_toolManager->GetSettings() );
292 wxASSERT( cfg != nullptr );
293 m_ui->ApplyPreferences( cfg->m_Simulator.preferences );
294}
295
296
298{
299 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
300 wxASSERT( cfg );
301
302 return cfg ? &cfg->m_Simulator.window : nullptr;
303}
304
305
307{
308 if( m_ui->GetCurrentSimTab() )
310 else
311 return m_circuitModel->GetSchTextSimCommand();
312}
313
314
316{
318}
319
320
322{
323 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
324 return simTab->GetSimOptions();
325 else
327}
328
329
331{
332 bool unsaved = true;
333 bool readOnly = false;
334 wxString title;
335 wxFileName filename = Prj().AbsolutePath( m_simulator->Settings()->GetWorkbookFilename() );
336
337 if( filename.IsOk() && filename.FileExists() )
338 {
339 unsaved = false;
340 readOnly = !filename.IsFileWritable();
341 }
342
344 title = wxT( "*" ) + filename.GetName();
345 else
346 title = filename.GetName();
347
348 if( readOnly )
349 title += wxS( " " ) + _( "[Read Only]" );
350
351 if( unsaved )
352 title += wxS( " " ) + _( "[Unsaved]" );
353
354 title += wxT( " \u2014 " ) + _( "SPICE Simulator" );
355
356 SetTitle( title );
357}
358
359
360// Don't let the dialog grow too tall: you may not be able to get to the OK button
361#define MAX_MESSAGES 20
362
364{
365 if( !aReporter.HasMessage() )
366 return;
367
368 wxArrayString lines = wxSplit( aReporter.GetMessages(), '\n' );
369
370 if( lines.size() > MAX_MESSAGES )
371 {
372 lines.RemoveAt( MAX_MESSAGES, lines.size() - MAX_MESSAGES );
373 lines.Add( wxS( "..." ) );
374 }
375
377 {
378 DisplayErrorMessage( this, _( "Errors during netlist generation." ),
379 wxJoin( lines, '\n' ) );
380 }
381 else if( aReporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) )
382 {
383 DisplayInfoMessage( this, _( "Warnings during netlist generation." ),
384 wxJoin( lines, '\n' ) );
385 }
386}
387
388
389bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
390{
392
393 if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) ) )
394 return false;
395
396 // If we are using the new connectivity, make sure that we do a full-rebuild
397 if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
399
400 bool success = m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions,
401 Prj().GetProjectPath(), s_reporter );
402
404
405 return success;
406}
407
408
409void SIMULATOR_FRAME::ReloadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
410{
412
413 m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, Prj().GetProjectPath(),
414 s_reporter );
415
417}
418
419
421{
422 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
423
424 if( !simTab )
425 return;
426
427 if( simTab->GetSimCommand().Upper().StartsWith( wxT( "FFT" ) )
428 || simTab->GetSimCommand().Upper().Contains( wxT( "\nFFT" ) ) )
429 {
430 wxString tranSpicePlot;
431
432 if( SIM_TAB* tranPlotTab = m_ui->GetSimTab( ST_TRAN ) )
433 tranSpicePlot = tranPlotTab->GetSpicePlotName();
434
435 if( tranSpicePlot.IsEmpty() )
436 {
437 DisplayErrorMessage( this, _( "You must run a TRAN simulation first; its results"
438 "will be used for the fast Fourier transform." ) );
439 }
440 else
441 {
442 m_simulator->Command( "setplot " + tranSpicePlot.ToStdString() );
443
444 wxArrayString commands = wxSplit( simTab->GetSimCommand(), '\n' );
445
446 for( const wxString& command : commands )
447 {
448 wxBusyCursor wait;
449 m_simulator->Command( command.ToStdString() );
450 }
451
452 simTab->SetSpicePlotName( m_simulator->CurrentPlotName() );
453 m_ui->OnSimRefresh( true );
454
455#if 0
456 m_simulator->Command( "setplot" ); // Print available plots to console
457 m_simulator->Command( "display" ); // Print vectors in current plot to console
458#endif
459 }
460
461 return;
462 }
463 else
464 {
465 if( m_ui->GetSimTabIndex( simTab ) == 0
466 && m_circuitModel->GetSchTextSimCommand() != simTab->GetLastSchTextSimCommand() )
467 {
468 if( simTab->GetLastSchTextSimCommand().IsEmpty()
469 || IsOK( this, _( "Schematic sheet simulation command directive has changed. "
470 "Do you wish to update the Simulation Command?" ) ) )
471 {
472 simTab->SetSimCommand( m_circuitModel->GetSchTextSimCommand() );
473 simTab->SetLastSchTextSimCommand( simTab->GetSimCommand() );
474 OnModify();
475 }
476 }
477 }
478
479 if( !LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() ) )
480 return;
481
482 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
483
484 if( simulatorLock.owns_lock() )
485 {
486 m_simFinished = false;
487
488 m_ui->OnSimUpdate();
489 m_simulator->Run();
490
491 // Netlist from schematic may have changed; update signals list, measurements list,
492 // etc.
494 }
495 else
496 {
497 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
498 }
499}
500
501
502SIM_TAB* SIMULATOR_FRAME::NewSimTab( const wxString& aSimCommand )
503{
504 return m_ui->NewSimTab( aSimCommand );
505}
506
507
508const std::vector<wxString> SIMULATOR_FRAME::SimPlotVectors()
509{
510 return m_ui->SimPlotVectors();
511}
512
513
514const std::vector<wxString> SIMULATOR_FRAME::Signals()
515{
516 return m_ui->Signals();
517}
518
519
520const std::map<int, wxString>& SIMULATOR_FRAME::UserDefinedSignals()
521{
522 return m_ui->UserDefinedSignals();
523}
524
525
526void SIMULATOR_FRAME::SetUserDefinedSignals( const std::map<int, wxString>& aSignals )
527{
528 m_ui->SetUserDefinedSignals( aSignals );
529}
530
531
532void SIMULATOR_FRAME::AddVoltageTrace( const wxString& aNetName )
533{
534 m_ui->AddTrace( aNetName, SPT_VOLTAGE );
535}
536
537
538void SIMULATOR_FRAME::AddCurrentTrace( const wxString& aDeviceName )
539{
540 m_ui->AddTrace( aDeviceName, SPT_CURRENT );
541}
542
543
544void SIMULATOR_FRAME::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol )
545{
546 m_ui->AddTuner( aSheetPath, aSymbol );
547}
548
549
551{
552 return m_ui->GetCurrentSimTab();
553}
554
555
556bool SIMULATOR_FRAME::LoadWorkbook( const wxString& aPath )
557{
558 if( m_ui->LoadWorkbook( aPath ) )
559 {
560 UpdateTitle();
561
562 // Successfully loading a workbook does not count as modifying it. Clear the modified
563 // flag after all the EVT_WORKBOOK_MODIFIED events have been processed.
564 CallAfter( [this]()
565 {
566 m_workbookModified = false;
567 } );
568
569 return true;
570 }
571
572 DisplayErrorMessage( this, wxString::Format( _( "Unable to load or parse file %s" ), aPath ) );
573 return false;
574}
575
576
577bool SIMULATOR_FRAME::SaveWorkbook( const wxString& aPath )
578{
579 if( m_ui->SaveWorkbook( aPath ) )
580 {
581 m_workbookModified = false;
582 UpdateTitle();
583
584 return true;
585 }
586
587 return false;
588}
589
590
592{
594}
595
596
598{
600}
601
602
604{
606}
607
608
610{
611 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
612 DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() );
613
615
616 if( !simTab )
617 return false;
618
620 s_reporter );
621
623
624 dlg.SetSimCommand( simTab->GetSimCommand() );
625 dlg.SetSimOptions( simTab->GetSimOptions() );
626 dlg.SetPlotSettings( simTab );
627
628 if( dlg.ShowModal() == wxID_OK )
629 {
630 simTab->SetSimCommand( dlg.GetSimCommand() );
631 dlg.ApplySettings( simTab );
633 OnModify();
634 return true;
635 }
636
637 return false;
638}
639
640
641bool SIMULATOR_FRAME::canCloseWindow( wxCloseEvent& aEvent )
642{
644 {
645 wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
646
647 if( filename.GetName().IsEmpty() )
648 {
649 if( Prj().GetProjectName().IsEmpty() )
650 filename.SetFullName( wxT( "noname.wbk" ) );
651 else
652 filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
653 }
654
655 return HandleUnsavedChanges( this, _( "Save changes to workbook?" ),
656 [&]() -> bool
657 {
658 return SaveWorkbook( Prj().AbsolutePath( filename.GetFullName() ) );
659 } );
660 }
661
662 return true;
663}
664
665
667{
668 if( m_simulator->IsRunning() )
669 m_simulator->Stop();
670
671 // Prevent memory leak on exit by deleting all simulation vectors
672 m_simulator->Clean();
673
674 // Cancel a running simProbe or simTune tool
676
677 SaveSettings( config() );
678
679 m_simulator->Settings() = nullptr;
680
681 Destroy();
682}
683
684
686{
688
690 wxASSERT( mgr );
691
692 auto showGridCondition =
693 [this]( const SELECTION& aSel )
694 {
695 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
696 return plotTab && plotTab->IsGridShown();
697 };
698
699 auto showLegendCondition =
700 [this]( const SELECTION& aSel )
701 {
702 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
703 return plotTab && plotTab->IsLegendShown();
704 };
705
706 auto showDottedCondition =
707 [this]( const SELECTION& aSel )
708 {
709 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
710 return plotTab && plotTab->GetDottedSecondary();
711 };
712
713 auto darkModePlotCondition =
714 [this]( const SELECTION& aSel )
715 {
716 return m_ui->DarkModePlots();
717 };
718
719 auto simRunning =
720 [this]( const SELECTION& aSel )
721 {
722 return m_simulator && m_simulator->IsRunning();
723 };
724
725 auto simFinished =
726 [this]( const SELECTION& aSel )
727 {
728 return m_simFinished;
729 };
730
731 auto haveSim =
732 [this]( const SELECTION& aSel )
733 {
734 return GetCurrentSimTab() != nullptr;
735 };
736
737 auto havePlot =
738 [this]( const SELECTION& aSel )
739 {
740 return dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() ) != nullptr;
741 };
742
743 auto haveZoomUndo =
744 [this]( const SELECTION& aSel )
745 {
746 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
747 return plotTab && plotTab->GetPlotWin()->UndoZoomStackSize() > 0;
748 };
749
750 auto haveZoomRedo =
751 [this]( const SELECTION& aSel )
752 {
753 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
754 return plotTab && plotTab->GetPlotWin()->RedoZoomStackSize() > 0;
755 };
756
757 auto isConsoleShown =
758 [this]( const SELECTION& aSel )
759 {
760 bool aBool = false;
761
762 if( m_simulator )
763 return m_ui->IsConsoleShown();
764
765 return aBool;
766 };
767
768 auto isSidePanelShown =
769 [this]( const SELECTION& aSel )
770 {
771 bool aBool = false;
772
773 if( m_simulator )
774 return m_ui->IsSidePanelShown();
775
776 return aBool;
777 };
778
779#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
780#define CHECK( x ) ACTION_CONDITIONS().Check( x )
781 // clang-format off
785
790
791 mgr->SetConditions( ACTIONS::toggleSimulationSidePanel, CHECK( isSidePanelShown ) );
792 mgr->SetConditions( ACTIONS::toggleConsole, CHECK( isConsoleShown ) );
793
794 mgr->SetConditions( ACTIONS::zoomUndo, ENABLE( haveZoomUndo ) );
795 mgr->SetConditions( ACTIONS::zoomRedo, ENABLE( haveZoomRedo ) );
796 mgr->SetConditions( SCH_ACTIONS::toggleGrid, CHECK( showGridCondition ) );
797 mgr->SetConditions( SCH_ACTIONS::toggleLegend, CHECK( showLegendCondition ) );
798 mgr->SetConditions( SCH_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) );
799 mgr->SetConditions( SCH_ACTIONS::toggleDarkModePlots, CHECK( darkModePlotCondition ) );
800
803 mgr->SetConditions( SCH_ACTIONS::runSimulation, ENABLE( !simRunning ) );
804 mgr->SetConditions( SCH_ACTIONS::stopSimulation, ENABLE( simRunning ) );
805 mgr->SetConditions( SCH_ACTIONS::simProbe, ENABLE( simFinished ) );
806 mgr->SetConditions( SCH_ACTIONS::simTune, ENABLE( simFinished ) );
808 // clang-format on
809#undef CHECK
810#undef ENABLE
811}
812
813
814void SIMULATOR_FRAME::onSimStarted( wxCommandEvent& aEvent )
815{
816 SetCursor( wxCURSOR_ARROWWAIT );
817}
818
819
820void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
821{
822 // Sometimes (for instance with a directive like wrdata my_file.csv "my_signal")
823 // the simulator is in idle state (simulation is finished), but still running, during
824 // the time the file is written. So gives a slice of time to fully finish the work:
825 if( m_simulator->IsRunning() )
826 {
827 int max_time = 40; // For a max timeout = 2s
828
829 do
830 {
831 wxMilliSleep( 50 );
832 wxYield();
833
834 if( max_time )
835 max_time--;
836
837 } while( max_time && m_simulator->IsRunning() );
838 }
839
840 // ensure the shown cursor is the default cursor, not the wxCURSOR_ARROWWAIT set when
841 // staring the simulator in onSimStarted:
842 SetCursor( wxNullCursor );
843
844 // Is a warning message useful if the simulatior is still running?
845 SCHEMATIC& schematic = m_schematicFrame->Schematic();
846 schematic.ClearOperatingPoints();
847
848 m_simFinished = true;
849
850 m_ui->OnSimRefresh( true );
851
854}
855
856
857void SIMULATOR_FRAME::onUpdateSim( wxCommandEvent& aEvent )
858{
859 static bool updateInProgress = false;
860
861 // skip update when events are triggered too often and previous call didn't end yet
862 if( updateInProgress )
863 return;
864
865 updateInProgress = true;
866
867 if( m_simulator->IsRunning() )
868 m_simulator->Stop();
869
870 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
871
872 if( simulatorLock.owns_lock() )
873 {
874 m_ui->OnSimUpdate();
875 m_simulator->Run();
876 }
877 else
878 {
879 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
880 }
881
882 updateInProgress = false;
883}
884
885
886void SIMULATOR_FRAME::onSimReport( wxCommandEvent& aEvent )
887{
888 m_ui->OnSimReport( aEvent.GetString() );
889}
890
891
892void SIMULATOR_FRAME::onExit( wxCommandEvent& aEvent )
893{
894 if( aEvent.GetId() == wxID_EXIT )
895 Kiway().OnKiCadExit();
896
897 if( aEvent.GetId() == wxID_CLOSE )
898 Close( false );
899}
900
901
903{
905 m_workbookModified = true;
906 UpdateTitle();
907}
908
909
910wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
911wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
912
913wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
914wxDEFINE_EVENT( EVT_SIM_FINISHED, wxCommandEvent );
constexpr EDA_IU_SCALE unityScale
Definition: base_units.h:111
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:104
static TOOL_ACTION toggleGrid
Definition: actions.h:191
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION zoomRedo
Definition: actions.h:140
static TOOL_ACTION toggleSimulationSidePanel
Definition: actions.h:158
static TOOL_ACTION toggleConsole
Definition: actions.h:157
static TOOL_ACTION zoomUndo
Definition: actions.h:139
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.
Definition: app_settings.h:92
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...
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.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
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:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
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:285
void OnKiCadExit()
Definition: kiway.cpp:727
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:406
Container for Ngspice simulator settings.
void SetCompatibilityMode(NGSPICE_COMPATIBILITY_MODE aMode)
A singleton reporter that reports to nowhere.
Definition: reporter.h:204
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:125
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:73
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:203
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:370
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:73
Holds all the data relating to one schematic.
Definition: schematic.h:69
void ClearOperatingPoints()
Clear operating points from a .op simulation.
Definition: schematic.h:240
static TOOL_ACTION exportPlotToClipboard
Definition: sch_actions.h:292
static TOOL_ACTION saveWorkbookAs
Definition: sch_actions.h:289
static TOOL_ACTION exportPlotAsCSV
Definition: sch_actions.h:291
static TOOL_ACTION simAnalysisProperties
Definition: sch_actions.h:300
static TOOL_ACTION toggleDottedSecondary
Definition: sch_actions.h:298
static TOOL_ACTION simTune
Definition: sch_actions.h:296
static TOOL_ACTION toggleDarkModePlots
Definition: sch_actions.h:299
static TOOL_ACTION exportPlotAsPNG
Definition: sch_actions.h:290
static TOOL_ACTION exportPlotToSchematic
Definition: sch_actions.h:293
static TOOL_ACTION runSimulation
Definition: sch_actions.h:301
static TOOL_ACTION newAnalysisTab
Definition: sch_actions.h:286
static TOOL_ACTION simProbe
Definition: sch_actions.h:295
static TOOL_ACTION showNetlist
Definition: sch_actions.h:304
static TOOL_ACTION openWorkbook
Definition: sch_actions.h:287
static TOOL_ACTION saveWorkbook
Definition: sch_actions.h:288
static TOOL_ACTION toggleLegend
Definition: sch_actions.h:297
static TOOL_ACTION stopSimulation
Definition: sch_actions.h:302
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Schematic editor (Eeschema) main window.
void RefreshOperatingPointDisplay()
Refresh the display of any operating points.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
bool ReadyToNetlist(const wxString &aAnnotateMessage)
Check if we are ready to write a netlist file for the current schematic.
SCHEMATIC & Schematic() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
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:75
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
T * GetToolbarSettings(const wxString &aFilename)
Return a handle to the given toolbar settings.
Handle actions for the various symbol editor and viewers.
The SIMULATOR_FRAME_UI holds the main user-interface for running simulations.
SIM_TAB * NewSimTab(const wxString &aSimCommand)
Create a new simulation tab for a given simulation type.
void SetUserDefinedSignals(const std::map< int, wxString > &aSignals)
void OnSimRefresh(bool aFinal)
SIM_TAB * GetSimTab(SIM_TYPE aType) const
std::vector< wxString > SimPlotVectors() const
std::vector< wxString > Signals() const
bool SaveWorkbook(const wxString &aPath)
Save plot, signal, cursor, measurement, etc.
SIM_TAB * GetCurrentSimTab() const
Return the currently opened plot panel (or NULL if there is none).
bool LoadWorkbook(const wxString &aPath)
Load plot, signal, cursor, measurement, etc.
bool DarkModePlots() const
const std::map< int, wxString > & UserDefinedSignals()
void AddTrace(const wxString &aName, SIM_TRACE_TYPE aType)
Add a new trace to the current plot.
void SaveSettings(EESCHEMA_SETTINGS *aCfg)
int GetSimTabIndex(SIM_TAB *aPlot) const
void OnSimReport(const wxString &aMsg)
void ApplyPreferences(const SIM_PREFERENCES &aPrefs)
Called when settings are changed via the common Preferences dialog.
void AddTuner(const SCH_SHEET_PATH &aSheetPath, SCH_SYMBOL *aSymbol)
Add a tuner for a symbol.
void LoadSettings(EESCHEMA_SETTINGS *aCfg)
The SIMULATOR_FRAME holds the main user-interface for running simulations.
SIM_TAB * GetCurrentSimTab() const
Return the current tab (or NULL if there is none).
void ShowChangedLanguage() override
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)
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.
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 ToggleSimulationSidePanel()
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
Interface to receive simulation updates from SPICE_SIMULATOR class.
Toolbar configuration for the simulator frame.
static std::shared_ptr< SPICE_SIMULATOR > CreateInstance(const std::string &aName)
mpWindow * GetPlotWin() const
Definition: sim_plot_tab.h:350
bool IsGridShown() const
Definition: sim_plot_tab.h:285
bool GetDottedSecondary() const
Turn on/off the cursor for a particular trace.
Definition: sim_plot_tab.h:329
bool IsLegendShown() const
Definition: sim_plot_tab.h:299
int GetSimOptions() const
Definition: sim_tab.h:55
const wxString & GetSpicePlotName() const
Definition: sim_tab.h:61
void SetLastSchTextSimCommand(const wxString &aCmd)
Definition: sim_tab.h:59
void SetSimCommand(const wxString &aSimCommand)
Definition: sim_tab.h:53
const wxString & GetSimCommand() const
Definition: sim_tab.h:52
wxString GetLastSchTextSimCommand() const
Definition: sim_tab.h:58
void SetSpicePlotName(const wxString &aPlotName)
Definition: sim_tab.h:62
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 the reporter client is non-empty.
void OnSimStateChange(SIMULATOR *aObject, SIM_STATE aNewState) override
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Return simulation type basing on a simulation command directive.
wxString GetWorkbookFilename() const
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:171
TOOL_DISPATCHER * m_toolDispatcher
Definition: tools_holder.h:173
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
virtual void DispatchWxEvent(wxEvent &aEvent)
Process wxEvents (mostly UI events), translate them to TOOL_EVENTs, and make tools handle those.
Master controller class:
Definition: tool_manager.h:62
ACTION_MANAGER * GetActionManager() const
Definition: tool_manager.h:306
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:404
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
void RegisterTool(TOOL_BASE *aTool)
Add a tool to the manager set and sets it up.
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
void InitTools()
Initialize all registered tools.
A modified version of the wxInfoBar class that allows us to:
Definition: wx_infobar.h:76
A wrapper for reporting to a wxString object.
Definition: reporter.h:172
bool HasMessage() const override
Returns true if the reporter client is non-empty.
Definition: reporter.cpp:100
bool HasMessageOfSeverity(int aSeverityMask) const override
Returns true if the reporter has one or more messages matching the specified severity mask.
Definition: reporter.cpp:106
const wxString & GetMessages() const
Definition: reporter.cpp:87
int RedoZoomStackSize() const
Definition: mathplot.h:1269
int UndoZoomStackSize() const
Definition: mathplot.h:1268
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:249
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:221
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:130
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:194
This file is part of the common library.
#define CHECK(x)
#define ENABLE(x)
#define _(s)
@ FRAME_SCH
Definition: frame_type.h:34
@ FRAME_SIMULATOR
Definition: frame_type.h:38
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1071
see class PGM_BASE
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
@ GLOBAL_CLEANUP
@ SPT_VOLTAGE
Definition: sim_types.h:52
@ SPT_CURRENT
Definition: sim_types.h:53
SIM_TYPE
< Possible simulation types
Definition: sim_types.h:32
@ ST_TRAN
Definition: sim_types.h:42
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: app_settings.h:74
Definition of file extensions used in Kicad.