ADDED: Cadence Allegro PCB Designer netlist exporter
This commit is contained in:
parent
6d3f512e15
commit
4cb993d872
|
@ -145,6 +145,7 @@ const std::string LtspiceSchematicExtension( "asc" );
|
||||||
const std::string CadstarNetlistFileExtension( "frp" );
|
const std::string CadstarNetlistFileExtension( "frp" );
|
||||||
const std::string OrCadPcb2NetlistFileExtension( "net" );
|
const std::string OrCadPcb2NetlistFileExtension( "net" );
|
||||||
const std::string NetlistFileExtension( "net" );
|
const std::string NetlistFileExtension( "net" );
|
||||||
|
const std::string AllegroNetlistFileExtension( "txt" );
|
||||||
const std::string FootprintAssignmentFileExtension( "cmp" );
|
const std::string FootprintAssignmentFileExtension( "cmp" );
|
||||||
const std::string GerberFileExtension( "gbr" );
|
const std::string GerberFileExtension( "gbr" );
|
||||||
const std::string GerberJobFileExtension( "gbrjob" );
|
const std::string GerberJobFileExtension( "gbrjob" );
|
||||||
|
@ -330,6 +331,13 @@ wxString NetlistFileWildcard()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString AllegroNetlistFileWildcard()
|
||||||
|
{
|
||||||
|
return _( "Allegro netlist files" )
|
||||||
|
+ AddFileExtListToFilter( { AllegroNetlistFileExtension } );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
wxString LegacyPcbFileWildcard()
|
wxString LegacyPcbFileWildcard()
|
||||||
{
|
{
|
||||||
return _( "KiCad printed circuit board files" ) + AddFileExtListToFilter( { "brd" } );
|
return _( "KiCad printed circuit board files" ) + AddFileExtListToFilter( { "brd" } );
|
||||||
|
|
|
@ -355,6 +355,7 @@ set( EESCHEMA_SRCS
|
||||||
toolbars_sch_editor.cpp
|
toolbars_sch_editor.cpp
|
||||||
toolbars_symbol_viewer.cpp
|
toolbars_symbol_viewer.cpp
|
||||||
|
|
||||||
|
netlist_exporters/netlist_exporter_allegro.cpp
|
||||||
netlist_exporters/netlist_exporter_base.cpp
|
netlist_exporters/netlist_exporter_base.cpp
|
||||||
netlist_exporters/netlist_exporter_cadstar.cpp
|
netlist_exporters/netlist_exporter_cadstar.cpp
|
||||||
netlist_exporters/netlist_exporter_kicad.cpp
|
netlist_exporters/netlist_exporter_kicad.cpp
|
||||||
|
|
|
@ -59,14 +59,16 @@
|
||||||
|
|
||||||
|
|
||||||
/* panel (notebook page) identifiers */
|
/* panel (notebook page) identifiers */
|
||||||
enum panel_netlist_index {
|
enum panel_netlist_index
|
||||||
PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
|
{
|
||||||
PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
|
PANELPCBNEW = 0, /* Handle Netlist format Pcbnew */
|
||||||
PANELCADSTAR, /* Handle Netlist format CadStar */
|
PANELORCADPCB2, /* Handle Netlist format OracdPcb2 */
|
||||||
PANELSPICE, /* Handle Netlist format Spice */
|
PANELALLEGRO, /* Handle Netlist format Allegro */
|
||||||
PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
|
PANELCADSTAR, /* Handle Netlist format CadStar */
|
||||||
PANELCUSTOMBASE /* First auxiliary panel (custom netlists).
|
PANELSPICE, /* Handle Netlist format Spice */
|
||||||
* others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */
|
PANELSPICEMODEL, /* Handle Netlist format Spice Model (subcircuit) */
|
||||||
|
PANELCUSTOMBASE /* First auxiliary panel (custom netlists).
|
||||||
|
* others use PANELCUSTOMBASE+1, PANELCUSTOMBASE+2.. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,14 +247,17 @@ DIALOG_EXPORT_NETLIST::DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* parent ) :
|
||||||
page = nullptr;
|
page = nullptr;
|
||||||
|
|
||||||
// Add notebook pages:
|
// Add notebook pages:
|
||||||
m_PanelNetType[PANELPCBNEW] = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ),
|
m_PanelNetType[PANELPCBNEW] =
|
||||||
NET_TYPE_PCBNEW, false );
|
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "KiCad" ), NET_TYPE_PCBNEW, false );
|
||||||
|
|
||||||
m_PanelNetType[PANELORCADPCB2] = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ),
|
m_PanelNetType[PANELORCADPCB2] =
|
||||||
NET_TYPE_ORCADPCB2, false );
|
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "OrcadPCB2" ), NET_TYPE_ORCADPCB2, false );
|
||||||
|
|
||||||
m_PanelNetType[PANELCADSTAR] = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ),
|
m_PanelNetType[PANELALLEGRO] =
|
||||||
NET_TYPE_CADSTAR, false );
|
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false );
|
||||||
|
|
||||||
|
m_PanelNetType[PANELCADSTAR] =
|
||||||
|
new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false );
|
||||||
|
|
||||||
InstallPageSpice();
|
InstallPageSpice();
|
||||||
InstallPageSpiceModel();
|
InstallPageSpiceModel();
|
||||||
|
@ -496,6 +501,9 @@ bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow()
|
||||||
case NET_TYPE_ORCADPCB2:
|
case NET_TYPE_ORCADPCB2:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NET_TYPE_ALLEGRO:
|
||||||
|
break;
|
||||||
|
|
||||||
default: // custom, NET_TYPE_CUSTOM1 and greater
|
default: // custom, NET_TYPE_CUSTOM1 and greater
|
||||||
{
|
{
|
||||||
title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
|
title.Printf( _( "%s Export" ), currPage->m_TitleStringCtrl->GetValue() );
|
||||||
|
@ -629,6 +637,11 @@ bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt
|
||||||
fileWildcard = NetlistFileWildcard();
|
fileWildcard = NetlistFileWildcard();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NET_TYPE_ALLEGRO:
|
||||||
|
fileExt = AllegroNetlistFileExtension;
|
||||||
|
fileWildcard = AllegroNetlistFileWildcard();
|
||||||
|
break;
|
||||||
|
|
||||||
default: // custom, NET_TYPE_CUSTOM1 and greater
|
default: // custom, NET_TYPE_CUSTOM1 and greater
|
||||||
fileWildcard = AllFilesWildcard();
|
fileWildcard = AllFilesWildcard();
|
||||||
ret = false;
|
ret = false;
|
||||||
|
|
|
@ -1242,24 +1242,42 @@ LIB_FIELD* LIB_SYMBOL::GetFieldById( int aId ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LIB_FIELD* LIB_SYMBOL::FindField( const wxString& aFieldName )
|
LIB_FIELD* LIB_SYMBOL::FindField( const wxString& aFieldName, bool aCaseInsensitive )
|
||||||
{
|
{
|
||||||
for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
|
for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
|
||||||
{
|
{
|
||||||
if( static_cast<LIB_FIELD*>( &item )->GetCanonicalName() == aFieldName )
|
if( aCaseInsensitive )
|
||||||
return static_cast<LIB_FIELD*>( &item );
|
{
|
||||||
|
if( static_cast<LIB_FIELD*>( &item )->GetCanonicalName().Upper() == aFieldName.Upper() )
|
||||||
|
return static_cast<LIB_FIELD*>( &item );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( static_cast<LIB_FIELD*>( &item )->GetCanonicalName() == aFieldName )
|
||||||
|
return static_cast<LIB_FIELD*>( &item );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const LIB_FIELD* LIB_SYMBOL::FindField( const wxString& aFieldName ) const
|
const LIB_FIELD* LIB_SYMBOL::FindField( const wxString& aFieldName,
|
||||||
|
const bool aCaseInsensitive ) const
|
||||||
{
|
{
|
||||||
for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
|
for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
|
||||||
{
|
{
|
||||||
if( static_cast<const LIB_FIELD*>( &item )->GetCanonicalName() == aFieldName )
|
if( aCaseInsensitive )
|
||||||
return static_cast<const LIB_FIELD*>( &item );
|
{
|
||||||
|
if( static_cast<const LIB_FIELD*>( &item )->GetCanonicalName().Upper()
|
||||||
|
== aFieldName.Upper() )
|
||||||
|
return static_cast<const LIB_FIELD*>( &item );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( static_cast<const LIB_FIELD*>( &item )->GetCanonicalName() == aFieldName )
|
||||||
|
return static_cast<const LIB_FIELD*>( &item );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -292,10 +292,15 @@ public:
|
||||||
/**
|
/**
|
||||||
* Find a field within this symbol matching \a aFieldName and returns it
|
* Find a field within this symbol matching \a aFieldName and returns it
|
||||||
* or NULL if not found.
|
* or NULL if not found.
|
||||||
|
* @param aFieldName is the name of the field to find.
|
||||||
|
* @param aCaseInsensitive ignore the filed name case if true.
|
||||||
|
*
|
||||||
|
* @return the field if found or NULL if the field was not found.
|
||||||
*/
|
*/
|
||||||
LIB_FIELD* FindField( const wxString& aFieldName );
|
LIB_FIELD* FindField( const wxString& aFieldName, bool aCaseInsensitive = false );
|
||||||
|
|
||||||
const LIB_FIELD* FindField( const wxString& aFieldName ) const;
|
const LIB_FIELD* FindField( const wxString& aFieldName,
|
||||||
|
const bool aCaseInsensitive = false ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return pointer to the requested field.
|
* Return pointer to the requested field.
|
||||||
|
|
|
@ -40,6 +40,7 @@ enum NETLIST_TYPE_ID {
|
||||||
NET_TYPE_CADSTAR,
|
NET_TYPE_CADSTAR,
|
||||||
NET_TYPE_SPICE,
|
NET_TYPE_SPICE,
|
||||||
NET_TYPE_SPICE_MODEL,
|
NET_TYPE_SPICE_MODEL,
|
||||||
|
NET_TYPE_ALLEGRO,
|
||||||
NET_TYPE_CUSTOM1, /* NET_TYPE_CUSTOM1
|
NET_TYPE_CUSTOM1, /* NET_TYPE_CUSTOM1
|
||||||
* is the first id for user netlist format
|
* is the first id for user netlist format
|
||||||
* NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1
|
* NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1
|
||||||
|
|
|
@ -0,0 +1,797 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1992-2018 jp.charras at wanadoo.fr
|
||||||
|
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 1992-2021 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <confirm.h>
|
||||||
|
#include <refdes_utils.h>
|
||||||
|
#include <sch_edit_frame.h>
|
||||||
|
#include <sch_reference_list.h>
|
||||||
|
#include <string_utils.h>
|
||||||
|
#include <connection_graph.h>
|
||||||
|
#include <core/kicad_algo.h>
|
||||||
|
#include <symbol_library.h>
|
||||||
|
#include <symbol_lib_table.h>
|
||||||
|
#include <netlist.h>
|
||||||
|
#include "netlist_exporter_allegro.h"
|
||||||
|
#include "netlist_exporter_xml.h"
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
|
||||||
|
bool NETLIST_EXPORTER_ALLEGRO::WriteNetlist( const wxString& aOutFileName,
|
||||||
|
unsigned /* aNetlistOptions */,
|
||||||
|
REPORTER& aReporter )
|
||||||
|
{
|
||||||
|
m_f = nullptr;
|
||||||
|
wxString field;
|
||||||
|
wxString footprint;
|
||||||
|
int ret = 0; // zero now, OR in the sign bit on error
|
||||||
|
wxString netName;
|
||||||
|
|
||||||
|
// Create the devices directory
|
||||||
|
m_exportPath = wxFileName( aOutFileName ).GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR )
|
||||||
|
+ wxString( "devices" );
|
||||||
|
if( !wxDirExists( m_exportPath ) )
|
||||||
|
{
|
||||||
|
if( !wxMkdir( m_exportPath, wxS_DIR_DEFAULT ) )
|
||||||
|
{
|
||||||
|
wxString msg = wxString::Format( _( "Failed to create directory 'devices' ." ) );
|
||||||
|
aReporter.Report( msg, RPT_SEVERITY_ERROR );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the netlist file
|
||||||
|
if( ( m_f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == nullptr )
|
||||||
|
{
|
||||||
|
wxString msg = wxString::Format( _( "Failed to create file '%s'." ), aOutFileName );
|
||||||
|
aReporter.Report( msg, RPT_SEVERITY_ERROR );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fprintf( m_f, "(Source: %s)\n", TO_UTF8( m_schematic->GetFileName() ) );
|
||||||
|
ret |= fprintf( m_f, "(Date: %s)\n", TO_UTF8( DateAndTime() ) );
|
||||||
|
|
||||||
|
m_packageProperties.clear();
|
||||||
|
m_componentGroups.clear();
|
||||||
|
m_orderedSymbolsSheetpath.clear();
|
||||||
|
m_netNameNodes.clear();
|
||||||
|
|
||||||
|
extractComponentsInfo();
|
||||||
|
|
||||||
|
// Start with package definitions, which we create from component groups.
|
||||||
|
toAllegroPackages();
|
||||||
|
|
||||||
|
// Write out nets
|
||||||
|
toAllegroNets();
|
||||||
|
|
||||||
|
// Write out package properties. NOTE: Allegro doesn't recognize much...
|
||||||
|
toAllegroPackageProperties();
|
||||||
|
|
||||||
|
// Done with the netlist
|
||||||
|
fclose( m_f );
|
||||||
|
|
||||||
|
m_f = nullptr;
|
||||||
|
|
||||||
|
return ret >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NETLIST_EXPORTER_ALLEGRO::CompareSymbolSheetpath(
|
||||||
|
const std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>& aItem1,
|
||||||
|
const std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>& aItem2 )
|
||||||
|
{
|
||||||
|
wxString refText1 = aItem1.first->GetRef( &aItem1.second );
|
||||||
|
wxString refText2 = aItem2.first->GetRef( &aItem2.second );
|
||||||
|
|
||||||
|
if( refText1 == refText2 )
|
||||||
|
{
|
||||||
|
return aItem1.second.PathHumanReadable() < aItem2.second.PathHumanReadable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompareSymbolRef( refText1, refText2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NETLIST_EXPORTER_ALLEGRO::CompareSymbolRef( const wxString& aRefText1,
|
||||||
|
const wxString& aRefText2 )
|
||||||
|
{
|
||||||
|
if( removeTailDigits( aRefText1 ) == removeTailDigits( aRefText2 ) )
|
||||||
|
{
|
||||||
|
return extractTailNumber( aRefText1 ) < extractTailNumber( aRefText2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return aRefText1 < aRefText2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NETLIST_EXPORTER_ALLEGRO::CompareLibPin( const LIB_PIN* aPin1, const LIB_PIN* aPin2 )
|
||||||
|
{
|
||||||
|
// return "lhs < rhs"
|
||||||
|
return StrNumCmp( aPin1->GetShownNumber(), aPin2->GetShownNumber(), true ) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NETLIST_EXPORTER_ALLEGRO::extractComponentsInfo()
|
||||||
|
{
|
||||||
|
m_referencesAlreadyFound.Clear();
|
||||||
|
m_libParts.clear();
|
||||||
|
|
||||||
|
SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
|
||||||
|
|
||||||
|
for( unsigned ii = 0; ii < sheetList.size(); ii++ )
|
||||||
|
{
|
||||||
|
SCH_SHEET_PATH sheet = sheetList[ii];
|
||||||
|
m_schematic->SetCurrentSheet( sheet );
|
||||||
|
|
||||||
|
auto cmp = [sheet]( SCH_SYMBOL* a, SCH_SYMBOL* b )
|
||||||
|
{
|
||||||
|
return ( StrNumCmp( a->GetRef( &sheet, false ),
|
||||||
|
b->GetRef( &sheet, false ), true ) < 0 );
|
||||||
|
};
|
||||||
|
|
||||||
|
std::set<SCH_SYMBOL*, decltype( cmp )> ordered_symbols( cmp );
|
||||||
|
std::multiset<SCH_SYMBOL*, decltype( cmp )> extra_units( cmp );
|
||||||
|
|
||||||
|
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
|
||||||
|
{
|
||||||
|
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
|
||||||
|
auto test = ordered_symbols.insert( symbol );
|
||||||
|
|
||||||
|
if( !test.second )
|
||||||
|
{
|
||||||
|
if( ( *( test.first ) )->m_Uuid > symbol->m_Uuid )
|
||||||
|
{
|
||||||
|
extra_units.insert( *( test.first ) );
|
||||||
|
ordered_symbols.erase( test.first );
|
||||||
|
ordered_symbols.insert( symbol );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
extra_units.insert( symbol );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( EDA_ITEM* item : ordered_symbols )
|
||||||
|
{
|
||||||
|
SCH_SYMBOL* symbol = findNextSymbol( item, &sheet );
|
||||||
|
|
||||||
|
if( !symbol || symbol->GetExcludedFromBoard() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIB_PINS pinList;
|
||||||
|
pinList.clear();
|
||||||
|
symbol->GetLibPins(pinList);
|
||||||
|
|
||||||
|
if( !pinList.size() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_packageProperties.insert(std::pair<wxString, wxString>(sheet.PathHumanReadable(), symbol->GetRef(&sheet)));
|
||||||
|
m_orderedSymbolsSheetpath.push_back(std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>(symbol, sheet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString netCodeTxt;
|
||||||
|
wxString netName;
|
||||||
|
wxString ref;
|
||||||
|
|
||||||
|
struct NET_RECORD
|
||||||
|
{
|
||||||
|
NET_RECORD( const wxString& aName ) :
|
||||||
|
m_Name( aName )
|
||||||
|
{};
|
||||||
|
|
||||||
|
wxString m_Name;
|
||||||
|
std::vector<NET_NODE> m_Nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<NET_RECORD*> nets;
|
||||||
|
|
||||||
|
for( const auto& it : m_schematic->ConnectionGraph()->GetNetMap() )
|
||||||
|
{
|
||||||
|
wxString net_name = it.first.Name;
|
||||||
|
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs = it.second;
|
||||||
|
NET_RECORD* net_record = nullptr;
|
||||||
|
|
||||||
|
if( subgraphs.empty() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nets.emplace_back( new NET_RECORD( net_name ) );
|
||||||
|
net_record = nets.back();
|
||||||
|
|
||||||
|
for( CONNECTION_SUBGRAPH* subgraph : subgraphs )
|
||||||
|
{
|
||||||
|
bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() == SCH_NO_CONNECT_T;
|
||||||
|
const SCH_SHEET_PATH& sheet = subgraph->GetSheet();
|
||||||
|
|
||||||
|
for( SCH_ITEM* item : subgraph->GetItems() )
|
||||||
|
{
|
||||||
|
if( item->Type() == SCH_PIN_T )
|
||||||
|
{
|
||||||
|
SCH_PIN* pin = static_cast<SCH_PIN*>( item );
|
||||||
|
SCH_SYMBOL* symbol = pin->GetParentSymbol();
|
||||||
|
|
||||||
|
if( !symbol || symbol->GetExcludedFromBoard() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_record->m_Nodes.emplace_back( pin, sheet, nc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Netlist ordering: Net name, then ref des, then pin name
|
||||||
|
std::sort( nets.begin(), nets.end(),
|
||||||
|
[]( const NET_RECORD* a, const NET_RECORD*b )
|
||||||
|
{
|
||||||
|
return StrNumCmp( a->m_Name, b->m_Name ) < 0;
|
||||||
|
} );
|
||||||
|
|
||||||
|
for( int i = 0; i < (int) nets.size(); ++i )
|
||||||
|
{
|
||||||
|
NET_RECORD* net_record = nets[i];
|
||||||
|
|
||||||
|
// Netlist ordering: Net name, then ref des, then pin name
|
||||||
|
std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
|
||||||
|
[]( const NET_NODE& a, const NET_NODE& b )
|
||||||
|
{
|
||||||
|
wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
|
||||||
|
wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
|
||||||
|
|
||||||
|
if( refA == refB )
|
||||||
|
return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
|
||||||
|
|
||||||
|
return refA < refB;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Some duplicates can exist, for example on multi-unit parts with duplicated pins across
|
||||||
|
// units. If the user connects the pins on each unit, they will appear on separate
|
||||||
|
// subgraphs. Remove those here:
|
||||||
|
alg::remove_duplicates( net_record->m_Nodes,
|
||||||
|
[]( const NET_NODE& a, const NET_NODE& b )
|
||||||
|
{
|
||||||
|
wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
|
||||||
|
wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
|
||||||
|
|
||||||
|
return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
|
||||||
|
} );
|
||||||
|
|
||||||
|
for( const NET_NODE& netNode : net_record->m_Nodes )
|
||||||
|
{
|
||||||
|
wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
|
||||||
|
wxString pinText = netNode.m_Pin->GetShownNumber();
|
||||||
|
|
||||||
|
// Skip power symbols and virtual symbols
|
||||||
|
if( refText[0] == wxChar( '#' ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_netNameNodes.insert( std::pair<wxString, NET_NODE>( net_record->m_Name, netNode ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( NET_RECORD* record : nets )
|
||||||
|
delete record;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NETLIST_EXPORTER_ALLEGRO::toAllegroPackages()
|
||||||
|
{
|
||||||
|
int ret = 0; // zero now, OR in the sign bit on error
|
||||||
|
int groupCount = 1;
|
||||||
|
wxString deviceFileCreatingError = wxString( "" );
|
||||||
|
|
||||||
|
//Group the components......
|
||||||
|
while(!m_orderedSymbolsSheetpath.empty())
|
||||||
|
{
|
||||||
|
std::pair<SCH_SYMBOL*, SCH_SHEET_PATH> first_ele = m_orderedSymbolsSheetpath.front();
|
||||||
|
m_orderedSymbolsSheetpath.pop_front();
|
||||||
|
m_componentGroups.insert(
|
||||||
|
std::pair<int, std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>>( groupCount, first_ele ) );
|
||||||
|
|
||||||
|
for( auto it = m_orderedSymbolsSheetpath.begin(); it != m_orderedSymbolsSheetpath.end();
|
||||||
|
++it )
|
||||||
|
{
|
||||||
|
if( it->first->GetValueFieldText( false, &it->second, false )
|
||||||
|
!= first_ele.first->GetValueFieldText( false, &first_ele.second, false ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( it->first->GetFootprintFieldText( false, &it->second, false )
|
||||||
|
!= first_ele.first->GetFootprintFieldText( false, &first_ele.second, false ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString ref1 = it->first->GetRef( &it->second );
|
||||||
|
wxString ref2 = first_ele.first->GetRef( &first_ele.second );
|
||||||
|
if( removeTailDigits( ref1 ) == removeTailDigits( ref2 ) )
|
||||||
|
{
|
||||||
|
m_componentGroups.insert( std::pair<int, std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>>(
|
||||||
|
groupCount, ( *it ) ) );
|
||||||
|
it = m_orderedSymbolsSheetpath.erase( it );
|
||||||
|
if( std::distance( it, m_orderedSymbolsSheetpath.begin() ) > 0 )
|
||||||
|
it--;
|
||||||
|
else if( it == m_orderedSymbolsSheetpath.end() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groupCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= fprintf( m_f, "%s\n", "$PACKAGES" );
|
||||||
|
|
||||||
|
struct COMP_PACKAGE_STRUCT
|
||||||
|
{
|
||||||
|
wxString m_value;
|
||||||
|
wxString m_tolerance;
|
||||||
|
std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> m_symbolSheetpaths;
|
||||||
|
};
|
||||||
|
|
||||||
|
COMP_PACKAGE_STRUCT compPackageStruct;
|
||||||
|
std::map<wxString, COMP_PACKAGE_STRUCT> compPackageMap;
|
||||||
|
|
||||||
|
for( int groupIndex = 1; groupIndex < groupCount; groupIndex++ )
|
||||||
|
{
|
||||||
|
auto pairIter = m_componentGroups.equal_range(groupIndex);
|
||||||
|
auto beginIter = pairIter.first;
|
||||||
|
auto endIter = pairIter.second;
|
||||||
|
|
||||||
|
SCH_SYMBOL* sym = (beginIter->second).first;
|
||||||
|
SCH_SHEET_PATH sheetPath = (beginIter->second).second;
|
||||||
|
|
||||||
|
wxString valueText = sym->GetValueFieldText( false, &sheetPath, false );
|
||||||
|
wxString footprintText = sym->GetFootprintFieldText( false, &sheetPath, false);
|
||||||
|
wxString deviceType = valueText + wxString("_") + footprintText;
|
||||||
|
|
||||||
|
while( deviceType.GetChar(deviceType.Length()-1) == '_' )
|
||||||
|
{
|
||||||
|
deviceType.RemoveLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceType = formatDevice( deviceType );
|
||||||
|
|
||||||
|
wxArrayString fieldArray;
|
||||||
|
fieldArray.Add("Spice_Model");
|
||||||
|
fieldArray.Add("VALUE");
|
||||||
|
|
||||||
|
wxString value = getGroupField( groupIndex, fieldArray );
|
||||||
|
|
||||||
|
fieldArray.clear();
|
||||||
|
fieldArray.Add("TOLERANCE");
|
||||||
|
fieldArray.Add("TOL");
|
||||||
|
wxString tol = getGroupField( groupIndex, fieldArray );
|
||||||
|
|
||||||
|
std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> symbolSheetpaths;
|
||||||
|
|
||||||
|
for( auto iter = beginIter; iter != endIter; iter++ )
|
||||||
|
{
|
||||||
|
symbolSheetpaths.push_back( std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>(
|
||||||
|
iter->second.first, iter->second.second ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stable_sort( symbolSheetpaths.begin(), symbolSheetpaths.end(),
|
||||||
|
NETLIST_EXPORTER_ALLEGRO::CompareSymbolSheetpath );
|
||||||
|
|
||||||
|
compPackageStruct.m_value = value;
|
||||||
|
compPackageStruct.m_tolerance = tol;
|
||||||
|
compPackageStruct.m_symbolSheetpaths = symbolSheetpaths;
|
||||||
|
compPackageMap.insert( std::pair( deviceType, compPackageStruct ) );
|
||||||
|
|
||||||
|
// Write out the corresponding device file
|
||||||
|
FILE* d = nullptr;
|
||||||
|
wxString deviceFileName = wxFileName(m_exportPath, deviceType, wxString("txt")).GetFullPath();
|
||||||
|
if( ( d = wxFopen( deviceFileName, wxT( "wt" ) ) ) == nullptr )
|
||||||
|
{
|
||||||
|
wxString msg;
|
||||||
|
msg.Printf( _( "Failed to create file '%s'.\n" ), deviceFileName );
|
||||||
|
deviceFileCreatingError += msg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
footprintText = footprintText.AfterLast( ':' );
|
||||||
|
|
||||||
|
wxArrayString footprintAlt;
|
||||||
|
wxArrayString footprintArray = sym->GetLibSymbolRef()->GetFPFilters();
|
||||||
|
|
||||||
|
for( auto fp : footprintArray )
|
||||||
|
{
|
||||||
|
if( ( fp.Find( '*' ) != wxNOT_FOUND ) || ( fp.Find( '?' ) != wxNOT_FOUND ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
footprintAlt.Add( fp.AfterLast( ':' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( footprintText.IsEmpty() )
|
||||||
|
{
|
||||||
|
if( !footprintAlt.IsEmpty() )
|
||||||
|
{
|
||||||
|
footprintText = footprintAlt[0];
|
||||||
|
footprintAlt.RemoveAt( 0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
footprintText = deviceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( d, "PACKAGE '%s'\n", TO_UTF8( formatDevice( footprintText ) ) );
|
||||||
|
fprintf( d, "CLASS IC\n" );
|
||||||
|
|
||||||
|
LIB_PINS pinList;
|
||||||
|
sym->GetLibSymbolRef()->GetPins( pinList, 0, 0 );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must erase redundant Pins references in pinList
|
||||||
|
* These redundant pins exist because some pins are found more than one time when a
|
||||||
|
* symbol has multiple parts per package or has 2 representations (DeMorgan conversion).
|
||||||
|
* For instance, a 74ls00 has DeMorgan conversion, with different pin shapes, and
|
||||||
|
* therefore each pin appears 2 times in the list. Common pins (VCC, GND) can also be
|
||||||
|
* found more than once.
|
||||||
|
*/
|
||||||
|
sort( pinList.begin(), pinList.end(), NETLIST_EXPORTER_ALLEGRO::CompareLibPin );
|
||||||
|
for( int ii = 0; ii < (int) pinList.size() - 1; ii++ )
|
||||||
|
{
|
||||||
|
if( pinList[ii]->GetNumber() == pinList[ii + 1]->GetNumber() )
|
||||||
|
{ // 2 pins have the same number, remove the redundant pin at index i+1
|
||||||
|
pinList.erase( pinList.begin() + ii + 1 );
|
||||||
|
ii--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int pinCount = pinList.size();
|
||||||
|
fprintf( d, "PINCOUNT %u\n", pinCount );
|
||||||
|
|
||||||
|
if( pinCount > 0 )
|
||||||
|
{
|
||||||
|
fprintf( d, "%s", TO_UTF8( formatFunction( "main", pinList ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !value.IsEmpty() )
|
||||||
|
{
|
||||||
|
fprintf( d, "PACKAGEPROP VALUE %s\n", TO_UTF8( value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !tol.IsEmpty() )
|
||||||
|
{
|
||||||
|
fprintf( d, "PACKAGEPROP TOL %s\n", TO_UTF8( tol ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !footprintAlt.IsEmpty() )
|
||||||
|
{
|
||||||
|
fprintf( d, "PACKAGEPROP ALT_SYMBOLS '(" );
|
||||||
|
|
||||||
|
wxString footprintAltSymbolsText;
|
||||||
|
for( auto fp : footprintAlt )
|
||||||
|
{
|
||||||
|
footprintAltSymbolsText += fp + wxString( "," );
|
||||||
|
}
|
||||||
|
footprintAltSymbolsText.Truncate( footprintAltSymbolsText.Length() - 1 );
|
||||||
|
fprintf( d, "%s)'\n", TO_UTF8( footprintAltSymbolsText ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxArrayString propArray;
|
||||||
|
propArray.Add( "PART_NUMBER" );
|
||||||
|
propArray.Add( "mpn" );
|
||||||
|
propArray.Add( "mfr_pn" );
|
||||||
|
wxString data = getGroupField( groupIndex, propArray );
|
||||||
|
if(!data.IsEmpty())
|
||||||
|
{
|
||||||
|
fprintf( d, "PACKAGEPROP %s %s\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
propArray.clear();
|
||||||
|
propArray.Add( "HEIGHT" );
|
||||||
|
data = getGroupField( groupIndex, propArray );
|
||||||
|
if(!data.IsEmpty())
|
||||||
|
{
|
||||||
|
fprintf( d, "PACKAGEPROP %s %s\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( d, "END\n" );
|
||||||
|
|
||||||
|
fclose( d );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( auto iter = compPackageMap.begin(); iter != compPackageMap.end(); iter++ )
|
||||||
|
{
|
||||||
|
wxString deviceType = iter->first;
|
||||||
|
wxString value = iter->second.m_value;
|
||||||
|
wxString tolerance = iter->second.m_tolerance;
|
||||||
|
|
||||||
|
if( value.IsEmpty() && tolerance.IsEmpty() )
|
||||||
|
{
|
||||||
|
ret |= fprintf( m_f, "!%s;", TO_UTF8( deviceType ) );
|
||||||
|
}
|
||||||
|
else if( tolerance.IsEmpty() )
|
||||||
|
{
|
||||||
|
ret |= fprintf( m_f, "!%s!%s;", TO_UTF8( deviceType ), TO_UTF8( value ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret |= fprintf( m_f, "!%s!%s!%s;", TO_UTF8( deviceType ), TO_UTF8( value ),
|
||||||
|
TO_UTF8( tolerance ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> symbolSheetpaths =
|
||||||
|
iter->second.m_symbolSheetpaths;
|
||||||
|
|
||||||
|
for( auto it = symbolSheetpaths.begin(); it != symbolSheetpaths.end(); it++ )
|
||||||
|
{
|
||||||
|
SCH_SYMBOL* sym = it->first;
|
||||||
|
SCH_SHEET_PATH sheetPath = it->second;
|
||||||
|
wxString refText = sym->GetRef( &sheetPath );
|
||||||
|
ret |= fprintf( m_f, ",\n\t%s", TO_UTF8( refText ) );
|
||||||
|
}
|
||||||
|
ret |= fprintf( m_f, "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !deviceFileCreatingError.IsEmpty() )
|
||||||
|
{
|
||||||
|
DisplayError( nullptr, deviceFileCreatingError );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString NETLIST_EXPORTER_ALLEGRO::formatText( wxString aString )
|
||||||
|
{
|
||||||
|
if( aString.IsEmpty() )
|
||||||
|
{
|
||||||
|
return wxString( "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
aString.Replace( "\u03BC", "u" );
|
||||||
|
|
||||||
|
std::regex reg( "[!']|[^ -~]" );
|
||||||
|
wxString processedString = wxString( std::regex_replace( std::string( aString ), reg, "?" ) );
|
||||||
|
|
||||||
|
std::regex search_reg( "[^a-zA-Z0-9_/]" );
|
||||||
|
if( std::regex_search( std::string( processedString ), search_reg ) )
|
||||||
|
{
|
||||||
|
return wxString( "'" ) + processedString + wxString( "'" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return processedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString NETLIST_EXPORTER_ALLEGRO::formatPin( const LIB_PIN& aPin )
|
||||||
|
{
|
||||||
|
wxString pinName4Telesis = aPin.GetName() + wxString( "__" ) + aPin.GetNumber();
|
||||||
|
std::regex reg( "[^A-Za-z0-9_+?/-]" );
|
||||||
|
return wxString( std::regex_replace( std::string( pinName4Telesis ), reg, "?" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString NETLIST_EXPORTER_ALLEGRO::formatFunction( wxString aName, LIB_PINS aPinList )
|
||||||
|
{
|
||||||
|
aName.MakeUpper();
|
||||||
|
std::list<wxString> pinNameList;
|
||||||
|
|
||||||
|
std::stable_sort( aPinList.begin(), aPinList.end(), NETLIST_EXPORTER_ALLEGRO::CompareLibPin );
|
||||||
|
|
||||||
|
for( auto pin : aPinList )
|
||||||
|
{
|
||||||
|
pinNameList.push_back( formatPin( *pin ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString out_str = "";
|
||||||
|
wxString str;
|
||||||
|
|
||||||
|
out_str.Printf( wxT( "PINORDER %s " ), TO_UTF8( aName ) );
|
||||||
|
|
||||||
|
for( auto pinName : pinNameList )
|
||||||
|
{
|
||||||
|
str.Printf( ",\n\t%s", TO_UTF8( pinName ) );
|
||||||
|
out_str += str;
|
||||||
|
}
|
||||||
|
out_str += wxString( "\n" );
|
||||||
|
|
||||||
|
str.Printf( wxT( "FUNCTION %s %s " ), TO_UTF8( aName ), TO_UTF8( aName ) );
|
||||||
|
out_str += str;
|
||||||
|
|
||||||
|
for( auto pin : aPinList )
|
||||||
|
{
|
||||||
|
str.Printf( ",\n\t%s", TO_UTF8( pin->GetNumber() ) );
|
||||||
|
out_str += str;
|
||||||
|
}
|
||||||
|
out_str += wxString( "\n" );
|
||||||
|
|
||||||
|
return out_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString NETLIST_EXPORTER_ALLEGRO::getGroupField( int aGroupIndex, const wxArrayString& aFieldArray,
|
||||||
|
bool aSanitize )
|
||||||
|
{
|
||||||
|
auto pairIter = m_componentGroups.equal_range( aGroupIndex );
|
||||||
|
|
||||||
|
for( auto iter = pairIter.first; iter != pairIter.second; ++iter )
|
||||||
|
{
|
||||||
|
SCH_SYMBOL* sym = ( iter->second ).first;
|
||||||
|
SCH_SHEET_PATH sheetPath = ( iter->second ).second;
|
||||||
|
|
||||||
|
for( auto field : aFieldArray )
|
||||||
|
{
|
||||||
|
SCH_FIELD* fld = sym->FindField( field, true, true );
|
||||||
|
if( fld != NULL )
|
||||||
|
{
|
||||||
|
wxString fieldText = fld->GetShownText( &sheetPath, true );
|
||||||
|
if( !fieldText.IsEmpty() )
|
||||||
|
{
|
||||||
|
if( aSanitize )
|
||||||
|
{
|
||||||
|
return formatText( fieldText );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return fieldText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for( auto iter = pairIter.first; iter != pairIter.second; ++iter )
|
||||||
|
{
|
||||||
|
SCH_SYMBOL* sym = ( iter->second ).first;
|
||||||
|
SCH_SHEET_PATH sheetPath = ( iter->second ).second;
|
||||||
|
|
||||||
|
for( auto field : aFieldArray )
|
||||||
|
{
|
||||||
|
LIB_FIELD* fld = sym->GetLibSymbolRef()->FindField( field, true );
|
||||||
|
if( fld != NULL )
|
||||||
|
{
|
||||||
|
wxString fieldText = fld->GetShownText( &sheetPath, true );
|
||||||
|
if( !fieldText.IsEmpty() )
|
||||||
|
{
|
||||||
|
if( aSanitize )
|
||||||
|
{
|
||||||
|
return formatText( fieldText );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return fieldText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wxString( "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString NETLIST_EXPORTER_ALLEGRO::formatDevice( wxString aString )
|
||||||
|
{
|
||||||
|
aString.MakeLower();
|
||||||
|
std::regex reg( "[^a-z0-9_-]" );
|
||||||
|
return wxString( std::regex_replace( std::string( aString ), reg, "_" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void NETLIST_EXPORTER_ALLEGRO::toAllegroPackageProperties()
|
||||||
|
{
|
||||||
|
int ret = 0; // zero now, OR in the sign bit on error
|
||||||
|
|
||||||
|
ret |= fprintf( m_f, "%s\n", "$PACKAGES" );
|
||||||
|
ret |= fprintf( m_f, "%s\n", "$A_PROPERTIES" );
|
||||||
|
|
||||||
|
while( !m_packageProperties.empty() )
|
||||||
|
{
|
||||||
|
std::multimap<wxString, wxString>::iterator iter = m_packageProperties.begin();
|
||||||
|
wxString sheetPathText = iter->first;
|
||||||
|
|
||||||
|
ret |= fprintf( m_f, "ROOM %s;", TO_UTF8( formatText( sheetPathText ) ) );
|
||||||
|
|
||||||
|
std::vector<wxString> refTexts;
|
||||||
|
|
||||||
|
auto pairIter = m_packageProperties.equal_range( sheetPathText );
|
||||||
|
for( iter = pairIter.first; iter != pairIter.second; ++iter )
|
||||||
|
{
|
||||||
|
wxString refText = iter->second;
|
||||||
|
refTexts.push_back( refText );
|
||||||
|
}
|
||||||
|
m_packageProperties.erase( pairIter.first, pairIter.second );
|
||||||
|
|
||||||
|
std::stable_sort( refTexts.begin(), refTexts.end(),
|
||||||
|
NETLIST_EXPORTER_ALLEGRO::CompareSymbolRef );
|
||||||
|
|
||||||
|
for( auto it = refTexts.begin(); it != refTexts.end(); it++ )
|
||||||
|
{
|
||||||
|
ret |= fprintf( m_f, ",\n\t%s", TO_UTF8( *it ) );
|
||||||
|
}
|
||||||
|
ret |= fprintf( m_f, "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NETLIST_EXPORTER_ALLEGRO::toAllegroNets()
|
||||||
|
{
|
||||||
|
int ret = 0; // zero now, OR in the sign bit on error
|
||||||
|
|
||||||
|
ret |= fprintf( m_f, "%s\n", "$NETS" );
|
||||||
|
|
||||||
|
while( !m_netNameNodes.empty() )
|
||||||
|
{
|
||||||
|
std::multimap<wxString, NET_NODE>::iterator iter = m_netNameNodes.begin();
|
||||||
|
std::vector<NET_NODE> netNodes;
|
||||||
|
|
||||||
|
wxString netName = iter->first;
|
||||||
|
|
||||||
|
ret |= fprintf( m_f, "%s;", TO_UTF8( formatText( netName ).MakeUpper() ) );
|
||||||
|
|
||||||
|
auto pairIter = m_netNameNodes.equal_range( netName );
|
||||||
|
for( iter = pairIter.first; iter != pairIter.second; ++iter )
|
||||||
|
{
|
||||||
|
NET_NODE netNode = iter->second;
|
||||||
|
netNodes.push_back( netNode );
|
||||||
|
}
|
||||||
|
m_netNameNodes.erase( pairIter.first, pairIter.second );
|
||||||
|
|
||||||
|
std::stable_sort( netNodes.begin(), netNodes.end() );
|
||||||
|
|
||||||
|
for( auto it = netNodes.begin(); it != netNodes.end(); it++ )
|
||||||
|
{
|
||||||
|
NET_NODE netNode = *it;
|
||||||
|
wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
|
||||||
|
wxString pinText = netNode.m_Pin->GetShownNumber();
|
||||||
|
ret |= fprintf( m_f, ",\n\t%s.%s", TO_UTF8( refText ), TO_UTF8( pinText ) );
|
||||||
|
}
|
||||||
|
ret |= fprintf( m_f, "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString NETLIST_EXPORTER_ALLEGRO::removeTailDigits( wxString aString )
|
||||||
|
{
|
||||||
|
while( ( aString.GetChar( aString.Length() - 1 ) >= '0' )
|
||||||
|
&& ( aString.GetChar( aString.Length() - 1 ) <= '9' ) )
|
||||||
|
{
|
||||||
|
aString.RemoveLast();
|
||||||
|
}
|
||||||
|
return aString;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NETLIST_EXPORTER_ALLEGRO::extractTailNumber( wxString aString )
|
||||||
|
{
|
||||||
|
wxString numString;
|
||||||
|
while( ( aString.GetChar( aString.Length() - 1 ) >= '0' )
|
||||||
|
&& ( aString.GetChar( aString.Length() - 1 ) <= '9' ) )
|
||||||
|
{
|
||||||
|
numString.insert( 0, aString.GetChar( aString.Length() - 1 ) );
|
||||||
|
aString.RemoveLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long val;
|
||||||
|
//From wxWidgets 3.1.6, here we can use ToUInt instead of ToULong function.
|
||||||
|
numString.ToULong( &val );
|
||||||
|
return (unsigned int) val;
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1992-2013 jp.charras at wanadoo.fr
|
||||||
|
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
|
* Copyright (C) 1992-2021 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NETLIST_EXPORTER_ALLEGRO_H
|
||||||
|
#define NETLIST_EXPORTER_ALLEGRO_H
|
||||||
|
|
||||||
|
#include "netlist_exporter_base.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a netlist compatible with Allegro.
|
||||||
|
*/
|
||||||
|
class NETLIST_EXPORTER_ALLEGRO : public NETLIST_EXPORTER_BASE
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NETLIST_EXPORTER_ALLEGRO( SCHEMATIC* aSchematic ) :
|
||||||
|
NETLIST_EXPORTER_BASE( aSchematic )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write netlist to \a aOutFileName.
|
||||||
|
* Generate the Allegro netlist format supported by Allegro.
|
||||||
|
*/
|
||||||
|
bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions,
|
||||||
|
REPORTER& aReporter ) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two std::pair<SCH_SYMBOL*, SCH_SHEET_PATH> variables.
|
||||||
|
*
|
||||||
|
* @param aItem1 comparing object 1
|
||||||
|
* @param aItem2 comparing object 2
|
||||||
|
* @return true if aItem1 < aItem2
|
||||||
|
*/
|
||||||
|
static bool CompareSymbolSheetpath( const std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>& aItem1,
|
||||||
|
const std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>& aItem2 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two wxString variables.
|
||||||
|
*
|
||||||
|
* @param aRefText1
|
||||||
|
* @param aRefText2
|
||||||
|
* @return bool value
|
||||||
|
*/
|
||||||
|
static bool CompareSymbolRef( const wxString& aRefText1, const wxString& aRefText2 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two LIB_PIN* variables.
|
||||||
|
*
|
||||||
|
* @param aPin1
|
||||||
|
* @param aPin2
|
||||||
|
* @return bool value
|
||||||
|
*/
|
||||||
|
static bool CompareLibPin( const LIB_PIN* aPin1, const LIB_PIN* aPin2 );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void extractComponentsInfo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the $PACKAGES section
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void toAllegroPackages();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the $NETS section
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void toAllegroNets();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write $A_PROPERTIES section
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void toAllegroPackageProperties();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string into one safe for a Telesis device name.
|
||||||
|
* These are all lowercase and have a more restricted set of characters.
|
||||||
|
* FIXME: replace unsupported characters with an encoding instead
|
||||||
|
*
|
||||||
|
* @param aString wxString to be formatted.
|
||||||
|
* @return a formatted wxString.
|
||||||
|
*/
|
||||||
|
wxString formatDevice( wxString aString );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string into Telesis-safe format. Unsupported characters are
|
||||||
|
* replaced with ?'s, and the string is quoted if necessary.
|
||||||
|
* FIXME: replace unsupported characters with an encoding instead, to avoid
|
||||||
|
* having similar strings mapped to each other.
|
||||||
|
*
|
||||||
|
* @param aString
|
||||||
|
* @return wxString
|
||||||
|
*/
|
||||||
|
wxString formatText( wxString aString );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a Telesis-compatible pin name from a pin node.
|
||||||
|
* Telesis requires all pin names to be unique, and doesn't have separate
|
||||||
|
* fields for pin number and pin name/function, so we combine them together to
|
||||||
|
* make a unique name that still describes its function if you check pin info.
|
||||||
|
* FIXME: replace unsupported characters with an encoding instead
|
||||||
|
*
|
||||||
|
* @param aPin
|
||||||
|
* @return wxString
|
||||||
|
*/
|
||||||
|
wxString formatPin( const LIB_PIN& aPin );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the definition of a function in Telesis format, which consists of
|
||||||
|
* multiple declarations (PINORDER, PINSWAP, and FUNCTIONs).
|
||||||
|
*
|
||||||
|
* @param aName
|
||||||
|
* @param aPinList
|
||||||
|
* @return wxString
|
||||||
|
*/
|
||||||
|
wxString formatFunction( wxString aName, LIB_PINS aPinList );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a field for a component group, which may have mismatched case, or
|
||||||
|
* the component group may not have the field defined and instead the library
|
||||||
|
* entry has to be searched. Returns None if no fields exist.
|
||||||
|
*
|
||||||
|
* @param aGroupIndex the component group index to query
|
||||||
|
* @param aFieldArray one or more (equivalent) fields to query, in the order specified.
|
||||||
|
* first field that exists is returned.
|
||||||
|
* @param aSanitize if true (default), will format/escape the field for Telesis output
|
||||||
|
* @return return the found field, or return wxString("") if no field exist.
|
||||||
|
*/
|
||||||
|
wxString getGroupField( int aGroupIndex, const wxArrayString& aFieldArray,
|
||||||
|
bool aSanitize = true );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the str's tailing digits.
|
||||||
|
*
|
||||||
|
* @param aString
|
||||||
|
* @return wxString
|
||||||
|
*/
|
||||||
|
static wxString removeTailDigits( wxString aString );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the str's tailing number.
|
||||||
|
*
|
||||||
|
* @param aString
|
||||||
|
* @return unsigned int
|
||||||
|
*/
|
||||||
|
static unsigned int extractTailNumber( wxString aString );
|
||||||
|
|
||||||
|
struct NET_NODE
|
||||||
|
{
|
||||||
|
NET_NODE( SCH_PIN* aPin, const SCH_SHEET_PATH& aSheet, bool aNoConnect ) :
|
||||||
|
m_Pin( aPin ),
|
||||||
|
m_Sheet( aSheet ),
|
||||||
|
m_NoConnect( aNoConnect )
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator<( const NET_NODE& aNetNode ) const
|
||||||
|
{
|
||||||
|
wxString refText1 = m_Pin->GetParentSymbol()->GetRef( &m_Sheet );
|
||||||
|
wxString refText2 = aNetNode.m_Pin->GetParentSymbol()->GetRef( &aNetNode.m_Sheet );
|
||||||
|
if( refText1 == refText2 )
|
||||||
|
{
|
||||||
|
unsigned long val1, val2;
|
||||||
|
//From wxWidgets 3.1.6, the function ToULong can be repalced with ToUInt
|
||||||
|
bool convertingResult = m_Pin->GetShownNumber().ToULong( &val1 );
|
||||||
|
convertingResult &= aNetNode.m_Pin->GetShownNumber().ToULong( &val2 );
|
||||||
|
if( convertingResult )
|
||||||
|
{
|
||||||
|
return val1 < val2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_Pin->GetShownNumber() < aNetNode.m_Pin->GetShownNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CompareSymbolRef( refText1, refText2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
SCH_PIN* m_Pin;
|
||||||
|
SCH_SHEET_PATH m_Sheet;
|
||||||
|
bool m_NoConnect;
|
||||||
|
};
|
||||||
|
|
||||||
|
FILE* m_f; ///< file pointer for netlist file writing operation
|
||||||
|
wxString m_exportPath; ///< directory to store device files
|
||||||
|
std::multimap<wxString, wxString> m_packageProperties;
|
||||||
|
std::multimap<int, std::pair<SCH_SYMBOL*, SCH_SHEET_PATH> > m_componentGroups; ///< Store the component group
|
||||||
|
std::list<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>>
|
||||||
|
m_orderedSymbolsSheetpath; ///< Store the ordered symbols with sheetpath
|
||||||
|
std::multimap<wxString, NET_NODE> m_netNameNodes; ///< Store the NET_NODE with the net name
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -41,6 +41,7 @@
|
||||||
#include <netlist_exporter_spice.h>
|
#include <netlist_exporter_spice.h>
|
||||||
#include <netlist_exporter_spice_model.h>
|
#include <netlist_exporter_spice_model.h>
|
||||||
#include <netlist_exporter_kicad.h>
|
#include <netlist_exporter_kicad.h>
|
||||||
|
#include <netlist_exporter_allegro.h>
|
||||||
#include <netlist_exporter_xml.h>
|
#include <netlist_exporter_xml.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,6 +89,10 @@ bool SCH_EDIT_FRAME::WriteNetListFile( int aFormat, const wxString& aFullFileNam
|
||||||
helper = new NETLIST_EXPORTER_SPICE_MODEL( sch );
|
helper = new NETLIST_EXPORTER_SPICE_MODEL( sch );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NET_TYPE_ALLEGRO:
|
||||||
|
helper = new NETLIST_EXPORTER_ALLEGRO( sch );
|
||||||
|
break;
|
||||||
|
|
||||||
case NET_TYPE_BOM:
|
case NET_TYPE_BOM:
|
||||||
// When generating the BOM, we have a bare filename so don't strip
|
// When generating the BOM, we have a bare filename so don't strip
|
||||||
// the extension or you might string a '.' from the middle of the filename
|
// the extension or you might string a '.' from the middle of the filename
|
||||||
|
|
|
@ -953,14 +953,23 @@ void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SCH_FIELD* SCH_SYMBOL::FindField( const wxString& aFieldName, bool aIncludeDefaultFields )
|
SCH_FIELD* SCH_SYMBOL::FindField( const wxString& aFieldName, bool aIncludeDefaultFields,
|
||||||
|
bool aCaseInsensitive )
|
||||||
{
|
{
|
||||||
unsigned start = aIncludeDefaultFields ? 0 : MANDATORY_FIELDS;
|
unsigned start = aIncludeDefaultFields ? 0 : MANDATORY_FIELDS;
|
||||||
|
|
||||||
for( unsigned i = start; i < m_fields.size(); ++i )
|
for( unsigned i = start; i < m_fields.size(); ++i )
|
||||||
{
|
{
|
||||||
if( aFieldName == m_fields[i].GetName( false ) )
|
if( aCaseInsensitive )
|
||||||
return &m_fields[i];
|
{
|
||||||
|
if( aFieldName.Upper() == m_fields[i].GetName( false ).Upper() )
|
||||||
|
return &m_fields[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( aFieldName == m_fields[i].GetName( false ) )
|
||||||
|
return &m_fields[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -458,10 +458,12 @@ public:
|
||||||
*
|
*
|
||||||
* @param aFieldName is the name of the field to find.
|
* @param aFieldName is the name of the field to find.
|
||||||
* @param aIncludeDefaultFields searches the library symbol default fields if true.
|
* @param aIncludeDefaultFields searches the library symbol default fields if true.
|
||||||
|
* @param aCaseInsensitive ignore the filed name case if true.
|
||||||
*
|
*
|
||||||
* @return the field if found or NULL if the field was not found.
|
* @return the field if found or NULL if the field was not found.
|
||||||
*/
|
*/
|
||||||
SCH_FIELD* FindField( const wxString& aFieldName, bool aIncludeDefaultFields = true );
|
SCH_FIELD* FindField( const wxString& aFieldName, bool aIncludeDefaultFields = true,
|
||||||
|
bool aCaseInsensitive = false );
|
||||||
|
|
||||||
const wxString GetValueFieldText( bool aResolve, const SCH_SHEET_PATH* aPath,
|
const wxString GetValueFieldText( bool aResolve, const SCH_SHEET_PATH* aPath,
|
||||||
bool aAllowExtraText ) const;
|
bool aAllowExtraText ) const;
|
||||||
|
|
|
@ -128,6 +128,7 @@ extern const std::string SpiceFileExtension;
|
||||||
extern const std::string CadstarNetlistFileExtension;
|
extern const std::string CadstarNetlistFileExtension;
|
||||||
extern const std::string OrCadPcb2NetlistFileExtension;
|
extern const std::string OrCadPcb2NetlistFileExtension;
|
||||||
extern const std::string NetlistFileExtension;
|
extern const std::string NetlistFileExtension;
|
||||||
|
extern const std::string AllegroNetlistFileExtension;
|
||||||
extern const std::string GerberFileExtension;
|
extern const std::string GerberFileExtension;
|
||||||
extern const std::string GerberJobFileExtension;
|
extern const std::string GerberJobFileExtension;
|
||||||
extern const std::string HtmlFileExtension;
|
extern const std::string HtmlFileExtension;
|
||||||
|
@ -211,6 +212,7 @@ extern wxString LegacySchematicFileWildcard();
|
||||||
extern wxString BoardFileWildcard();
|
extern wxString BoardFileWildcard();
|
||||||
extern wxString OrCadPcb2NetlistFileWildcard();
|
extern wxString OrCadPcb2NetlistFileWildcard();
|
||||||
extern wxString NetlistFileWildcard();
|
extern wxString NetlistFileWildcard();
|
||||||
|
extern wxString AllegroNetlistFileWildcard();
|
||||||
extern wxString HtmlFileWildcard();
|
extern wxString HtmlFileWildcard();
|
||||||
extern wxString CsvFileWildcard();
|
extern wxString CsvFileWildcard();
|
||||||
extern wxString LegacyPcbFileWildcard();
|
extern wxString LegacyPcbFileWildcard();
|
||||||
|
|
Loading…
Reference in New Issue