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
177 setupTools();
179
180 // Set the tool manager for the toolbar here, since the tool manager didn't exist when the toolbar
181 // was created.
182 m_tbTopMain->SetToolManager( m_toolManager );
183
188
189 Bind( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIMULATOR_FRAME::onExit ), this, wxID_EXIT );
190
191 Bind( EVT_SIM_UPDATE, &SIMULATOR_FRAME::onUpdateSim, this );
192 Bind( EVT_SIM_STARTED, &SIMULATOR_FRAME::onSimStarted, this );
193 Bind( EVT_SIM_FINISHED, &SIMULATOR_FRAME::onSimFinished, this );
194
195 // Ensure new items are taken in account by sizers:
196 Layout();
197
198 // resize the subwindows size. At least on Windows, calling wxSafeYield before
199 // resizing the subwindows forces the wxSplitWindows size events automatically generated
200 // by wxWidgets to be executed before our resize code.
201 // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
202 // events
203 wxSafeYield();
204 m_ui->SetSubWindowsSashSize();
205
206 // Ensure the window is on top
207 Raise();
208
209 m_ui->InitWorkbook();
210 m_ui->FlushSimConsole();
211 UpdateTitle();
212}
213
214
216{
217 NULL_REPORTER devnull;
218
219 m_simulator->Attach( nullptr, wxEmptyString, 0, wxEmptyString, devnull );
220 m_simulator->SetSimStateListener( nullptr );
221 m_simulator->SetReporter( nullptr );
222 delete m_stateListener;
223 delete m_consoleReporter;
224}
225
226
228{
229 // Create the manager
231 m_toolManager->SetEnvironment( nullptr, nullptr, nullptr, config(), this );
232
234
235 // Attach the events to the tool dispatcher
237 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
238
239 // Register tools
240 m_toolManager->RegisterTool( new COMMON_CONTROL );
241 m_toolManager->RegisterTool( new SIMULATOR_CONTROL );
242 m_toolManager->InitTools();
243}
244
245
247{
249
250 UpdateTitle();
251
252 m_ui->ShowChangedLanguage();
253}
254
255
257{
258 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg ) )
259 {
261 m_ui->LoadSettings( cfg );
262 }
263
264 if( m_simulator )
266}
267
268
270{
271 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg ) )
272 {
274 m_ui->SaveSettings( cfg );
275 }
276
278
279 if( m_schematicFrame && modified )
280 m_schematicFrame->OnModify();
281}
282
283
285{
287
289 m_ui->ApplyPreferences( cfg->m_Simulator.preferences );
290}
291
292
294{
296 return &cfg->m_Simulator.window;
297
298 wxFAIL_MSG( wxT( "SIMULATOR not running with EESCHEMA_SETTINGS" ) );
299 return &aCfg->m_Window; // non-null fail-safe
300}
301
302
304{
305 if( m_ui->GetCurrentSimTab() )
306 return m_ui->GetCurrentSimTab()->GetSimCommand();
307 else
308 return m_circuitModel->GetSchTextSimCommand();
309}
310
311
316
317
319{
320 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
321 return simTab->GetSimOptions();
322 else
324}
325
326
328{
329 bool unsaved = true;
330 bool readOnly = false;
331 wxString title;
332 std::shared_ptr<NGSPICE_SETTINGS> cfg = Prj().GetProjectFile().m_SchematicSettings->m_NgspiceSettings;
333 wxFileName filename = Prj().AbsolutePath( cfg->GetWorkbookFilename() );
334
335 if( filename.IsOk() && filename.FileExists() )
336 {
337 unsaved = false;
338 readOnly = !filename.IsFileWritable();
339 }
340
342 title = wxT( "*" ) + filename.GetName();
343 else
344 title = filename.GetName();
345
346 if( readOnly )
347 title += wxS( " " ) + _( "[Read Only]" );
348
349 if( unsaved )
350 title += wxS( " " ) + _( "[Unsaved]" );
351
352 title += wxT( " \u2014 " ) + _( "SPICE Simulator" );
353
354 SetTitle( title );
355}
356
357
358// Don't let the dialog grow too tall: you may not be able to get to the OK button
359#define MAX_MESSAGES 20
360
362{
363 if( !aReporter.HasMessage() )
364 return;
365
366 wxArrayString lines = wxSplit( aReporter.GetMessages(), '\n' );
367
368 if( lines.size() > MAX_MESSAGES )
369 {
370 lines.RemoveAt( MAX_MESSAGES, lines.size() - MAX_MESSAGES );
371 lines.Add( wxS( "..." ) );
372 }
373
375 {
376 DisplayErrorMessage( this, _( "Errors during netlist generation." ),
377 wxJoin( lines, '\n' ) );
378 }
379 else if( aReporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) )
380 {
381 DisplayInfoMessage( this, _( "Warnings during netlist generation." ),
382 wxJoin( lines, '\n' ) );
383 }
384}
385
386
387bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
388{
389 s_reporter.Clear();
390
391 if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) ) )
392 return false;
393
394 // If we are using the new connectivity, make sure that we do a full-rebuild
395 if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
396 m_schematicFrame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
397
398 bool success = m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions,
399 Prj().GetProjectPath(), s_reporter );
400
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
415}
416
417
419{
420 wxString oldPlotName = aSimTab->GetSpicePlotName();
421
422 if( oldPlotName.IsEmpty() )
423 return;
424
425 // A run may report a plot that another tab still owns (e.g. an FFT deriving from a TRAN plot,
426 // or an aborted run that produced nothing new). Never destroy such a shared plot; just forget
427 // this tab's reference to it.
428 if( m_ui->IsPlotOwnedByOtherTab( aSimTab, oldPlotName ) )
429 {
430 aSimTab->SetSpicePlotName( wxEmptyString );
431 return;
432 }
433
434 // A noise run produces a pair of plots (odd spectral density noiseN, even integrated noiseN+1).
435 // Destroy both regardless of which of the pair the tab happened to record.
436 long noiseNumber = 0;
437
438 if( oldPlotName.StartsWith( wxS( "noise" ) ) && oldPlotName.Mid( 5 ).ToLong( &noiseNumber ) )
439 {
440 long spectral = ( noiseNumber % 2 == 0 ) ? noiseNumber - 1 : noiseNumber;
441
442 m_simulator->Command( wxString::Format( wxT( "destroy noise%ld" ), spectral ).ToStdString() );
443 m_simulator->Command(
444 wxString::Format( wxT( "destroy noise%ld" ), spectral + 1 ).ToStdString() );
445 }
446 else
447 {
448 m_simulator->Command( "destroy " + oldPlotName.ToStdString() );
449 }
450
451 aSimTab->SetSpicePlotName( wxEmptyString );
452}
453
454
456{
457 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
458
459 if( !simTab )
460 return;
461
462 if( simTab->GetSimCommand().Upper().StartsWith( wxT( "FFT" ) )
463 || simTab->GetSimCommand().Upper().Contains( wxT( "\nFFT" ) ) )
464 {
465 wxString tranSpicePlot;
466
467 if( SIM_TAB* tranPlotTab = m_ui->GetSimTab( ST_TRAN ) )
468 tranSpicePlot = tranPlotTab->GetSpicePlotName();
469
470 if( tranSpicePlot.IsEmpty() )
471 {
472 DisplayErrorMessage( this, _( "You must run a TRAN simulation first; its results "
473 "will be used for the fast Fourier transform." ) );
474 }
475 else
476 {
477 // Free the tab's previous FFT plot before recomputing; destroyTabPlot() leaves the
478 // shared TRAN plot it derives from untouched.
479 destroyTabPlot( simTab );
480
481 m_simulator->Command( "setplot " + tranSpicePlot.ToStdString() );
482
483 wxArrayString commands = wxSplit( simTab->GetSimCommand(), '\n' );
484
485 for( const wxString& command : commands )
486 {
487 wxBusyCursor wait;
488 m_simulator->Command( command.ToStdString() );
489 }
490
491 simTab->SetSpicePlotName( m_simulator->CurrentPlotName() );
492 m_ui->OnSimRefresh( true );
493
494#if 0
495 m_simulator->Command( "setplot" ); // Print available plots to console
496 m_simulator->Command( "display" ); // Print vectors in current plot to console
497#endif
498 }
499
500 return;
501 }
502 else
503 {
504 if( m_ui->GetSimTabIndex( simTab ) == 0
505 && m_circuitModel->GetSchTextSimCommand() != simTab->GetLastSchTextSimCommand() )
506 {
507 if( simTab->GetLastSchTextSimCommand().IsEmpty()
508 || IsOK( this, _( "Schematic sheet simulation command directive has changed. "
509 "Do you wish to update the Simulation Command?" ) ) )
510 {
511 simTab->SetSimCommand( m_circuitModel->GetSchTextSimCommand() );
512 simTab->SetLastSchTextSimCommand( simTab->GetSimCommand() );
513 OnModify();
514 }
515 }
516 }
517
518 if( !LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() ) )
519 return;
520
521 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
522
523 if( simulatorLock.owns_lock() )
524 {
525 m_simFinished = false;
526
527 // Free this tab's previous plot only once the rerun is committed, so a failed netlist or
528 // a busy simulator leaves the existing results intact. Other tabs' plots must survive
529 // (e.g. an FFT consumes a prior TRAN plot).
530 destroyTabPlot( simTab );
531
532 m_ui->OnSimUpdate();
533 m_simulator->Run();
534
535 // Netlist from schematic may have changed; update signals list, measurements list,
536 // etc.
537 m_ui->OnPlotSettingsChanged();
538 }
539 else
540 {
541 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
542 }
543}
544
545
546SIM_TAB* SIMULATOR_FRAME::NewSimTab( const wxString& aSimCommand )
547{
548 return m_ui->NewSimTab( aSimCommand );
549}
550
551
552const std::vector<wxString> SIMULATOR_FRAME::SimPlotVectors()
553{
554 return m_ui->SimPlotVectors();
555}
556
557
558const std::vector<wxString> SIMULATOR_FRAME::Signals()
559{
560 return m_ui->Signals();
561}
562
563
564const std::map<int, wxString>& SIMULATOR_FRAME::UserDefinedSignals()
565{
566 return m_ui->UserDefinedSignals();
567}
568
569
570void SIMULATOR_FRAME::SetUserDefinedSignals( const std::map<int, wxString>& aSignals )
571{
572 m_ui->SetUserDefinedSignals( aSignals );
573}
574
575
576void SIMULATOR_FRAME::AddVoltageTrace( const wxString& aNetName )
577{
578 m_ui->AddTrace( aNetName, SPT_VOLTAGE );
579}
580
581
582void SIMULATOR_FRAME::AddCurrentTrace( const wxString& aDeviceName )
583{
584 m_ui->AddTrace( aDeviceName, SPT_CURRENT );
585}
586
587
588void SIMULATOR_FRAME::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol )
589{
590 m_ui->AddTuner( aSheetPath, aSymbol );
591}
592
593
595{
596 return m_ui->GetCurrentSimTab();
597}
598
599
600bool SIMULATOR_FRAME::LoadWorkbook( const wxString& aPath )
601{
602 if( m_ui->LoadWorkbook( aPath ) )
603 {
604 UpdateTitle();
605
606 // Successfully loading a workbook does not count as modifying it. Clear the modified
607 // flag after all the EVT_WORKBOOK_MODIFIED events have been processed.
608 CallAfter( [this]()
609 {
610 m_workbookModified = false;
611 } );
612
613 return true;
614 }
615
616 DisplayErrorMessage( this, wxString::Format( _( "Unable to load or parse file %s" ), aPath ) );
617 return false;
618}
619
620
621bool SIMULATOR_FRAME::SaveWorkbook( const wxString& aPath )
622{
623 if( m_ui->SaveWorkbook( aPath ) )
624 {
625 m_workbookModified = false;
626 UpdateTitle();
627
628 return true;
629 }
630
631 return false;
632}
633
634
636{
637 m_ui->ToggleSimConsole();
638}
639
640
642{
643 m_ui->ToggleSimSidePanel();
644}
645
646
648{
649 m_ui->ToggleSmithChart();
650}
651
652
654{
655 m_ui->ToggleDarkModePlots();
656}
657
658
660{
661 SIM_TAB* simTab = m_ui->GetCurrentSimTab();
662 DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() );
663
664 s_reporter.Clear();
665
666 if( !simTab )
667 return false;
668
670 s_reporter );
671
673
674 dlg.SetSimCommand( simTab->GetSimCommand() );
675 dlg.SetSimOptions( simTab->GetSimOptions() );
676 dlg.SetPlotSettings( simTab );
677
678 if( dlg.ShowModal() == wxID_OK )
679 {
680 simTab->SetSimCommand( dlg.GetSimCommand() );
681 dlg.ApplySettings( simTab );
682 m_ui->OnPlotSettingsChanged();
683 OnModify();
684 return true;
685 }
686
687 return false;
688}
689
690
691bool SIMULATOR_FRAME::canCloseWindow( wxCloseEvent& aEvent )
692{
694 {
695 wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
696
697 if( filename.GetName().IsEmpty() )
698 {
699 if( Prj().GetProjectName().IsEmpty() )
700 filename.SetFullName( wxT( "noname.wbk" ) );
701 else
702 filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
703 }
704
705 return HandleUnsavedChanges( this, _( "Save changes to workbook?" ),
706 [&]() -> bool
707 {
708 return SaveWorkbook( Prj().AbsolutePath( filename.GetFullName() ) );
709 } );
710 }
711
712 return true;
713}
714
715
717{
718 if( m_simulator->IsRunning() )
719 m_simulator->Stop();
720
721 // Prevent memory leak on exit by deleting all simulation vectors
722 m_simulator->Clean();
723
724 // Cancel a running simProbe or simTune tool
725 m_schematicFrame->GetToolManager()->PostAction( ACTIONS::cancelInteractive );
726
727 SaveSettings( config() );
728
729 m_simulator->Settings().reset();
730
731 Destroy();
732}
733
734
736{
738
739 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
740 wxASSERT( mgr );
741
742 auto showGridCondition =
743 [this]( const SELECTION& aSel )
744 {
745 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
746 return plotTab && plotTab->IsGridShown();
747 };
748
749 auto showLegendCondition =
750 [this]( const SELECTION& aSel )
751 {
752 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
753 return plotTab && plotTab->IsLegendShown();
754 };
755
756 auto showDottedCondition =
757 [this]( const SELECTION& aSel )
758 {
759 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
760 return plotTab && plotTab->GetDottedSecondary();
761 };
762
763 auto darkModePlotCondition =
764 [this]( const SELECTION& aSel )
765 {
766 return m_ui->DarkModePlots();
767 };
768
769 auto smithChartCondition =
770 [this]( const SELECTION& aSel )
771 {
772 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
773 return plotTab && plotTab->IsSmithMode();
774 };
775
776 auto haveSPPlot =
777 [this]( const SELECTION& aSel )
778 {
779 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
780 return plotTab && plotTab->GetSimType() == ST_SP;
781 };
782
783 auto simRunning =
784 [this]( const SELECTION& aSel )
785 {
786 return m_simulator && m_simulator->IsRunning();
787 };
788
789 auto simFinished =
790 [this]( const SELECTION& aSel )
791 {
792 return m_simFinished;
793 };
794
795 auto haveSim =
796 [this]( const SELECTION& aSel )
797 {
798 return GetCurrentSimTab() != nullptr;
799 };
800
801 auto havePlot =
802 [this]( const SELECTION& aSel )
803 {
804 return dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() ) != nullptr;
805 };
806
807 auto haveZoomUndo =
808 [this]( const SELECTION& aSel )
809 {
810 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
811 return plotTab && plotTab->GetPlotWin()->UndoZoomStackSize() > 0;
812 };
813
814 auto haveZoomRedo =
815 [this]( const SELECTION& aSel )
816 {
817 SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
818 return plotTab && plotTab->GetPlotWin()->RedoZoomStackSize() > 0;
819 };
820
821 // clang-format off
822 auto isSimConsoleShown =
823 [this]( const SELECTION& aSel )
824 {
825 bool aBool = false;
826
827 if( m_simulator )
828 return m_ui->IsSimConsoleShown();
829
830 return aBool;
831 };
832
833 auto isSimSidePanelShown =
834 [this]( const SELECTION& aSel )
835 {
836 bool aBool = false;
837
838 if( m_simulator )
839 return m_ui->IsSimSidePanelShown();
840
841 return aBool;
842 };
843 // clang-format on
844
845#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
846#define CHECK( x ) ACTION_CONDITIONS().Check( x )
847 // clang-format off
851
856
857 mgr->SetConditions( SCH_ACTIONS::toggleSimSidePanel, CHECK( isSimSidePanelShown ) );
858 mgr->SetConditions( SCH_ACTIONS::toggleSimConsole, CHECK( isSimConsoleShown ) );
859
860 mgr->SetConditions( ACTIONS::zoomUndo, ENABLE( haveZoomUndo ) );
861 mgr->SetConditions( ACTIONS::zoomRedo, ENABLE( haveZoomRedo ) );
862 mgr->SetConditions( SCH_ACTIONS::toggleGrid, CHECK( showGridCondition ) );
863 mgr->SetConditions( SCH_ACTIONS::toggleLegend, CHECK( showLegendCondition ) );
864 mgr->SetConditions( SCH_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) );
866 ACTION_CONDITIONS().Check( smithChartCondition ).Enable( haveSPPlot ) );
867 mgr->SetConditions( SCH_ACTIONS::toggleDarkModePlots, CHECK( darkModePlotCondition ) );
868
871 mgr->SetConditions( SCH_ACTIONS::runSimulation, ENABLE( !simRunning ) );
872 mgr->SetConditions( SCH_ACTIONS::stopSimulation, ENABLE( simRunning ) );
873 mgr->SetConditions( SCH_ACTIONS::simProbe, ENABLE( simFinished ) );
874 mgr->SetConditions( SCH_ACTIONS::simTune, ENABLE( simFinished ) );
876 // clang-format on
877#undef CHECK
878#undef ENABLE
879}
880
881
882void SIMULATOR_FRAME::onSimStarted( wxCommandEvent& aEvent )
883{
884 SetCursor( wxCURSOR_ARROWWAIT );
885}
886
887
889{
890 return m_consoleReporter->TakePendingMessages();
891}
892
893
894void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
895{
896 // Sometimes (for instance with a directive like wrdata my_file.csv "my_signal")
897 // the simulator is in idle state (simulation is finished), but still running, during
898 // the time the file is written. So gives a slice of time to fully finish the work:
899 if( m_simulator->IsRunning() )
900 {
901 int max_time = 40; // For a max timeout = 2s
902
903 do
904 {
905 wxMilliSleep( 50 );
906 wxYield();
907
908 if( max_time )
909 max_time--;
910
911 } while( max_time && m_simulator->IsRunning() );
912 }
913
914 // ensure the shown cursor is the default cursor, not the wxCURSOR_ARROWWAIT set when
915 // staring the simulator in onSimStarted:
916 SetCursor( wxNullCursor );
917
918 // Is a warning message useful if the simulatior is still running?
919 SCHEMATIC& schematic = m_schematicFrame->Schematic();
920 schematic.ClearOperatingPoints();
921
922 m_simFinished = true;
923
924 m_ui->OnSimRefresh( true );
925
926 m_schematicFrame->RefreshOperatingPointDisplay();
927 m_schematicFrame->GetCanvas()->Refresh();
928}
929
930
931void SIMULATOR_FRAME::onUpdateSim( wxCommandEvent& aEvent )
932{
933 static bool updateInProgress = false;
934
935 // skip update when events are triggered too often and previous call didn't end yet
936 if( updateInProgress )
937 return;
938
939 updateInProgress = true;
940
941 if( m_simulator->IsRunning() )
942 m_simulator->Stop();
943
944 std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
945
946 if( simulatorLock.owns_lock() )
947 {
948 // Tuner drags and multi-run steps rerun through here without going through
949 // StartSimulation(), so free the prior plot to keep repeated updates from leaking. A
950 // multi-run step's data is already copied into m_multiRunState before the next step.
951 if( SIM_TAB* simTab = m_ui->GetCurrentSimTab() )
952 destroyTabPlot( simTab );
953
954 m_ui->OnSimUpdate();
955 m_simulator->Run();
956 }
957 else
958 {
959 DisplayErrorMessage( this, _( "Another simulation is already running." ) );
960 }
961
962 updateInProgress = false;
963}
964
965
966void SIMULATOR_FRAME::onExit( wxCommandEvent& aEvent )
967{
968 if( aEvent.GetId() == wxID_EXIT )
969 Kiway().OnKiCadExit();
970
971 if( aEvent.GetId() == wxID_CLOSE )
972 Close( false );
973}
974
975
982
983
984wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
985
986wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
987wxDEFINE_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:786
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:250
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:142
virtual bool HasMessage() const
Returns true if any messages were reported.
Definition reporter.h:133
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 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: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.
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)
WX_STRING_REPORTER m_strRep
SIM_FRAME_STATE_LISTENER(SIMULATOR_FRAME *aParent)
void OnSimStateChange(SIMULATOR *aObject, SIM_STATE aNewState) override
mpWindow * GetPlotWin() const
bool IsGridShown() const
bool GetDottedSecondary() const
bool IsLegendShown() const
bool IsSmithMode() const
Refresh the grid z0 from the shown Smith traces.
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:173
std::mutex m_mutex
Definition reporter.h:193
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:225
const wxString & GetMessages() const
Definition reporter.cpp:160
int RedoZoomStackSize() const
Definition mathplot.h:1281
int UndoZoomStackSize() const
Definition mathplot.h:1280
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:728
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
@ GLOBAL_CLEANUP
Definition schematic.h:79
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.