From cb01bca1f4a362b27d479fad78068fa9d105e806 Mon Sep 17 00:00:00 2001 From: Marek Roszko Date: Sat, 9 Mar 2024 09:57:24 -0500 Subject: [PATCH] Add PADS netlist format export --- common/wildcards_and_files_ext.cpp | 7 + eeschema/CMakeLists.txt | 1 + eeschema/dialogs/dialog_export_netlist.cpp | 13 ++ eeschema/netlist_exporters/netlist.h | 1 + .../netlist_exporter_pads.cpp | 204 ++++++++++++++++++ .../netlist_exporters/netlist_exporter_pads.h | 59 +++++ .../netlist_exporters/netlist_generator.cpp | 7 +- include/wildcards_and_files_ext.h | 2 + 8 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 eeschema/netlist_exporters/netlist_exporter_pads.cpp create mode 100644 eeschema/netlist_exporters/netlist_exporter_pads.h diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp index 52eba28183..2946263abe 100644 --- a/common/wildcards_and_files_ext.cpp +++ b/common/wildcards_and_files_ext.cpp @@ -145,6 +145,7 @@ const std::string FILEEXT::CadstarNetlistFileExtension( "frp" ); const std::string FILEEXT::OrCadPcb2NetlistFileExtension( "net" ); const std::string FILEEXT::NetlistFileExtension( "net" ); const std::string FILEEXT::AllegroNetlistFileExtension( "txt" ); +const std::string FILEEXT::PADSNetlistFileExtension( "asc" ); const std::string FILEEXT::FootprintAssignmentFileExtension( "cmp" ); const std::string FILEEXT::GerberFileExtension( "gbr" ); const std::string FILEEXT::GerberJobFileExtension( "gbrjob" ); @@ -293,6 +294,12 @@ wxString FILEEXT::AllegroNetlistFileWildcard() } +wxString FILEEXT::PADSNetlistFileWildcard() +{ + return _( "PADS netlist files" ) + AddFileExtListToFilter( { PADSNetlistFileExtension } ); +} + + wxString FILEEXT::EasyEdaArchiveWildcard() { return _( "EasyEDA (JLCEDA) Std backup archive" ) + AddFileExtListToFilter( { "zip" } ); diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index bec96364c1..014ce6ca40 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -424,6 +424,7 @@ set( EESCHEMA_SRCS netlist_exporters/netlist_exporter_base.cpp netlist_exporters/netlist_exporter_cadstar.cpp netlist_exporters/netlist_exporter_kicad.cpp + netlist_exporters/netlist_exporter_pads.cpp netlist_exporters/netlist_exporter_orcadpcb2.cpp netlist_exporters/netlist_exporter_spice.cpp netlist_exporters/netlist_exporter_spice_model.cpp diff --git a/eeschema/dialogs/dialog_export_netlist.cpp b/eeschema/dialogs/dialog_export_netlist.cpp index 7d24a3bb35..74350c0a80 100644 --- a/eeschema/dialogs/dialog_export_netlist.cpp +++ b/eeschema/dialogs/dialog_export_netlist.cpp @@ -70,6 +70,7 @@ enum PANEL_NETLIST_INDEX 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). @@ -264,6 +265,9 @@ DIALOG_EXPORT_NETLIST::DIALOG_EXPORT_NETLIST( SCH_EDIT_FRAME* parent ) : m_PanelNetType[PANELALLEGRO] = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "Allegro" ), NET_TYPE_ALLEGRO, false ); + m_PanelNetType[PANELPADS] = + new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "PADS" ), NET_TYPE_PADS, false ); + m_PanelNetType[PANELCADSTAR] = new EXPORT_NETLIST_PAGE( m_NoteBook, wxT( "CadStar" ), NET_TYPE_CADSTAR, false ); @@ -512,6 +516,9 @@ bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow() 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() ); @@ -671,6 +678,12 @@ bool DIALOG_EXPORT_NETLIST::FilenamePrms( NETLIST_TYPE_ID aType, wxString * aExt 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; diff --git a/eeschema/netlist_exporters/netlist.h b/eeschema/netlist_exporters/netlist.h index 2d5687a785..3bc2cc1469 100644 --- a/eeschema/netlist_exporters/netlist.h +++ b/eeschema/netlist_exporters/netlist.h @@ -41,6 +41,7 @@ enum NETLIST_TYPE_ID { NET_TYPE_SPICE, NET_TYPE_SPICE_MODEL, NET_TYPE_ALLEGRO, + NET_TYPE_PADS, NET_TYPE_CUSTOM1, /* NET_TYPE_CUSTOM1 * is the first id for user netlist format * NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1 diff --git a/eeschema/netlist_exporters/netlist_exporter_pads.cpp b/eeschema/netlist_exporters/netlist_exporter_pads.cpp new file mode 100644 index 0000000000..d745194a13 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_pads.cpp @@ -0,0 +1,204 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 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 +#include + +#include +#include +#include +#include + +#include "netlist_exporter_pads.h" + +bool NETLIST_EXPORTER_PADS::WriteNetlist( const wxString& aOutFileName, + unsigned /* aNetlistOptions */, + REPORTER& aReporter ) +{ + int ret = 0; + FILE* f = nullptr; + + if( ( f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == nullptr ) + { + wxString msg = wxString::Format( _( "Failed to create file '%s'." ), aOutFileName ); + aReporter.Report( msg, RPT_SEVERITY_ERROR ); + return false; + } + + wxString msg; + wxString footprint; + SCH_SYMBOL* symbol; + + ret |= fputs( "*PADS-PCB*\n", f ); + ret |= fputs( "*PART*\n", f ); + + // Create netlist footprints section + m_referencesAlreadyFound.Clear(); + + SCH_SHEET_LIST sheetList = m_schematic->GetSheets(); + + for( unsigned i = 0; i < sheetList.size(); i++ ) + { + for( SCH_ITEM* item : sheetList[i].LastScreen()->Items().OfType( SCH_SYMBOL_T ) ) + { + symbol = findNextSymbol( item, &sheetList[ i ] ); + + if( !symbol ) + continue; + + if( symbol->GetExcludedFromBoard() ) + continue; + + footprint = symbol->GetFootprintFieldText( true, &sheetList[ i ], false ); + + footprint = footprint.Trim( true ); + footprint = footprint.Trim( false ); + footprint.Replace( wxT( " " ), wxT( "_" ) ); + + if( footprint.IsEmpty() ) + { + // fall back to value field + footprint = symbol->GetValueFieldText( true, &sheetList[i], false ); + footprint.Replace( wxT( " " ), wxT( "_" ) ); + footprint = footprint.Trim( true ); + footprint = footprint.Trim( false ); + } + + msg = symbol->GetRef( &sheetList[i] ); + ret |= fprintf( f, "%-16s %s\n", TO_UTF8( msg ), TO_UTF8( footprint ) ); + } + } + + ret |= fputs( "\n", f ); + + if( !writeListOfNets( f ) ) + ret = -1; // set error + + fclose( f ); + + return ret >= 0; +} + + +bool NETLIST_EXPORTER_PADS::writeListOfNets( FILE* f ) +{ + int ret = 0; + int print_ter = 0; + + wxString initialSignalLine; + wxString netName; + + ret |= fputs( "*NET*\n", f ); + + for( const auto& [ key, subgraphs ] : m_schematic->ConnectionGraph()->GetNetMap() ) + { + netName = key.Name; + + std::vector> sorted_items; + + for( CONNECTION_SUBGRAPH* subgraph : subgraphs ) + { + SCH_SHEET_PATH sheet = subgraph->GetSheet(); + + for( SCH_ITEM* item : subgraph->GetItems() ) + { + if( item->Type() == SCH_PIN_T ) + sorted_items.emplace_back( static_cast( item ), sheet ); + } + } + + // Netlist ordering: Net name, then ref des, then pin name + std::sort( sorted_items.begin(), sorted_items.end(), + []( std::pair a, std::pair b ) + { + wxString ref_a = a.first->GetParentSymbol()->GetRef( &a.second ); + wxString ref_b = b.first->GetParentSymbol()->GetRef( &b.second ); + + if( ref_a == ref_b ) + return a.first->GetShownNumber() < b.first->GetShownNumber(); + + return ref_a < ref_b; + } ); + + // 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: + sorted_items.erase( std::unique( sorted_items.begin(), sorted_items.end(), + []( std::pair a, std::pair b ) + { + wxString ref_a = a.first->GetParentSymbol()->GetRef( &a.second ); + wxString ref_b = b.first->GetParentSymbol()->GetRef( &b.second ); + + return ref_a == ref_b && a.first->GetShownNumber() == b.first->GetShownNumber(); + } ), + sorted_items.end() ); + + print_ter = 0; + + std::vector netConns; + + for( const std::pair& pair : sorted_items ) + { + SCH_PIN* pin = pair.first; + SCH_SHEET_PATH sheet = pair.second; + + wxString refText = pin->GetParentSymbol()->GetRef( &sheet ); + wxString pinText = pin->GetShownNumber(); + + // Skip power symbols and virtual symbols + if( refText[0] == wxChar( '#' ) ) + continue; + + netConns.push_back( + wxString::Format( "%s.%.4s", refText, pinText ) ); + } + + // format it such that there are 6 net connections per line + // which seems to be the standard everyone follows + if( netConns .size() > 1 ) + { + ret |= fprintf( f, "*SIGNAL* %s\n", TO_UTF8(netName) ); + int cnt = 0; + for( wxString& netConn : netConns ) + { + ret |= fputs( TO_UTF8( netConn ), f ); + if( cnt != 0 && cnt % 6 == 0 ) + { + ret |= fputc( '\n', f ); + } + else + { + ret |= fputc( ' ', f ); + } + + cnt++; + } + + ret |= fputc( '\n', f ); + } + } + + ret |= fprintf( f, "*END*\n" ); + + return ret >= 0; +} diff --git a/eeschema/netlist_exporters/netlist_exporter_pads.h b/eeschema/netlist_exporters/netlist_exporter_pads.h new file mode 100644 index 0000000000..cfe0c795a2 --- /dev/null +++ b/eeschema/netlist_exporters/netlist_exporter_pads.h @@ -0,0 +1,59 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 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_PADS_H +#define NETLIST_EXPORTER_PADS_H + +#include "netlist_exporter_base.h" + + +/** + * Generate a netlist compatible with PADS. + */ +class NETLIST_EXPORTER_PADS : public NETLIST_EXPORTER_BASE +{ +public: + NETLIST_EXPORTER_PADS( SCHEMATIC* aSchematic ) : + NETLIST_EXPORTER_BASE( aSchematic ) + { + } + + /** + * Write to specified output file. + */ + bool WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions, + REPORTER& aReporter ) override; + +private: + /** + * Write a net list (ranked by Netcode), and pins connected to it. + * + * Format: + * - ADD_TER RR2 6 \"$42\" + * - B U1 100 + * - 6 CA + */ + bool writeListOfNets( FILE* f ); +}; + +#endif diff --git a/eeschema/netlist_exporters/netlist_generator.cpp b/eeschema/netlist_exporters/netlist_generator.cpp index a1fd91159e..f65db3d4e4 100644 --- a/eeschema/netlist_exporters/netlist_generator.cpp +++ b/eeschema/netlist_exporters/netlist_generator.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -91,7 +92,11 @@ bool SCH_EDIT_FRAME::WriteNetListFile( int aFormat, const wxString& aFullFileNam case NET_TYPE_ALLEGRO: helper = new NETLIST_EXPORTER_ALLEGRO( sch ); - break; + break; + + case NET_TYPE_PADS: + helper = new NETLIST_EXPORTER_PADS( sch ); + break; case NET_TYPE_BOM: // When generating the BOM, we have a bare filename so don't strip diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h index 13425998d6..43c4da0829 100644 --- a/include/wildcards_and_files_ext.h +++ b/include/wildcards_and_files_ext.h @@ -135,6 +135,7 @@ public: static const std::string OrCadPcb2NetlistFileExtension; static const std::string NetlistFileExtension; static const std::string AllegroNetlistFileExtension; + static const std::string PADSNetlistFileExtension; static const std::string GerberFileExtension; static const std::string GerberJobFileExtension; static const std::string HtmlFileExtension; @@ -219,6 +220,7 @@ public: static wxString OrCadPcb2NetlistFileWildcard(); static wxString NetlistFileWildcard(); static wxString AllegroNetlistFileWildcard(); + static wxString PADSNetlistFileWildcard(); static wxString HtmlFileWildcard(); static wxString CsvFileWildcard(); static wxString PcbFileWildcard();