905 lines
31 KiB
C++
905 lines
31 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2013-2017 Jean-Pierre Charras, jp.charras@wanadoo.fr
|
|
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
|
|
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* 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 2
|
|
* 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:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
/* Functions relative to the dialog creating the netlist for Pcbnew. The dialog is a notebook
|
|
* with 4 fixed netlist formats:
|
|
* Pcbnew
|
|
* ORCADPCB2
|
|
* CADSTAR
|
|
* SPICE
|
|
* and up to CUSTOMPANEL_COUNTMAX user programmable formats. These external converters are
|
|
* referred to as plugins, but they are really just external binaries.
|
|
*/
|
|
|
|
#include <pgm_base.h>
|
|
#include <kiface_base.h>
|
|
#include <gestfich.h>
|
|
#include <widgets/wx_html_report_panel.h>
|
|
#include <sch_edit_frame.h>
|
|
#include <netlist.h>
|
|
#include <dialogs/dialog_export_netlist_base.h>
|
|
#include <wildcards_and_files_ext.h>
|
|
#include <invoke_sch_dialog.h>
|
|
#include <netlist_exporters/netlist_exporter_spice.h>
|
|
#include <eeschema_settings.h>
|
|
#include <schematic.h>
|
|
#include <paths.h>
|
|
|
|
#include <eeschema_id.h>
|
|
#include <wx/checkbox.h>
|
|
#include <wx/filedlg.h>
|
|
#include <wx/msgdlg.h>
|
|
#include <wx/regex.h>
|
|
#include <wx/txtstrm.h>
|
|
|
|
#include <thread>
|
|
|
|
|
|
#define CUSTOMPANEL_COUNTMAX 8 // Max number of netlist plugins
|
|
|
|
|
|
/* panel (notebook page) identifiers
|
|
* if modified, fix also the DEFINED_NETLISTS_COUNT value
|
|
* PANEL_NETLIST_INDEX values are used as index in m_PanelNetType[]
|
|
*/
|
|
enum PANEL_NETLIST_INDEX
|
|
{
|
|
PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
|
|
PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
|
|
PANELALLEGRO, /* Handle Netlist format Allegro */
|
|
PANELCADSTAR, /* Handle Netlist format CadStar */
|
|
PANELPADS, /* Handle Netlist format PADS */
|
|
PANELSPICE, /* Handle Netlist format Spice */
|
|
PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
|
|
PANELCUSTOMBASE /* First auxiliary panel (custom netlists).
|
|
* others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */
|
|
};
|
|
|
|
// The count of panels for internally defined netlist formats
|
|
// (the max count of panel is DEFINED_NETLISTS_COUNT+CUSTOMPANEL_COUNTMAX)
|
|
#define DEFINED_NETLISTS_COUNT 6
|
|
|
|
/* wxPanels for creating the NoteBook pages for each netlist format: */
|
|
class EXPORT_NETLIST_PAGE : public wxPanel
|
|
{
|
|
|
|
public:
|
|
/**
|
|
* Create a setup page for one netlist format.
|
|
*
|
|
* Used in Netlist format dialog box creation.
|
|
*
|
|
* @param parent is the wxNotebook parent.
|
|
* @param title is the title of the notebook page.
|
|
* @param id_NetType is the netlist ID type.
|
|
*/
|
|
EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
|
|
NETLIST_TYPE_ID aIdNetType, bool aCustom );
|
|
~EXPORT_NETLIST_PAGE() { };
|
|
|
|
/**
|
|
* @return the name of the netlist format for this page.
|
|
*/
|
|
const wxString GetPageNetFmtName() { return m_pageNetFmtName; }
|
|
|
|
NETLIST_TYPE_ID m_IdNetType;
|
|
// opt to reformat passive component values (e.g. 1M -> 1Meg):
|
|
wxCheckBox* m_CurSheetAsRoot;
|
|
wxCheckBox* m_SaveAllVoltages;
|
|
wxCheckBox* m_SaveAllCurrents;
|
|
wxCheckBox* m_SaveAllDissipations;
|
|
wxCheckBox* m_RunExternalSpiceCommand;
|
|
wxTextCtrl* m_CommandStringCtrl;
|
|
wxTextCtrl* m_TitleStringCtrl;
|
|
wxBoxSizer* m_LeftBoxSizer;
|
|
wxBoxSizer* m_RightBoxSizer;
|
|
wxBoxSizer* m_RightOptionsBoxSizer;
|
|
wxBoxSizer* m_LowBoxSizer;
|
|
|
|
bool IsCustom() const { return m_custom; }
|
|
|
|
private:
|
|
wxString m_pageNetFmtName;
|
|
|
|
bool m_custom;
|
|
};
|
|
|
|
|
|
/* Dialog frame for creating netlists */
|
|
class DIALOG_EXPORT_NETLIST : public DIALOG_EXPORT_NETLIST_BASE
|
|
{
|
|
public:
|
|
DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* parent );
|
|
~DIALOG_EXPORT_NETLIST() { };
|
|
|
|
private:
|
|
void InstallCustomPages();
|
|
EXPORT_NETLIST_PAGE* AddOneCustomPage( const wxString& aTitle, const wxString& aCommandString,
|
|
NETLIST_TYPE_ID aNetTypeId );
|
|
void InstallPageSpice();
|
|
void InstallPageSpiceModel();
|
|
|
|
bool TransferDataFromWindow() override;
|
|
bool NetlistUpdateOpt();
|
|
|
|
void updateGeneratorButtons();
|
|
|
|
// Called when changing the notebook page (and therefore the current netlist format)
|
|
void OnNetlistTypeSelection( wxNotebookEvent& event ) override;
|
|
|
|
/**
|
|
* Add a new panel for a new netlist plugin.
|
|
*/
|
|
void OnAddGenerator( wxCommandEvent& event ) override;
|
|
|
|
/**
|
|
* Remove a panel relative to a netlist plugin.
|
|
*/
|
|
void OnDelGenerator( wxCommandEvent& event ) override;
|
|
|
|
/**
|
|
* Write the current netlist options setup in the configuration.
|
|
*/
|
|
void WriteCurrentNetlistSetup();
|
|
|
|
/**
|
|
* Return the filename extension and the wildcard string for this page or a void name
|
|
* if there is no default name.
|
|
*
|
|
* @param aType is the netlist type ( NET_TYPE_PCBNEW ... ).
|
|
* @param aExt [in] is a holder for the netlist file extension.
|
|
* @param aWildCard [in] is a holder for netlist file dialog wildcard.
|
|
* @return true for known netlist type, false for custom formats.
|
|
*/
|
|
bool FilenamePrms( NETLIST_TYPE_ID aType, wxString* aExt, wxString* aWildCard );
|
|
|
|
public:
|
|
SCH_EDIT_FRAME* m_Parent;
|
|
EXPORT_NETLIST_PAGE* m_PanelNetType[DEFINED_NETLISTS_COUNT + CUSTOMPANEL_COUNTMAX];
|
|
};
|
|
|
|
|
|
class NETLIST_DIALOG_ADD_GENERATOR : public NETLIST_DIALOG_ADD_GENERATOR_BASE
|
|
{
|
|
public:
|
|
NETLIST_DIALOG_ADD_GENERATOR( DIALOG_EXPORT_NETLIST* parent );
|
|
|
|
const wxString GetGeneratorTitle() { return m_textCtrlName->GetValue(); }
|
|
const wxString GetGeneratorTCommandLine() { return m_textCtrlCommand->GetValue(); }
|
|
|
|
bool TransferDataFromWindow() override;
|
|
|
|
private:
|
|
/*
|
|
* Browse plugin files, and set m_CommandStringCtrl field
|
|
*/
|
|
void OnBrowseGenerators( wxCommandEvent& event ) override;
|
|
|
|
DIALOG_EXPORT_NETLIST* m_Parent;
|
|
};
|
|
|
|
|
|
/* Event id for notebook page buttons: */
|
|
enum id_netlist {
|
|
ID_CREATE_NETLIST = ID_END_EESCHEMA_ID_LIST + 1,
|
|
ID_CUR_SHEET_AS_ROOT,
|
|
ID_SAVE_ALL_VOLTAGES,
|
|
ID_SAVE_ALL_CURRENTS,
|
|
ID_SAVE_ALL_DISSIPATIONS,
|
|
ID_RUN_SIMULATOR
|
|
};
|
|
|
|
|
|
EXPORT_NETLIST_PAGE::EXPORT_NETLIST_PAGE( wxNotebook* aParent, const wxString& aTitle,
|
|
NETLIST_TYPE_ID aIdNetType, bool aCustom ) :
|
|
wxPanel( aParent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL )
|
|
{
|
|
m_IdNetType = aIdNetType;
|
|
m_pageNetFmtName = aTitle;
|
|
m_CommandStringCtrl = nullptr;
|
|
m_CurSheetAsRoot = nullptr;
|
|
m_TitleStringCtrl = nullptr;
|
|
m_SaveAllVoltages = nullptr;
|
|
m_SaveAllCurrents = nullptr;
|
|
m_SaveAllDissipations = nullptr;
|
|
m_RunExternalSpiceCommand = nullptr;
|
|
m_custom = aCustom;
|
|
|
|
aParent->AddPage( this, aTitle, false );
|
|
|
|
wxBoxSizer* MainBoxSizer = new wxBoxSizer( wxVERTICAL );
|
|
SetSizer( MainBoxSizer );
|
|
wxBoxSizer* UpperBoxSizer = new wxBoxSizer( wxHORIZONTAL );
|
|
m_LowBoxSizer = new wxBoxSizer( wxVERTICAL );
|
|
MainBoxSizer->Add( UpperBoxSizer, 0, wxGROW | wxALL, 5 );
|
|
MainBoxSizer->Add( m_LowBoxSizer, 0, wxGROW | wxALL, 5 );
|
|
|
|
m_LeftBoxSizer = new wxBoxSizer( wxVERTICAL );
|
|
m_RightBoxSizer = new wxBoxSizer( wxVERTICAL );
|
|
m_RightOptionsBoxSizer = new wxBoxSizer( wxVERTICAL );
|
|
UpperBoxSizer->Add( m_LeftBoxSizer, 0, wxGROW | wxALL, 5 );
|
|
UpperBoxSizer->Add( m_RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
|
|
UpperBoxSizer->Add( m_RightOptionsBoxSizer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
|
|
}
|
|
|
|
|
|
DIALOG_EXPORT_NETLIST::DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* parent ) :
|
|
DIALOG_EXPORT_NETLIST_BASE( parent )
|
|
{
|
|
m_Parent = parent;
|
|
|
|
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
|
|
|
|
for( EXPORT_NETLIST_PAGE*& page : m_PanelNetType )
|
|
page = nullptr;
|
|
|
|
// Add notebook pages:
|
|
EXPORT_NETLIST_PAGE* page = nullptr;
|
|
wxStaticText* label = nullptr;
|
|
|
|
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
|
|
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in legacy KiCad format" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
m_PanelNetType[PANELPCBNEW] = page;
|
|
|
|
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
|
|
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in OrcadPCB2 format" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
m_PanelNetType[PANELORCADPCB2] = page;
|
|
|
|
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
|
|
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in Allegro format" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
m_PanelNetType[PANELALLEGRO] = page;
|
|
|
|
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false );
|
|
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in PADS format" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
m_PanelNetType[PANELPADS] = page;
|
|
|
|
page = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
|
|
label = new wxStaticText( page, wxID_ANY, _( "Export netlist in CadStar format" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
m_PanelNetType[PANELCADSTAR] = page;
|
|
|
|
InstallPageSpice();
|
|
InstallPageSpiceModel();
|
|
InstallCustomPages();
|
|
|
|
SetupStandardButtons( { { wxID_OK, _( "Export Netlist" ) },
|
|
{ wxID_CANCEL, _( "Close" ) } } );
|
|
|
|
for( int ii = 0; (ii < 4 + CUSTOMPANEL_COUNTMAX) && m_PanelNetType[ii]; ++ii )
|
|
{
|
|
if( m_PanelNetType[ii]->GetPageNetFmtName() == settings.m_NetFormatName )
|
|
{
|
|
m_NoteBook->ChangeSelection( ii );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now all widgets have the size fixed, call FinishDialogSettings
|
|
finishDialogSettings();
|
|
|
|
updateGeneratorButtons();
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::InstallPageSpice()
|
|
{
|
|
EXPORT_NETLIST_PAGE* page = m_PanelNetType[PANELSPICE] =
|
|
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Spice" ), NET_TYPE_SPICE, false );
|
|
|
|
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
|
|
|
|
wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist in SPICE format" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
|
|
page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
|
|
_( "Use current sheet as root" ) );
|
|
page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
|
|
page->m_CurSheetAsRoot->SetValue( settings.m_SpiceCurSheetAsRoot );
|
|
page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
|
|
|
|
page->m_SaveAllVoltages = new wxCheckBox( page, ID_SAVE_ALL_VOLTAGES,
|
|
_( "Save all voltages" ) );
|
|
page->m_SaveAllVoltages->SetToolTip( _( "Write a directive to save all voltages (.save all)" ) );
|
|
page->m_SaveAllVoltages->SetValue( settings.m_SpiceSaveAllVoltages );
|
|
page->m_LeftBoxSizer->Add( page->m_SaveAllVoltages, 0, wxBOTTOM | wxRIGHT, 5 );
|
|
|
|
page->m_SaveAllCurrents = new wxCheckBox( page, ID_SAVE_ALL_CURRENTS,
|
|
_( "Save all currents" ) );
|
|
page->m_SaveAllCurrents->SetToolTip( _( "Write a directive to save all currents (.probe alli)" ) );
|
|
page->m_SaveAllCurrents->SetValue( settings.m_SpiceSaveAllCurrents );
|
|
page->m_LeftBoxSizer->Add( page->m_SaveAllCurrents, 0, wxBOTTOM | wxRIGHT, 5 );
|
|
|
|
page->m_SaveAllDissipations = new wxCheckBox( page, ID_SAVE_ALL_DISSIPATIONS,
|
|
_( "Save all power dissipations" ) );
|
|
page->m_SaveAllDissipations->SetToolTip( _( "Write directives to save power dissipation of all items (.probe p(<item>))" ) );
|
|
page->m_SaveAllDissipations->SetValue( settings.m_SpiceSaveAllDissipations );
|
|
page->m_LeftBoxSizer->Add( page->m_SaveAllDissipations, 0, wxBOTTOM | wxRIGHT, 5 );
|
|
|
|
|
|
page->m_RunExternalSpiceCommand = new wxCheckBox( page, ID_RUN_SIMULATOR,
|
|
_( "Run external simulator command:" ) );
|
|
wxString simulatorCommand = settings.m_SpiceCommandString;
|
|
page->m_RunExternalSpiceCommand->SetToolTip( _( "Enter the command line to run SPICE\n"
|
|
"Usually '<path to SPICE binary> \"%I\"'\n"
|
|
"%I will be replaced by the netlist filepath" ) );
|
|
page->m_LowBoxSizer->Add( page->m_RunExternalSpiceCommand, 0,
|
|
wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
|
|
|
page->m_CommandStringCtrl = new wxTextCtrl( page, -1, simulatorCommand,
|
|
wxDefaultPosition, wxDefaultSize );
|
|
|
|
page->m_CommandStringCtrl->SetInsertionPoint( 1 );
|
|
page->m_LowBoxSizer->Add( page->m_CommandStringCtrl, 0,
|
|
wxGROW | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::InstallPageSpiceModel()
|
|
{
|
|
EXPORT_NETLIST_PAGE* page = m_PanelNetType[PANELSPICEMODEL] =
|
|
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Spice Model" ), NET_TYPE_SPICE_MODEL, false );
|
|
|
|
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
|
|
|
|
wxStaticText* label = new wxStaticText( page, wxID_ANY, _( "Export netlist as a SPICE .subckt model" ) );
|
|
page->m_LeftBoxSizer->Add( label, 0, wxBOTTOM, 10 );
|
|
|
|
page->m_CurSheetAsRoot = new wxCheckBox( page, ID_CUR_SHEET_AS_ROOT,
|
|
_( "Use current sheet as root" ) );
|
|
page->m_CurSheetAsRoot->SetToolTip( _( "Export netlist only for the current sheet" ) );
|
|
page->m_CurSheetAsRoot->SetValue( settings.m_SpiceModelCurSheetAsRoot );
|
|
page->m_LeftBoxSizer->Add( page->m_CurSheetAsRoot, 0, wxGROW | wxBOTTOM | wxRIGHT, 5 );
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::InstallCustomPages()
|
|
{
|
|
EXPORT_NETLIST_PAGE* currPage;
|
|
EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
|
wxASSERT( cfg );
|
|
|
|
if( cfg )
|
|
{
|
|
for( size_t i = 0; i < CUSTOMPANEL_COUNTMAX && i < cfg->m_NetlistPanel.plugins.size(); i++ )
|
|
{
|
|
// pairs of (title, command) are stored
|
|
wxString title = cfg->m_NetlistPanel.plugins[i].name;
|
|
|
|
if( i >= cfg->m_NetlistPanel.plugins.size() )
|
|
break; // No more panel to install
|
|
|
|
wxString command = cfg->m_NetlistPanel.plugins[i].command;
|
|
|
|
currPage = AddOneCustomPage( title, command,
|
|
static_cast<NETLIST_TYPE_ID>( NET_TYPE_CUSTOM1 + i ) );
|
|
|
|
m_PanelNetType[PANELCUSTOMBASE + i] = currPage;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
EXPORT_NETLIST_PAGE* DIALOG_EXPORT_NETLIST::AddOneCustomPage( const wxString& aTitle,
|
|
const wxString& aCommandString,
|
|
NETLIST_TYPE_ID aNetTypeId )
|
|
{
|
|
EXPORT_NETLIST_PAGE* currPage = new EXPORT_NETLIST_PAGE( m_NoteBook, aTitle, aNetTypeId, true );
|
|
|
|
currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Title:" ) ), 0,
|
|
wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
|
|
|
|
currPage->m_TitleStringCtrl = new wxTextCtrl( currPage, -1, aTitle,
|
|
wxDefaultPosition, wxDefaultSize );
|
|
|
|
currPage->m_TitleStringCtrl->SetInsertionPoint( 1 );
|
|
currPage->m_LowBoxSizer->Add( currPage->m_TitleStringCtrl, 0,
|
|
wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
|
|
|
currPage->m_LowBoxSizer->Add( new wxStaticText( currPage, -1, _( "Netlist command:" ) ), 0,
|
|
wxGROW | wxLEFT | wxRIGHT | wxTOP, 5 );
|
|
|
|
currPage->m_CommandStringCtrl = new wxTextCtrl( currPage, -1, aCommandString,
|
|
wxDefaultPosition, wxDefaultSize );
|
|
|
|
currPage->m_CommandStringCtrl->SetInsertionPoint( 1 );
|
|
currPage->m_LowBoxSizer->Add( currPage->m_CommandStringCtrl, 0,
|
|
wxGROW | wxTOP | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
|
|
|
|
return currPage;
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::OnNetlistTypeSelection( wxNotebookEvent& event )
|
|
{
|
|
updateGeneratorButtons();
|
|
}
|
|
|
|
|
|
bool DIALOG_EXPORT_NETLIST::NetlistUpdateOpt()
|
|
{
|
|
bool changed = false;
|
|
|
|
bool saveAllVoltages = m_PanelNetType[ PANELSPICE ]->m_SaveAllVoltages->IsChecked();
|
|
bool saveAllCurrents = m_PanelNetType[ PANELSPICE ]->m_SaveAllCurrents->IsChecked();
|
|
bool saveAllDissipations = m_PanelNetType[ PANELSPICE ]->m_SaveAllDissipations->IsChecked();
|
|
wxString spiceCmdString = m_PanelNetType[ PANELSPICE ]->m_CommandStringCtrl->GetValue();
|
|
bool curSheetAsRoot = m_PanelNetType[ PANELSPICE ]->m_CurSheetAsRoot->GetValue();
|
|
bool spiceModelCurSheetAsRoot = m_PanelNetType[ PANELSPICEMODEL ]->m_CurSheetAsRoot->GetValue();
|
|
|
|
SCHEMATIC_SETTINGS& settings = m_Parent->Schematic().Settings();
|
|
wxString netFormatName = m_PanelNetType[m_NoteBook->GetSelection()]->GetPageNetFmtName();
|
|
|
|
changed |= ( settings.m_SpiceSaveAllVoltages != saveAllVoltages );
|
|
changed |= ( settings.m_SpiceSaveAllCurrents != saveAllCurrents );
|
|
changed |= ( settings.m_SpiceSaveAllDissipations != saveAllDissipations );
|
|
changed |= ( settings.m_SpiceCommandString != spiceCmdString );
|
|
changed |= ( settings.m_SpiceCurSheetAsRoot != curSheetAsRoot );
|
|
changed |= ( settings.m_SpiceModelCurSheetAsRoot != spiceModelCurSheetAsRoot );
|
|
changed |= ( settings.m_NetFormatName != netFormatName );
|
|
|
|
settings.m_SpiceSaveAllVoltages = saveAllVoltages;
|
|
settings.m_SpiceSaveAllCurrents = saveAllCurrents;
|
|
settings.m_SpiceSaveAllDissipations = saveAllDissipations;
|
|
settings.m_SpiceCommandString = spiceCmdString;
|
|
settings.m_SpiceCurSheetAsRoot = curSheetAsRoot;
|
|
settings.m_SpiceModelCurSheetAsRoot = spiceModelCurSheetAsRoot;
|
|
settings.m_NetFormatName = netFormatName;
|
|
|
|
return changed;
|
|
}
|
|
|
|
|
|
bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow()
|
|
{
|
|
wxFileName fn;
|
|
wxString fileWildcard;
|
|
wxString fileExt;
|
|
wxString title = _( "Save Netlist File" );
|
|
|
|
if( NetlistUpdateOpt() )
|
|
m_Parent->OnModify();
|
|
|
|
EXPORT_NETLIST_PAGE* currPage;
|
|
currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
|
|
|
|
bool runExternalSpiceCommand = false;
|
|
unsigned netlist_opt = 0;
|
|
|
|
// Calculate the netlist filename
|
|
fn = m_Parent->Schematic().GetFileName();
|
|
FilenamePrms( currPage->m_IdNetType, &fileExt, &fileWildcard );
|
|
|
|
// Set some parameters
|
|
switch( currPage->m_IdNetType )
|
|
{
|
|
case NET_TYPE_SPICE:
|
|
// Set spice netlist options:
|
|
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SIM_COMMAND;
|
|
|
|
if( currPage->m_SaveAllVoltages->GetValue() )
|
|
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES;
|
|
|
|
if( currPage->m_SaveAllCurrents->GetValue() )
|
|
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS;
|
|
|
|
if( currPage->m_SaveAllDissipations->GetValue() )
|
|
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS;
|
|
|
|
if( currPage->m_CurSheetAsRoot->GetValue() )
|
|
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT;
|
|
|
|
runExternalSpiceCommand = currPage->m_RunExternalSpiceCommand->GetValue();
|
|
break;
|
|
|
|
case NET_TYPE_SPICE_MODEL:
|
|
if( currPage->m_CurSheetAsRoot->GetValue() )
|
|
netlist_opt |= NETLIST_EXPORTER_SPICE::OPTION_CUR_SHEET_AS_ROOT;
|
|
|
|
break;
|
|
|
|
case NET_TYPE_CADSTAR:
|
|
break;
|
|
|
|
case NET_TYPE_PCBNEW:
|
|
break;
|
|
|
|
case NET_TYPE_ORCADPCB2:
|
|
break;
|
|
|
|
case NET_TYPE_ALLEGRO:
|
|
break;
|
|
|
|
case NET_TYPE_PADS:
|
|
break;
|
|
|
|
default: // custom, NET_TYPE_CUSTOM1 and greater
|
|
{
|
|
title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
|
|
break;
|
|
}
|
|
}
|
|
|
|
wxString fullpath;
|
|
|
|
if( runExternalSpiceCommand )
|
|
{
|
|
fn.SetExt( FILEEXT::SpiceFileExtension );
|
|
fullpath = fn.GetFullPath();
|
|
}
|
|
else
|
|
{
|
|
fn.SetExt( fileExt );
|
|
|
|
if( fn.GetPath().IsEmpty() )
|
|
fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
|
|
|
|
wxString fullname = fn.GetFullName();
|
|
wxString path = fn.GetPath();
|
|
|
|
// full name does not and should not include the path, per wx docs.
|
|
wxFileDialog dlg( this, title, path, fullname, fileWildcard, wxFD_SAVE );
|
|
|
|
if( dlg.ShowModal() == wxID_CANCEL )
|
|
return false;
|
|
|
|
fullpath = dlg.GetPath(); // directory + filename
|
|
}
|
|
|
|
m_Parent->ClearMsgPanel();
|
|
REPORTER& reporter = m_MessagesBox->Reporter();
|
|
|
|
if( currPage->m_CommandStringCtrl )
|
|
m_Parent->SetNetListerCommand( currPage->m_CommandStringCtrl->GetValue() );
|
|
else
|
|
m_Parent->SetNetListerCommand( wxEmptyString );
|
|
|
|
if( !m_Parent->ReadyToNetlist( _( "Exporting netlist requires a fully annotated schematic." ) ) )
|
|
return false;
|
|
|
|
m_Parent->WriteNetListFile( currPage->m_IdNetType, fullpath, netlist_opt, &reporter );
|
|
|
|
if( runExternalSpiceCommand )
|
|
{
|
|
// Build the command line
|
|
wxString commandLine = m_Parent->Schematic().Settings().m_SpiceCommandString;
|
|
commandLine.Replace( wxS( "%I" ), fullpath, true );
|
|
commandLine.Trim( true ).Trim( false );
|
|
|
|
if( !commandLine.IsEmpty() )
|
|
{
|
|
wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
|
|
process->Redirect();
|
|
wxExecute( commandLine, wxEXEC_ASYNC, process );
|
|
|
|
reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
|
|
process->Activate();
|
|
|
|
std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); // give the process time to start and output any data or errors
|
|
|
|
if( process->IsInputAvailable() )
|
|
{
|
|
wxInputStream* in = process->GetInputStream();
|
|
wxTextInputStream textstream( *in );
|
|
|
|
while( in->CanRead() )
|
|
{
|
|
wxString line = textstream.ReadLine();
|
|
|
|
if( !line.IsEmpty() )
|
|
reporter.Report( line, RPT_SEVERITY_INFO );
|
|
}
|
|
}
|
|
|
|
if( process->IsErrorAvailable() )
|
|
{
|
|
wxInputStream* err = process->GetErrorStream();
|
|
wxTextInputStream textstream( *err );
|
|
|
|
while( err->CanRead() )
|
|
{
|
|
wxString line = textstream.ReadLine();
|
|
|
|
if( !line.IsEmpty() )
|
|
{
|
|
if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
|
|
{
|
|
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
|
|
reporter.Report( _( "Note: command line is usually: "
|
|
"<tt><path to SPICE binary> \"%I\"</tt>" ),
|
|
RPT_SEVERITY_INFO );
|
|
}
|
|
else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
|
|
{
|
|
reporter.Report( _( "external simulator has the wrong format or "
|
|
"architecture" ), RPT_SEVERITY_ERROR );
|
|
}
|
|
else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
|
|
{
|
|
reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
|
|
}
|
|
else
|
|
{
|
|
reporter.Report( line, RPT_SEVERITY_ERROR );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
process->CloseOutput();
|
|
process->Detach();
|
|
|
|
// Do not delete process, it will delete itself when it terminates
|
|
}
|
|
}
|
|
|
|
WriteCurrentNetlistSetup();
|
|
|
|
return !runExternalSpiceCommand;
|
|
}
|
|
|
|
|
|
bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt, wxString * aWildCard )
|
|
{
|
|
wxString fileExt;
|
|
wxString fileWildcard;
|
|
bool ret = true;
|
|
|
|
switch( aType )
|
|
{
|
|
case NET_TYPE_SPICE:
|
|
fileExt = FILEEXT::SpiceFileExtension;
|
|
fileWildcard = FILEEXT::SpiceNetlistFileWildcard();
|
|
break;
|
|
|
|
case NET_TYPE_CADSTAR:
|
|
fileExt = FILEEXT::CadstarNetlistFileExtension;
|
|
fileWildcard = FILEEXT::CadstarNetlistFileWildcard();
|
|
break;
|
|
|
|
case NET_TYPE_ORCADPCB2:
|
|
fileExt = FILEEXT::OrCadPcb2NetlistFileExtension;
|
|
fileWildcard = FILEEXT::OrCadPcb2NetlistFileWildcard();
|
|
break;
|
|
|
|
case NET_TYPE_PCBNEW:
|
|
fileExt = FILEEXT::NetlistFileExtension;
|
|
fileWildcard = FILEEXT::NetlistFileWildcard();
|
|
break;
|
|
|
|
case NET_TYPE_ALLEGRO:
|
|
fileExt = FILEEXT::AllegroNetlistFileExtension;
|
|
fileWildcard = FILEEXT::AllegroNetlistFileWildcard();
|
|
break;
|
|
|
|
case NET_TYPE_PADS:
|
|
fileExt = FILEEXT::PADSNetlistFileExtension;
|
|
fileWildcard = FILEEXT::PADSNetlistFileWildcard();
|
|
break;
|
|
|
|
|
|
default: // custom, NET_TYPE_CUSTOM1 and greater
|
|
fileWildcard = FILEEXT::AllFilesWildcard();
|
|
ret = false;
|
|
}
|
|
|
|
if( aExt )
|
|
*aExt = fileExt;
|
|
|
|
if( aWildCard )
|
|
*aWildCard = fileWildcard;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::WriteCurrentNetlistSetup()
|
|
{
|
|
if( NetlistUpdateOpt() )
|
|
m_Parent->OnModify();
|
|
|
|
EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
|
|
wxASSERT( cfg );
|
|
|
|
if( !cfg )
|
|
return;
|
|
|
|
cfg->m_NetlistPanel.plugins.clear();
|
|
|
|
// Update existing custom pages
|
|
for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ )
|
|
{
|
|
EXPORT_NETLIST_PAGE* currPage = m_PanelNetType[ii + PANELCUSTOMBASE];
|
|
|
|
if( currPage == nullptr )
|
|
break;
|
|
|
|
wxString title = currPage->m_TitleStringCtrl->GetValue();
|
|
wxString command = currPage->m_CommandStringCtrl->GetValue();
|
|
|
|
if( title.IsEmpty() || command.IsEmpty() )
|
|
continue;
|
|
|
|
cfg->m_NetlistPanel.plugins.emplace_back( title, wxEmptyString );
|
|
cfg->m_NetlistPanel.plugins.back().command = command;
|
|
}
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::OnDelGenerator( wxCommandEvent& event )
|
|
{
|
|
EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
|
|
|
|
if( !currPage->IsCustom() )
|
|
return;
|
|
|
|
currPage->m_CommandStringCtrl->SetValue( wxEmptyString );
|
|
currPage->m_TitleStringCtrl->SetValue( wxEmptyString );
|
|
|
|
WriteCurrentNetlistSetup();
|
|
|
|
if( IsQuasiModal() )
|
|
EndQuasiModal( NET_PLUGIN_CHANGE );
|
|
else
|
|
EndDialog( NET_PLUGIN_CHANGE );
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::OnAddGenerator( wxCommandEvent& event )
|
|
{
|
|
NETLIST_DIALOG_ADD_GENERATOR dlg( this );
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
return;
|
|
|
|
// Creates a new custom plugin page
|
|
wxString title = dlg.GetGeneratorTitle();
|
|
|
|
// Verify it does not exists
|
|
int netTypeId = PANELCUSTOMBASE; // the first not used type id
|
|
EXPORT_NETLIST_PAGE* currPage;
|
|
|
|
for( int ii = 0; ii < CUSTOMPANEL_COUNTMAX; ii++ )
|
|
{
|
|
netTypeId = PANELCUSTOMBASE + ii;
|
|
currPage = m_PanelNetType[ii + PANELCUSTOMBASE];
|
|
|
|
if( currPage == nullptr )
|
|
break;
|
|
|
|
if( currPage->GetPageNetFmtName() == title )
|
|
{
|
|
wxMessageBox( _("This plugin already exists.") );
|
|
return;
|
|
}
|
|
}
|
|
|
|
wxString cmd = dlg.GetGeneratorTCommandLine();
|
|
currPage = AddOneCustomPage( title,cmd, (NETLIST_TYPE_ID)netTypeId );
|
|
m_PanelNetType[netTypeId] = currPage;
|
|
WriteCurrentNetlistSetup();
|
|
|
|
if( IsQuasiModal() )
|
|
EndQuasiModal( NET_PLUGIN_CHANGE );
|
|
else
|
|
EndDialog( NET_PLUGIN_CHANGE );
|
|
}
|
|
|
|
|
|
NETLIST_DIALOG_ADD_GENERATOR::NETLIST_DIALOG_ADD_GENERATOR( DIALOG_EXPORT_NETLIST* parent ) :
|
|
NETLIST_DIALOG_ADD_GENERATOR_BASE( parent )
|
|
{
|
|
m_Parent = parent;
|
|
SetupStandardButtons();
|
|
GetSizer()->SetSizeHints( this );
|
|
}
|
|
|
|
|
|
bool NETLIST_DIALOG_ADD_GENERATOR::TransferDataFromWindow()
|
|
{
|
|
if( !wxDialog::TransferDataFromWindow() )
|
|
return false;
|
|
|
|
if( m_textCtrlCommand->GetValue() == wxEmptyString )
|
|
{
|
|
wxMessageBox( _( "You must provide a netlist generator command string" ) );
|
|
return false;
|
|
}
|
|
|
|
if( m_textCtrlName->GetValue() == wxEmptyString )
|
|
{
|
|
wxMessageBox( _( "You must provide a netlist generator title" ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void NETLIST_DIALOG_ADD_GENERATOR::OnBrowseGenerators( wxCommandEvent& event )
|
|
{
|
|
wxString FullFileName, Path;
|
|
|
|
#ifndef __WXMAC__
|
|
Path = Pgm().GetExecutablePath();
|
|
#else
|
|
Path = PATHS::GetOSXKicadDataDir() + wxT( "/plugins" );
|
|
#endif
|
|
|
|
FullFileName = wxFileSelector( _( "Generator File" ), Path, FullFileName,
|
|
wxEmptyString, wxFileSelectorDefaultWildcardStr,
|
|
wxFD_OPEN, this );
|
|
|
|
if( FullFileName.IsEmpty() )
|
|
return;
|
|
|
|
// Creates a default command line, suitable for external tool xslproc or python, based on
|
|
// the plugin extension ("xsl" or "exe" or "py")
|
|
wxString cmdLine;
|
|
wxFileName fn( FullFileName );
|
|
wxString ext = fn.GetExt();
|
|
|
|
if( ext == wxT( "xsl" ) )
|
|
cmdLine.Printf( wxT( "xsltproc -o \"%%O\" \"%s\" \"%%I\"" ), FullFileName );
|
|
else if( ext == wxT( "exe" ) || ext.IsEmpty() )
|
|
cmdLine.Printf( wxT( "\"%s\" > \"%%O\" < \"%%I\"" ), FullFileName );
|
|
else if( ext == wxT( "py" ) || ext.IsEmpty() )
|
|
cmdLine.Printf( wxT( "python \"%s\" \"%%I\" \"%%O\"" ), FullFileName );
|
|
else
|
|
cmdLine.Printf( wxT( "\"%s\"" ), FullFileName );
|
|
|
|
m_textCtrlCommand->SetValue( cmdLine );
|
|
|
|
// We need a title for this panel
|
|
// Propose a default value if empty ( i.e. the short filename of the script)
|
|
if( m_textCtrlName->GetValue().IsEmpty() )
|
|
m_textCtrlName->SetValue( fn.GetName() );
|
|
}
|
|
|
|
|
|
void DIALOG_EXPORT_NETLIST::updateGeneratorButtons()
|
|
{
|
|
EXPORT_NETLIST_PAGE* currPage = (EXPORT_NETLIST_PAGE*) m_NoteBook->GetCurrentPage();
|
|
|
|
if( currPage == nullptr )
|
|
return;
|
|
|
|
m_buttonDelGenerator->Enable( currPage->IsCustom() );
|
|
}
|
|
|
|
|
|
int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller )
|
|
{
|
|
DIALOG_EXPORT_NETLIST dlg( aCaller );
|
|
|
|
int ret = dlg.ShowModal();
|
|
aCaller->SaveProjectLocalSettings();
|
|
|
|
return ret;
|
|
}
|