2023-07-14 16:44:05 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016-2023 CERN
|
|
|
|
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
|
|
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
|
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 3
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 3 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <wx/debug.h>
|
|
|
|
|
|
|
|
#include <project/project_file.h>
|
|
|
|
#include <confirm.h>
|
|
|
|
#include <string_utils.h>
|
|
|
|
#include <sim/simulator_frame_ui.h>
|
|
|
|
#include <sim/simulator_frame.h>
|
|
|
|
#include <sim/sim_plot_tab.h>
|
|
|
|
|
|
|
|
|
|
|
|
void SIMULATOR_FRAME_UI::parseTraceParams( SIM_PLOT_TAB* aPlotTab, TRACE* aTrace,
|
|
|
|
const wxString& aSignalName, const wxString& aParams )
|
|
|
|
{
|
|
|
|
auto addCursor =
|
|
|
|
[&]( int aCursorId, double x )
|
|
|
|
{
|
|
|
|
CURSOR* cursor = new CURSOR( aTrace, aPlotTab );
|
|
|
|
|
|
|
|
cursor->SetName( aSignalName );
|
|
|
|
cursor->SetPen( wxPen( aTrace->GetTraceColour() ) );
|
|
|
|
cursor->SetCoordX( x );
|
|
|
|
|
|
|
|
aTrace->SetCursor( aCursorId, cursor );
|
|
|
|
aPlotTab->GetPlotWin()->AddLayer( cursor );
|
|
|
|
};
|
|
|
|
|
|
|
|
wxArrayString items = wxSplit( aParams, '|' );
|
|
|
|
|
|
|
|
for( const wxString& item : items )
|
|
|
|
{
|
|
|
|
if( item.StartsWith( wxS( "rgb" ) ) )
|
|
|
|
{
|
|
|
|
wxColour color;
|
|
|
|
color.Set( item );
|
|
|
|
aTrace->SetTraceColour( color );
|
|
|
|
aPlotTab->UpdateTraceStyle( aTrace );
|
|
|
|
}
|
|
|
|
else if( item.StartsWith( wxS( "cursor1" ) ) )
|
|
|
|
{
|
|
|
|
wxArrayString parts = wxSplit( item, ':' );
|
|
|
|
double val;
|
|
|
|
|
|
|
|
if( parts.size() == 3 )
|
|
|
|
{
|
|
|
|
parts[0].AfterFirst( '=' ).ToDouble( &val );
|
|
|
|
m_cursorFormats[0][0].FromString( parts[1] );
|
|
|
|
m_cursorFormats[0][1].FromString( parts[2] );
|
|
|
|
addCursor( 1, val );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( item.StartsWith( wxS( "cursor2" ) ) )
|
|
|
|
{
|
|
|
|
wxArrayString parts = wxSplit( item, ':' );
|
|
|
|
double val;
|
|
|
|
|
|
|
|
if( parts.size() == 3 )
|
|
|
|
{
|
|
|
|
parts[0].AfterFirst( '=' ).ToDouble( &val );
|
|
|
|
m_cursorFormats[1][0].FromString( parts[1] );
|
|
|
|
m_cursorFormats[1][1].FromString( parts[2] );
|
|
|
|
addCursor( 2, val );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( item.StartsWith( wxS( "cursorD" ) ) )
|
|
|
|
{
|
|
|
|
wxArrayString parts = wxSplit( item, ':' );
|
|
|
|
|
|
|
|
if( parts.size() == 3 )
|
|
|
|
{
|
|
|
|
m_cursorFormats[2][0].FromString( parts[1] );
|
|
|
|
m_cursorFormats[2][1].FromString( parts[2] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( item == wxS( "dottedSecondary" ) )
|
|
|
|
{
|
|
|
|
aPlotTab->SetDottedSecondary( true );
|
|
|
|
}
|
|
|
|
else if( item == wxS( "hideGrid" ) )
|
|
|
|
{
|
|
|
|
aPlotTab->ShowGrid( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool SIMULATOR_FRAME_UI::loadLegacyWorkbook( const wxString& aPath )
|
|
|
|
{
|
|
|
|
wxTextFile file( aPath );
|
|
|
|
|
|
|
|
#define EXPECTING( msg ) \
|
|
|
|
DisplayErrorMessage( this, wxString::Format( _( "Error loading workbook: line %d: %s." ), \
|
|
|
|
file.GetCurrentLine()+1, \
|
|
|
|
msg ) )
|
|
|
|
|
|
|
|
if( !file.Open() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
long version = 1;
|
|
|
|
wxString firstLine = file.GetFirstLine();
|
|
|
|
wxString pageCountLine;
|
|
|
|
|
|
|
|
if( firstLine.StartsWith( wxT( "version " ) ) )
|
|
|
|
{
|
|
|
|
if( !firstLine.substr( 8 ).ToLong( &version ) )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting version" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pageCountLine = file.GetNextLine();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pageCountLine = firstLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
long tabCount;
|
|
|
|
|
|
|
|
if( !pageCountLine.ToLong( &tabCount ) )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting simulation tab count" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<SIM_PLOT_TAB*, std::vector<std::tuple<long, wxString, wxString>>> traceInfo;
|
|
|
|
|
|
|
|
for( long i = 0; i < tabCount; ++i )
|
|
|
|
{
|
|
|
|
long simType, tracesCount;
|
|
|
|
|
|
|
|
if( !file.GetNextLine().ToLong( &simType ) )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting simulation tab type" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString command = UnescapeString( file.GetNextLine() );
|
|
|
|
wxString simCommand;
|
|
|
|
int simOptions = NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS;
|
|
|
|
wxStringTokenizer tokenizer( command, wxT( "\r\n" ), wxTOKEN_STRTOK );
|
|
|
|
|
|
|
|
if( version >= 2 )
|
|
|
|
{
|
|
|
|
simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_ADJUST_INCLUDE_PATHS;
|
|
|
|
simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES;
|
|
|
|
simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( version >= 3 )
|
|
|
|
{
|
|
|
|
simOptions &= ~NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( tokenizer.HasMoreTokens() )
|
|
|
|
{
|
|
|
|
wxString line = tokenizer.GetNextToken();
|
|
|
|
|
|
|
|
if( line.StartsWith( wxT( ".kicad adjustpaths" ) ) )
|
|
|
|
simOptions |= NETLIST_EXPORTER_SPICE::OPTION_ADJUST_INCLUDE_PATHS;
|
|
|
|
else if( line.StartsWith( wxT( ".save all" ) ) )
|
|
|
|
simOptions |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES;
|
|
|
|
else if( line.StartsWith( wxT( ".probe alli" ) ) )
|
|
|
|
simOptions |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS;
|
|
|
|
else if( line.StartsWith( wxT( ".probe allp" ) ) )
|
|
|
|
simOptions |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS;
|
|
|
|
else
|
|
|
|
simCommand += line + wxT( "\n" );
|
|
|
|
}
|
|
|
|
|
2023-07-19 15:25:57 +00:00
|
|
|
SIM_TAB* simTab = NewSimTab( simCommand );
|
2023-07-14 16:44:05 +00:00
|
|
|
SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( simTab );
|
|
|
|
|
2023-07-19 15:25:57 +00:00
|
|
|
simTab->SetSimOptions( simOptions );
|
|
|
|
|
2023-07-14 16:44:05 +00:00
|
|
|
if( !file.GetNextLine().ToLong( &tracesCount ) )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting trace count" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( plotTab )
|
|
|
|
traceInfo[plotTab] = {};
|
|
|
|
|
|
|
|
for( long j = 0; j < tracesCount; ++j )
|
|
|
|
{
|
|
|
|
long traceType;
|
|
|
|
wxString name, param;
|
|
|
|
|
|
|
|
if( !file.GetNextLine().ToLong( &traceType ) )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting trace type" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = file.GetNextLine();
|
|
|
|
|
|
|
|
if( name.IsEmpty() )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting trace name" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
param = file.GetNextLine();
|
|
|
|
|
|
|
|
if( param.IsEmpty() )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting trace color" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( plotTab )
|
|
|
|
traceInfo[plotTab].emplace_back( std::make_tuple( traceType, name, param ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( version > 4 )
|
|
|
|
{
|
|
|
|
long measurementCount;
|
|
|
|
|
|
|
|
if( !file.GetNextLine().ToLong( &measurementCount ) )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting measurement count" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( int ii = 0; ii < (int) measurementCount; ++ ii )
|
|
|
|
{
|
|
|
|
wxString measurement = file.GetNextLine();
|
|
|
|
|
|
|
|
if( measurement.IsEmpty() )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting measurement definition" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString format = file.GetNextLine();
|
|
|
|
|
|
|
|
if( format.IsEmpty() )
|
|
|
|
{
|
|
|
|
EXPECTING( _( "expecting measurement format definition" ) );
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( plotTab )
|
|
|
|
plotTab->Measurements().emplace_back( measurement, format );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long userDefinedSignalCount;
|
|
|
|
|
|
|
|
if( file.GetNextLine().ToLong( &userDefinedSignalCount ) )
|
|
|
|
{
|
|
|
|
for( int ii = 0; ii < (int) userDefinedSignalCount; ++ii )
|
|
|
|
m_userDefinedSignals[ ii ] = file.GetNextLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
for( const auto& [ plotTab, traceInfoVector ] : traceInfo )
|
|
|
|
{
|
|
|
|
for( const auto& [ traceType, signalName, param ] : traceInfoVector )
|
|
|
|
{
|
|
|
|
if( traceType == SPT_UNKNOWN && signalName == wxS( "$LEGEND" ) )
|
|
|
|
{
|
|
|
|
wxArrayString coords = wxSplit( param, ' ' );
|
|
|
|
|
|
|
|
if( coords.size() >= 2 )
|
|
|
|
{
|
|
|
|
long x = 0;
|
|
|
|
long y = 0;
|
|
|
|
|
|
|
|
coords[0].ToLong( &x );
|
|
|
|
coords[1].ToLong( &y );
|
|
|
|
plotTab->SetLegendPosition( wxPoint( (int) x, (int) y ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
plotTab->ShowLegend( true );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wxString vectorName = vectorNameFromSignalName( plotTab, signalName, nullptr );
|
|
|
|
TRACE* trace = plotTab->AddTrace( vectorName, (int) traceType );
|
|
|
|
|
|
|
|
if( version >= 4 && trace )
|
|
|
|
parseTraceParams( plotTab, trace, signalName, param );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
plotTab->UpdatePlotColors();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( SIM_TAB* simTab = GetCurrentSimTab() )
|
|
|
|
{
|
|
|
|
m_simulatorFrame->LoadSimulator( simTab->GetSimCommand(), simTab->GetSimOptions() );
|
|
|
|
|
|
|
|
if( version >= 5 )
|
|
|
|
{
|
|
|
|
simTab = dynamic_cast<SIM_TAB*>( m_plotNotebook->GetPage( 0 ) );
|
2023-07-17 14:19:22 +00:00
|
|
|
|
|
|
|
if( simTab )
|
|
|
|
simTab->SetLastSchTextSimCommand( file.GetNextLine() );
|
2023-07-14 16:44:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file.Close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|