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>
54#include <reporter.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:
74
76 {
77 std::lock_guard lock( m_mutex );
78
79 wxString messages = m_strRep.GetMessages();
80 m_strRep.Clear();
81
82 return messages;
83 }
84
85private:
87};
88
89
91{
92public:
94 m_parent( aParent )
95 {
96 }
97
98 void OnSimStateChange( SIMULATOR* aObject, SIM_STATE aNewState ) override
99 {
100 wxCommandEvent* event = nullptr;
101
102 switch( aNewState )
103 {
104 case SIM_IDLE: event = new wxCommandEvent( EVT_SIM_FINISHED ); break;
105 case SIM_RUNNING: event = new wxCommandEvent( EVT_SIM_STARTED ); break;
106 default: wxFAIL; return;
107 }
108
109 wxQueueEvent( m_parent, event );
110 }
111
112private:
114};
115
116
117BEGIN_EVENT_TABLE( SIMULATOR_FRAME, KIWAY_PLAYER )
119 EVT_MENU( wxID_CLOSE, SIMULATOR_FRAME::onExit )
120END_EVENT_TABLE()
121
122
123SIMULATOR_FRAME::SIMULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
124 KIWAY_PLAYER( aKiway, aParent, FRAME_SIMULATOR, _( "Simulator" ), wxDefaultPosition,
125 wxDefaultSize, wxDEFAULT_FRAME_STYLE, wxT( "simulator" ), unityScale ),
126 m_schematicFrame( nullptr ),
127 m_toolBar( nullptr ),
128 m_ui( nullptr ),
129 m_consoleReporter( nullptr ),
130 m_stateListener( nullptr ),
131 m_simFinished( false ),
132 m_workbookModified( false )
133{
134 m_schematicFrame = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
135 wxASSERT( m_schematicFrame );
136
137 // Give an icon
138 wxIcon icon;
139 icon.CopyFromBitmap( KiBitmap( BITMAPS::simulator ) );
140 SetIcon( icon );
141
142 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
143 SetSizer( mainSizer );
144
145 m_infoBar = new WX_INFOBAR( this );
146 mainSizer->Add( m_infoBar, 0, wxEXPAND, 0 );
147
148 m_tbTopMain = new ACTION_TOOLBAR( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
149 wxAUI_TB_DEFAULT_STYLE|wxAUI_TB_HORZ_LAYOUT|wxAUI_TB_PLAIN_BACKGROUND );
150 m_tbTopMain->Realize();
151 mainSizer->Add( m_tbTopMain, 0, wxEXPAND, 5 );
152
154 mainSizer->Add( m_ui, 1, wxEXPAND, 5 );
155
157
158 if( !m_simulator )
159 throw SIMULATOR_INIT_ERR( "Failed to create simulator instance" );
160
161 LoadSettings( config() );
162
163 std::shared_ptr<NGSPICE_SETTINGS> cfg = Prj().GetProjectFile().m_SchematicSettings->m_NgspiceSettings;
164
165 if( cfg->GetWorkbookFilename().IsEmpty() )
166 cfg->SetCompatibilityMode( NGSPICE_COMPATIBILITY_MODE::LT_PSPICE );
167
168 m_simulator->Init();
169
172 m_simulator->SetReporter( m_consoleReporter );
173 m_simulator->SetSimStateListener( m_stateListener );
174
175 m_circuitModel = std::make_shared<SPICE_CIRCUIT_MODEL>( &m_schematicFrame->Schematic(),
176 &m_schematicFrame->Kiway() );
177
178 setupTools();
180
181 // Set the tool manager for the toolbar here, since the tool manager didn't exist when the toolbar
182 // was created.
183 m_tbTopMain->SetToolManager( m_toolManager );
184
189
190 Bind( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIMULATOR_FRAME::onExit ), this, wxID_EXIT );
191
192 Bind( EVT_SIM_UPDATE, &SIMULATOR_FRAME::onUpdateSim, this );
193 Bind( EVT_SIM_STARTED, &SIMULATOR_FRAME::onSimStarted, this );
194 Bind( EVT_SIM_FINISHED, &SIMULATOR_FRAME::onSimFinished, this );
195
196 // Ensure new items are taken in account by sizers:
197 Layout();
198
199 // resize the subwindows size. At least on Windows, calling wxSafeYield before
200 // resizing the subwindows forces the wxSplitWindows size events automatically generated
201 // by wxWidgets to be executed before our resize code.
202 // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
203 // events
204 wxSafeYield();
205 m_ui->SetSubWindowsSashSize();
206
207 // Ensure the window is on top
208 Raise();
209
210 m_ui->InitWorkbook();
211 m_ui->FlushSimConsole();
212 UpdateTitle();
213}
214
215
217{
218 NULL_REPORTER devnull;
219
220 m_simulator->Attach( nullptr, wxEmptyString, 0, wxEmptyString, devnull );
221 m_simulator->SetSimStateListener( nullptr );
222 m_simulator->SetReporter( nullptr );
223 delete m_stateListener;
224 delete m_consoleReporter;
225}
226
227
229{
230 // Create the manager
232 m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
233
235
236 // Attach the events to the tool dispatcher
238 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
239
240 // Register tools
241 m_toolManager->RegisterTool( new COMMON_CONTROL );
242 m_toolManager->RegisterTool( new SIMULATOR_CONTROL );
243 m_toolManager->InitTools();
244}
245
246
248{
250
251 UpdateTitle();
252
253 m_ui->ShowChangedLanguage();
254}
255
256
258{
259 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg ) )
260 {
262 m_ui->LoadSettings( cfg );
263 }
264
265 if( m_simulator )
267}
268
269
271{
272 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg ) )
273 {
275 m_ui->SaveSettings( cfg );
276 }
277
279
280 if( m_schematicFrame && modified )
281 m_schematicFrame->OnModify();
282}
283
284
286{
288
290 m_ui->ApplyPreferences( cfg->m_Simulator.preferences );
291}
292
293
295{
297 return &cfg->m_Simulator.window;
298
299 wxFAIL_MSG( wxT( "SIMULATOR not running with EESCHEMA_SETTINGS" ) );
300 return &aCfg->m_Window; // non-null fail-safe
301}
302
303
305{
306 if( m_ui->GetCurrentSimTab() )
307 return m_ui->GetCurrentSimTab()->GetSimCommand();
308 else
309 return m_circuitModel->GetSchTextSimCommand();
310}
311
312
317
318
320{
321 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
322 return simTab->GetSimOptions();
323 else
325}
326
327
329{
330 bool unsaved = true;
331 bool readOnly = false;
332 wxString title;
333 std::shared_ptr<NGSPICE_SETTINGS> cfg = Prj().GetProjectFile().m_SchematicSettings->m_NgspiceSettings;
334 wxFileName filename = Prj().AbsolutePath( cfg->GetWorkbookFilename() );
335
336 if( filename.IsOk() && filename.FileExists() )
337 {
338 unsaved = false;
339 readOnly = !filename.IsFileWritable();
340 }
341
343 title = wxT( "*" ) + filename.GetName();
344 else
345 title = filename.GetName();
346
347 if( readOnly )
348 title += wxS( " " ) + _( "[Read Only]" );
349
350 if( unsaved )
351 title += wxS( " " ) + _( "[Unsaved]" );
352
353 title += wxT( " \u2014 " ) + _( "SPICE Simulator" );
354
355 SetTitle( title );
356}
357
358
359// Don't let the dialog grow too tall: you may not be able to get to the OK button
360#define MAX_MESSAGES 20
361
363{
364 if( !aReporter.HasMessage() )
365 return;
366
367 wxArrayString lines = wxSplit( aReporter.GetMessages(), '\n' );
368
369 if( lines.size() > MAX_MESSAGES )
370 {
371 lines.RemoveAt( MAX_MESSAGES, lines.size() - MAX_MESSAGES );
372 lines.Add( wxS( "..." ) );
373 }
374
376 {
377 DisplayErrorMessage( this, _( "Errors during netlist generation." ),
378 wxJoin( lines, '\n' ) );
379 }
380 else if( aReporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) )
381 {
382 DisplayInfoMessage( this, _( "Warnings during netlist generation." ),
383 wxJoin( lines, '\n' ) );
384 }
385}
386
387
388bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
389{
390 s_reporter.Clear();
391
392 if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) ) )
393 return false;
394
395 m_schematicFrame->PrepareForNetlist();
396
397 bool success = m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions,
398 Prj().GetProjectPath(), s_reporter );
399
400 m_schematicFrame->RefreshConnectivity( true );
402
403 return success;
404}
405
406
407void SIMULATOR_FRAME::ReloadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
408{
409 s_reporter.Clear();
410
411 m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, Prj().GetProjectPath(),
412 s_reporter );
413
414 m_schematicFrame->RefreshConnectivity( true );
416}
417
418
420{
421 wxString oldPlotName = aSimTab->GetSpicePlotName();
422
423 if( oldPlotName.IsEmpty() )
424 return;
425
426 // A run may report a plot that another tab still owns (e.g. an FFT deriving from a TRAN plot,
427 // or an aborted run that produced nothing new). Never destroy such a shared plot; just forget
428 // this tab's reference to it.
429 if( m_ui->IsPlotOwnedByOtherTab( aSimTab, oldPlotName ) )
430 {
431 aSimTab->SetSpicePlotName( wxEmptyString );
432 return;
433 }
434
435 // A noise run produces a pair of plots (odd spectral density noiseN, even integrated noiseN+1).
436 // Destroy both regardless of which of the pair the tab happened to record.
437 long noiseNumber = 0;
438
439 if( oldPlotName.StartsWith( wxS( "noise" ) ) && oldPlotName.Mid( 5 ).ToLong( &noiseNumber ) )
440 {
441 long spectral = ( noiseNumber % 2 == 0 ) ? noiseNumber - 1 : noiseNumber;
442
443 m_simulator->Command( wxString::Format( wxT( "destroy noise%ld" ), spectral ).ToStdString() );
444 m_simulator->Command(
445 wxString::Format( wxT( "destroy noise%ld" ), spectral + 1 ).ToStdString() );
446 }
447 else
448 {
449 m_simulator->Command( "destroy " + oldPlotName.ToStdString() );
450 }
451
452 aSimTab->SetSpicePlotName( wxEmptyString );
453}
454
455
457{
458 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
459
460 if( !simTab )
461 return;
462
463 if( simTab->GetSimCommand().Upper().StartsWith( wxT( "FFT" ) )
464 || simTab->GetSimCommand().Upper().Contains( wxT( "\nFFT" ) ) )
465 {
466 wxString tranSpicePlot;
467
468 if( SIM_TAB* tranPlotTab = m_ui->GetSimTab( ST_TRAN ) )
469 tranSpicePlot = tranPlotTab->GetSpicePlotName();
470
471 if( tranSpicePlot.IsEmpty() )
472 {
473 DisplayErrorMessage( this, _( "You must run a TRAN simulation first; its results "
474 "will be used for the fast Fourier transform." ) );
475 }
476 else
477 {
478 // Free the tab's previous FFT plot before recomputing; destroyTabPlot() leaves the
479 // shared TRAN plot it derives from untouched.
480 destroyTabPlot( simTab );
481
482 m_simulator->Command( "setplot " + tranSpicePlot.ToStdString() );
483
484 wxArrayString commands = wxSplit( simTab->GetSimCommand(), '\n' );
485
486 for( const wxString& command : commands )
487 {
488 wxBusyCursor wait;
489 m_simulator->Command( command.ToStdString() );
490 }
491
492 simTab->SetSpicePlotName( m_simulator->CurrentPlotName() );
493 m_ui->OnSimRefresh( true );
494
495#if 0
496 m_simulator->Command( "setplot" ); // Print available plots to console
497 m_simulator->Command( "display" ); // Print vectors in current plot to console
498#endif
499 }
500
501 return;
502 }
503 else
504 {
505 if( m_ui->GetSimTabIndex( simTab ) == 0
506 && m_circuitModel->GetSchTextSimCommand() != simTab->GetLastSchTextSimCommand() )
507 {
508 if( simTab->GetLastSchTextSimCommand().IsEmpty()
509 || IsOK( this, _( "Schematic sheet simulation command directive has changed. "
510 "Do you wish to update the Simulation Command?" ) ) )
511 {
512 simTab->SetSimCommand( m_circuitModel->GetSchTextSimCommand() );
513 simTab->SetLastSchTextSimCommand( simTab->GetSimCommand() );
514 OnModify();
515 }
516 }
517 }
518
519 if( !LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() ) )
520 return;
521
522 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
523
524 if( simulatorLock.owns_lock() )
525 {
526 m_simFinished = false;
527
528 // Free this tab's previous plot only once the rerun is committed, so a failed netlist or
529 // a busy simulator leaves the existing results intact. Other tabs' plots must survive
530 // (e.g. an FFT consumes a prior TRAN plot).
531 destroyTabPlot( simTab );
532
533 m_ui->OnSimUpdate();
534 m_simulator->Run();
535
536 // Netlist from schematic may have changed; update signals list, measurements list,
537 // etc.
538 m_ui->OnPlotSettingsChanged();
539 }
540 else
541 {
542 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
543 }
544}
545
546
547SIM_TAB* SIMULATOR_FRAME::NewSimTab( const wxString& aSimCommand )
548{
549 return m_ui->NewSimTab( aSimCommand );
550}
551
552
553const std::vector<wxString> SIMULATOR_FRAME::SimPlotVectors()
554{
555 return m_ui->SimPlotVectors();
556}
557
558
559const std::vector<wxString> SIMULATOR_FRAME::Signals()
560{
561 return m_ui->Signals();
562}
563
564
565const std::map<int, wxString>& SIMULATOR_FRAME::UserDefinedSignals()
566{
567 return m_ui->UserDefinedSignals();
568}
569
570
571void SIMULATOR_FRAME::SetUserDefinedSignals( const std::map<int, wxString>& aSignals )
572{
573 m_ui->SetUserDefinedSignals( aSignals );
574}
575
576
577void SIMULATOR_FRAME::AddVoltageTrace( const wxString& aNetName )
578{
579 m_ui->AddTrace( aNetName, SPT_VOLTAGE );
580}
581
582
583void SIMULATOR_FRAME::AddCurrentTrace( const wxString& aDeviceName )
584{
585 m_ui->AddTrace( aDeviceName, SPT_CURRENT );
586}
587
588
589void SIMULATOR_FRAME::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol )
590{
591 m_ui->AddTuner( aSheetPath, aSymbol );
592}
593
594
596{
597 return m_ui->GetCurrentSimTab();
598}
599
600
601bool SIMULATOR_FRAME::LoadWorkbook( const wxString& aPath )
602{
603 if( m_ui->LoadWorkbook( aPath ) )
604 {
605 UpdateTitle();
606
607 // Successfully loading a workbook does not count as modifying it. Clear the modified
608 // flag after all the EVT_WORKBOOK_MODIFIED events have been processed.
609 CallAfter( [this]()
610 {
611 m_workbookModified = false;
612 } );
613
614 return true;
615 }
616
617 DisplayErrorMessage( this, wxString::Format( _( "Unable to load or parse file %s" ), aPath ) );
618 return false;
619}
620
621
622bool SIMULATOR_FRAME::SaveWorkbook( const wxString& aPath )
623{
624 if( m_ui->SaveWorkbook( aPath ) )
625 {
626 m_workbookModified = false;
627 UpdateTitle();
628
629 return true;
630 }
631
632 return false;
633}
634
635
637{
638 m_ui->ToggleSimConsole();
639}
640
641
643{
644 m_ui->ToggleSimSidePanel();
645}
646
647
649{
650 m_ui->ToggleSmithChart();
651}
652
653
655{
656 m_ui->ToggleDarkModePlots();
657}
658
659
661{
662 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
663 DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() );
664
665 s_reporter.Clear();
666
667 if( !simTab )
668 return false;
669
671 s_reporter );
672
674
675 dlg.SetSimCommand( simTab->GetSimCommand() );
676 dlg.SetSimOptions( simTab->GetSimOptions() );
677 dlg.SetPlotSettings( simTab );
678
679 if( dlg.ShowModal() == wxID_OK )
680 {
681 simTab->SetSimCommand( dlg.GetSimCommand() );
682 dlg.ApplySettings( simTab );
683 m_ui->OnPlotSettingsChanged();
684 OnModify();
685 return true;
686 }
687
688 return false;
689}
690
691
692bool SIMULATOR_FRAME::canCloseWindow( wxCloseEvent& aEvent )
693{
695 {
696 wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
697
698 if( filename.GetName().IsEmpty() )
699 {
700 if( Prj().GetProjectName().IsEmpty() )
701 filename.SetFullName( wxT( "noname.wbk" ) );
702 else
703 filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
704 }
705
706 return HandleUnsavedChanges( this, _( "Save changes to workbook?" ),
707 [&]() -> bool
708 {
709 return SaveWorkbook( Prj().AbsolutePath( filename.GetFullName() ) );
710 } );
711 }
712
713 return true;
714}
715
716
718{
719 if( m_simulator->IsRunning() )
720 m_simulator->Stop();
721
722 // Prevent memory leak on exit by deleting all simulation vectors
723 m_simulator->Clean();
724
725 // Cancel a running simProbe or simTune tool
726 m_schematicFrame->GetToolManager()->PostAction( ACTIONS::cancelInteractive );
727
728 SaveSettings( config() );
729
730 m_simulator->Settings().reset();
731
732 Destroy();
733}
734
735
737{
739
740 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
741 wxASSERT( mgr );
742
743 auto showGridCondition =
744 [this]( const SELECTION& aSel )
745 {
746 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
747 return plotTab && plotTab->IsGridShown();
748 };
749
750 auto showLegendCondition =
751 [this]( const SELECTION& aSel )
752 {
753 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
754 return plotTab && plotTab->IsLegendShown();
755 };
756
757 auto showDottedCondition =
758 [this]( const SELECTION& aSel )
759 {
760 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
761 return plotTab && plotTab->GetDottedSecondary();
762 };
763
764 auto darkModePlotCondition =
765 [this]( const SELECTION& aSel )
766 {
767 return m_ui->DarkModePlots();
768 };
769
770 auto smithChartCondition =
771 [this]( const SELECTION& aSel )
772 {
773 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
774 return plotTab && plotTab->IsSmithMode();
775 };
776
777 auto haveSPPlot =
778 [this]( const SELECTION& aSel )
779 {
780 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
781 return plotTab && plotTab->GetSimType() == ST_SP;
782 };
783
784 auto simRunning =
785 [this]( const SELECTION& aSel )
786 {
787 return m_simulator && m_simulator->IsRunning();
788 };
789
790 auto simFinished =
791 [this]( const SELECTION& aSel )
792 {
793 return m_simFinished;
794 };
795
796 auto haveSim =
797 [this]( const SELECTION& aSel )
798 {
799 return GetCurrentSimTab() != nullptr;
800 };
801
802 auto havePlot =
803 [this]( const SELECTION& aSel )
804 {
805 return dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() ) != nullptr;
806 };
807
808 auto haveZoomUndo =
809 [this]( const SELECTION& aSel )
810 {
811 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
812 return plotTab && plotTab->GetPlotWin()->UndoZoomStackSize() > 0;
813 };
814
815 auto haveZoomRedo =
816 [this]( const SELECTION& aSel )
817 {
818 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
819 return plotTab && plotTab->GetPlotWin()->RedoZoomStackSize() > 0;
820 };
821
822 // clang-format off
823 auto isSimConsoleShown =
824 [this]( const SELECTION& aSel )
825 {
826 bool aBool = false;
827
828 if( m_simulator )
829 return m_ui->IsSimConsoleShown();
830
831 return aBool;
832 };
833
834 auto isSimSidePanelShown =
835 [this]( const SELECTION& aSel )
836 {
837 bool aBool = false;
838
839 if( m_simulator )
840 return m_ui->IsSimSidePanelShown();
841
842 return aBool;
843 };
844 // clang-format on
845
846#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
847#define CHECK( x ) ACTION_CONDITIONS().Check( x )
848 // clang-format off
852
857
858 mgr->SetConditions( SCH_ACTIONS::toggleSimSidePanel, CHECK( isSimSidePanelShown ) );
859 mgr->SetConditions( SCH_ACTIONS::toggleSimConsole, CHECK( isSimConsoleShown ) );
860
861 mgr->SetConditions( ACTIONS::zoomUndo, ENABLE( haveZoomUndo ) );
862 mgr->SetConditions( ACTIONS::zoomRedo, ENABLE( haveZoomRedo ) );
863 mgr->SetConditions( SCH_ACTIONS::toggleGrid, CHECK( showGridCondition ) );
864 mgr->SetConditions( SCH_ACTIONS::toggleLegend, CHECK( showLegendCondition ) );
865 mgr->SetConditions( SCH_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) );
867 ACTION_CONDITIONS().Check( smithChartCondition ).Enable( haveSPPlot ) );
868 mgr->SetConditions( SCH_ACTIONS::toggleDarkModePlots, CHECK( darkModePlotCondition ) );
869
872 mgr->SetConditions( SCH_ACTIONS::runSimulation, ENABLE( !simRunning ) );
873 mgr->SetConditions( SCH_ACTIONS::stopSimulation, ENABLE( simRunning ) );
874 mgr->SetConditions( SCH_ACTIONS::simProbe, ENABLE( simFinished ) );
875 mgr->SetConditions( SCH_ACTIONS::simTune, ENABLE( simFinished ) );
877 // clang-format on
878#undef CHECK
879#undef ENABLE
880}
881
882
883void SIMULATOR_FRAME::onSimStarted( wxCommandEvent& aEvent )
884{
885 SetCursor( wxCURSOR_ARROWWAIT );
886}
887
888
890{
891 return m_consoleReporter->TakePendingMessages();
892}
893
894
895void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
896{
897 if( IsClosing() )
898 return;
899
900 // Sometimes (for instance with a directive like wrdata my_file.csv "my_signal")
901 // the simulator is in idle state (simulation is finished), but still running, during
902 // the time the file is written. So gives a slice of time to fully finish the work:
903 if( m_simulator->IsRunning() )
904 {
905 int max_time = 40; // For a max timeout = 2s
906
907 do
908 {
909 wxMilliSleep( 50 );
910 wxYield();
911
912 if( max_time )
913 max_time--;
914
915 } while( max_time && m_simulator->IsRunning() );
916 }
917
918 // ensure the shown cursor is the default cursor, not the wxCURSOR_ARROWWAIT set when
919 // staring the simulator in onSimStarted:
920 SetCursor( wxNullCursor );
921
922 // Is a warning message useful if the simulatior is still running?
923 SCHEMATIC& schematic = m_schematicFrame->Schematic();
924 schematic.ClearOperatingPoints();
925
926 m_simFinished = true;
927
928 m_ui->OnSimRefresh( true );
929
930 m_schematicFrame->RefreshOperatingPointDisplay();
931 m_schematicFrame->GetCanvas()->Refresh();
932}
933
934
935void SIMULATOR_FRAME::onUpdateSim( wxCommandEvent& aEvent )
936{
937 static bool updateInProgress = false;
938
939 // skip update when events are triggered too often and previous call didn't end yet
940 if( updateInProgress )
941 return;
942
943 updateInProgress = true;
944
945 if( m_simulator->IsRunning() )
946 m_simulator->Stop();
947
948 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
949
950 if( simulatorLock.owns_lock() )
951 {
952 // Tuner drags and multi-run steps rerun through here without going through
953 // StartSimulation(), so free the prior plot to keep repeated updates from leaking. A
954 // multi-run step's data is already copied into m_multiRunState before the next step.
955 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
956 destroyTabPlot( simTab );
957
958 m_ui->OnSimUpdate();
959 m_simulator->Run();
960 }
961 else
962 {
963 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
964 }
965
966 updateInProgress = false;
967}
968
969
970void SIMULATOR_FRAME::onExit( wxCommandEvent& aEvent )
971{
972 if( aEvent.GetId() == wxID_EXIT )
973 Kiway().OnKiCadExit();
974
975 if( aEvent.GetId() == wxID_CLOSE )
976 Close( false );
977}
978
979
986
987
988wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
989
990wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
991wxDEFINE_EVENT( EVT_SIM_FINISHED, wxCommandEvent );
constexpr EDA_IU_SCALE unityScale
Definition base_units.h:131
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.
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...
bool IsClosing() const
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:348
void OnKiCadExit()
Definition kiway.cpp:790
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:267
SCHEMATIC_SETTINGS * m_SchematicSettings
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
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:152
virtual bool HasMessage() const
Returns true if any messages were reported.
Definition reporter.h:143
std::shared_ptr< NGSPICE_SETTINGS > m_NgspiceSettings
Ngspice simulator settings.
Holds all the data relating to one schematic.
Definition schematic.h:149
void ClearOperatingPoints()
Clear operating points from a .op simulation.
Definition schematic.h:418
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 toggleSmithChart
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:73
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.
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
wxString TakeSimReportMessages()
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.
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()
SIM_FRAME_STATE_LISTENER * m_stateListener
void ToggleSmithChart()
Toggle the current S-parameter tab between Smith chart and amplitude/phase views.
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.
SIM_CONSOLE_REPORTER * m_consoleReporter
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...
static std::shared_ptr< SPICE_SIMULATOR > CreateInstance(const std::string &aName)
Create a simulator instance of particular type (currently only ngspice is handled)
WX_STRING_REPORTER m_strRep
SIM_FRAME_STATE_LISTENER(SIMULATOR_FRAME *aParent)
void OnSimStateChange(SIMULATOR *aObject, SIM_STATE aNewState) override
mpWindow * GetPlotWin() const
Getter for the default view's math plot window (back-compat for zoom undo/redo, export).
bool IsGridShown() const
bool GetDottedSecondary() const
bool IsLegendShown() const
bool IsSmithMode() const
Interface to receive simulation state transitions from SPICE_SIMULATOR.
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
SIM_TYPE GetSimType() const
Definition sim_tab.cpp:71
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
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Return simulation type basing on a simulation command directive.
SYNC_REPORTER(REPORTER &aReporter)
Definition reporter.h:186
std::mutex m_mutex
Definition reporter.h:210
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:76
A wrapper for reporting to a wxString object.
Definition reporter.h:242
const wxString & GetMessages() const
Definition reporter.cpp:188
int RedoZoomStackSize() const
Definition mathplot.h:1332
int UndoZoomStackSize() const
Definition mathplot.h:1331
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)
static std::string ToStdString(const wxString &aStr)
#define _(s)
@ FRAME_SCH
Definition frame_type.h:30
@ FRAME_SIMULATOR
Definition frame_type.h:34
PROJECT & Prj()
Definition kicad.cpp:733
EVT_MENU(ID_COMPARE_PROJECT_BRANCHES, KICAD_MANAGER_FRAME::OnCompareProjectBranches) KICAD_MANAGER_FRAME
see class PGM_BASE
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
@ SPT_VOLTAGE
Definition sim_types.h:51
@ SPT_CURRENT
Definition sim_types.h:52
SIM_TYPE
Possible simulation types.
Definition sim_types.h:31
@ ST_SP
Definition sim_types.h:42
@ ST_TRAN
Definition sim_types.h:41
wxDEFINE_EVENT(EVT_SIM_UPDATE, wxCommandEvent)
#define MAX_MESSAGES
static WX_STRING_REPORTER s_reporter
KIWAY Kiway(KFCTL_STANDALONE)
SIM_STATE
@ SIM_IDLE
@ SIM_RUNNING
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
Store the common settings that are saved and loaded for each window / frame.
Definition of file extensions used in Kicad.