KiCad PCB EDA Suite
netlist_exporter_base.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2017 jp.charras at wanadoo.fr
5  * Copyright (C) 2013-2017 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <netlist_exporter_base.h>
27 
28 #include <string_utils.h>
29 
30 #include <symbol_library.h>
31 #include <connection_graph.h>
32 #include <sch_reference_list.h>
33 #include <sch_screen.h>
34 #include <schematic.h>
35 
36 
37 wxString NETLIST_EXPORTER_BASE::MakeCommandLine( const wxString& aFormatString,
38  const wxString& aNetlistFile,
39  const wxString& aFinalFile,
40  const wxString& aProjectPath )
41 {
42  // Expand format symbols in the command line:
43  // %B => base filename of selected output file, minus path and extension.
44  // %P => project directory name, without trailing '/' or '\'.
45  // %I => full filename of the input file (the intermediate net file).
46  // %O => complete filename and path (but without extension) of the user chosen output file.
47 
48  wxString ret = aFormatString;
49  wxFileName in = aNetlistFile;
50  wxFileName out = aFinalFile;
51  wxString str_out = out.GetFullPath();
52 
53  ret.Replace( "%P", aProjectPath, true );
54  ret.Replace( "%B", out.GetName(), true );
55  ret.Replace( "%I", in.GetFullPath(), true );
56 
57 #ifdef __WINDOWS__
58  // A ugly hack to run xsltproc that has a serious bug on Window since a long time:
59  // the filename given after -o option (output filename) cannot use '\' in filename
60  // so replace if by '/' if possible (I mean if the filename does not start by "\\"
61  // that is a filename on a Windows server)
62 
63  if( !str_out.StartsWith( "\\\\" ) )
64  str_out.Replace( "\\", "/" );
65 #endif
66 
67  ret.Replace( "%O", str_out, true );
68 
69  return ret;
70 }
71 
72 
74 {
75  wxCHECK( aItem, nullptr );
76  wxCHECK( aSheetPath, nullptr );
77 
78  wxString ref;
79 
80  if( aItem->Type() != SCH_SYMBOL_T )
81  return nullptr;
82 
83  // found next symbol
84  SCH_SYMBOL* symbol = (SCH_SYMBOL*) aItem;
85 
86  // Power symbols and other symbols which have the reference starting with "#" are not
87  // included in netlist (pseudo or virtual symbols)
88  ref = symbol->GetRef( aSheetPath );
89 
90  if( ref[0] == wxChar( '#' ) )
91  return nullptr;
92 
93  SCH_SCREEN* screen = aSheetPath->LastScreen();
94 
95  wxCHECK( screen, nullptr );
96 
97  LIB_SYMBOL* libSymbol = screen->GetLibSymbols()[ symbol->GetSchSymbolLibraryName() ];
98 
99  wxCHECK( libSymbol, nullptr );
100 
101  // If symbol is a "multi parts per package" type
102  if( libSymbol->GetUnitCount() > 1 )
103  {
104  // test if this reference has already been processed, and if so skip
105  if( m_referencesAlreadyFound.Lookup( ref ) )
106  return nullptr;
107  }
108 
109  // record the usage of this library symbol entry.
110  m_libParts.insert( libSymbol ); // rejects non-unique pointers
111 
112  return symbol;
113 }
114 
115 
117 static bool sortPinsByNum( PIN_INFO& aPin1, PIN_INFO& aPin2 )
118 {
119  // return "lhs < rhs"
120  return StrNumCmp( aPin1.num, aPin2.num, true ) < 0;
121 }
122 
123 
125  SCH_SHEET_PATH* aSheetPath,
126  bool aKeepUnconnectedPins )
127 {
128  wxString ref( aSymbol->GetRef( aSheetPath ) );
129 
130  // Power symbols and other symbols which have the reference starting with "#" are not
131  // included in netlist (pseudo or virtual symbols)
132 
133  if( ref[0] == wxChar( '#' ) )
134  return;
135 
136  // if( aSymbol->m_FlagControlMulti == 1 )
137  // continue; /* yes */
138  // removed because with multiple instances of one schematic (several sheets pointing to
139  // 1 screen), this will be erroneously be toggled.
140 
141  if( !aSymbol->GetLibSymbolRef() )
142  return;
143 
144  m_sortedSymbolPinList.clear();
145 
146  // If symbol is a "multi parts per package" type
147  if( aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
148  {
149  // Collect all pins for this reference designator by searching the entire design for
150  // other parts with the same reference designator.
151  // This is only done once, it would be too expensive otherwise.
152  findAllUnitsOfSymbol( aSymbol, aSymbol->GetLibSymbolRef().get(),
153  aSheetPath, aKeepUnconnectedPins );
154  }
155 
156  else // GetUnitCount() <= 1 means one part per package
157  {
159 
160  for( const SCH_PIN* pin : aSymbol->GetPins( aSheetPath ) )
161  {
162  if( SCH_CONNECTION* conn = pin->Connection( aSheetPath ) )
163  {
164  const wxString& netName = conn->Name();
165 
166  if( !aKeepUnconnectedPins ) // Skip unconnected pins if requested
167  {
168  CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, *aSheetPath );
169 
170  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
171  continue;
172  }
173 
174  m_sortedSymbolPinList.emplace_back( pin->GetShownNumber(), netName );
175  }
176  }
177  }
178 
179  // Sort pins in m_SortedSymbolPinList by pin number
181 
182  // Remove duplicate Pins in m_SortedSymbolPinList
184 
185  // record the usage of this library symbol
186  m_libParts.insert( aSymbol->GetLibSymbolRef().get() ); // rejects non-unique pointers
187 }
188 
189 
191 {
192  for( unsigned ii = 0; ii < m_sortedSymbolPinList.size(); ii++ )
193  {
194  if( m_sortedSymbolPinList[ii].num.empty() ) /* already deleted */
195  continue;
196 
197  /* Search for duplicated pins
198  * If found, remove duplicates. The priority is to keep connected pins
199  * and remove unconnected
200  * - So this allows (for instance when using multi op amps per package
201  * - to connect only one op amp to power
202  * Because the pin list is sorted by m_PinNum value, duplicated pins
203  * are necessary successive in list
204  */
205  int idxref = ii;
206 
207  for( unsigned jj = ii + 1; jj < m_sortedSymbolPinList.size(); jj++ )
208  {
209  if( m_sortedSymbolPinList[jj].num.empty() ) // Already removed
210  continue;
211 
212  // if other pin num, stop search,
213  // because all pins having the same number are consecutive in list.
214  if( m_sortedSymbolPinList[idxref].num != m_sortedSymbolPinList[jj].num )
215  break;
216 
217  m_sortedSymbolPinList[jj].num.clear();
218  }
219  }
220 }
221 
222 
224  SCH_SHEET_PATH* aSheetPath,
225  bool aKeepUnconnectedPins )
226 {
227  wxString ref = aSchSymbol->GetRef( aSheetPath );
228  wxString ref2;
229 
230  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
232 
233  for( unsigned i = 0; i < sheetList.size(); i++ )
234  {
235  SCH_SHEET_PATH& sheet = sheetList[i];
236 
237  for( SCH_ITEM* item : sheetList[i].LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
238  {
239  SCH_SYMBOL* comp2 = static_cast<SCH_SYMBOL*>( item );
240 
241  ref2 = comp2->GetRef( &sheet );
242 
243  if( ref2.CmpNoCase( ref ) != 0 )
244  continue;
245 
246  for( const SCH_PIN* pin : comp2->GetPins( &sheet ) )
247  {
248  if( SCH_CONNECTION* conn = pin->Connection( &sheet ) )
249  {
250  const wxString& netName = conn->Name();
251 
252  if( !aKeepUnconnectedPins ) // Skip unconnected pins if requested
253  {
254  CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, sheet );
255 
256  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
257  continue;
258  }
259 
260  m_sortedSymbolPinList.emplace_back( pin->GetShownNumber(), netName );
261  }
262  }
263  }
264  }
265 }
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Returns the subgraph for a given net name on a given sheet.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
bool Lookup(const wxString &aString)
std::vector< PIN_INFO > m_sortedSymbolPinList
Used to temporarily store and filter the list of pins of a schematic symbol when generating schematic...
Calculates the connectivity of a schematic and generates netlists.
void eraseDuplicatePins()
Erase duplicate pins from m_sortedSymbolPinList (i.e.
virtual CONNECTION_GRAPH * ConnectionGraph() const =0
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:441
static bool sortPinsByNum(PIN_INFO &aPin1, PIN_INFO &aPin2)
Comparison routine for sorting by pin numbers.
Define a library symbol object.
Definition: lib_symbol.h:96
A subgraph is a set of items that are electrically connected on a single sheet.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:164
SCH_SYMBOL * findNextSymbol(EDA_ITEM *aItem, SCH_SHEET_PATH *aSheetPath)
Check if the given symbol should be processed for netlisting.
SCHEMATIC_IFACE * m_schematic
The schematic we're generating a netlist for.
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
static wxString MakeCommandLine(const wxString &aFormatString, const wxString &aNetlistFile, const wxString &aFinalFile, const wxString &aProjectDirectory)
Build up a string that describes a command line for executing a child process.
wxString GetSchSymbolLibraryName() const
Definition: sch_symbol.cpp:248
std::vector< SCH_ITEM * > m_items
int GetUnitCount() const override
For items with units, return the number of units.
void CreatePinList(SCH_SYMBOL *aSymbol, SCH_SHEET_PATH *aSheetPath, bool aKeepUnconnectedPins)
Find a symbol from the DrawList and builds its pin list in m_sortedSymbolPinList.
Definition for symbol library class.
std::map< wxString, LIB_SYMBOL * > & GetLibSymbols()
Fetch a list of unique LIB_SYMBOL object pointers required to properly render each SCH_SYMBOL in this...
Definition: sch_screen.h:424
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Schematic symbol object.
Definition: sch_symbol.h:78
SCH_SCREEN * LastScreen()
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
void findAllUnitsOfSymbol(SCH_SYMBOL *aSchSymbol, LIB_SYMBOL *aLibSymbol, SCH_SHEET_PATH *aSheetPath, bool aKeepUnconnectedPins)
Find all units for symbols with multiple symbols per package.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::set< LIB_SYMBOL *, LIB_SYMBOL_LESS_THAN > m_libParts
unique library symbols used. LIB_SYMBOL items are sorted by names
virtual SCH_SHEET_LIST GetSheets() const =0
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:866
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113