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 <refdes_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  wxString ref;
76 
77  if( aItem->Type() != SCH_SYMBOL_T )
78  return nullptr;
79 
80  // found next symbol
81  SCH_SYMBOL* symbol = (SCH_SYMBOL*) aItem;
82 
83  // Power symbols and other symbols which have the reference starting with "#" are not
84  // included in netlist (pseudo or virtual symbols)
85  ref = symbol->GetRef( aSheetPath );
86 
87  if( ref[0] == wxChar( '#' ) )
88  return nullptr;
89 
90  // if( symbol->m_FlagControlMulti == 1 )
91  // continue; /* yes */
92  // removed because with multiple instances of one schematic (several sheets pointing to
93  // 1 screen), this will be erroneously be toggled.
94 
95  if( !symbol->GetLibSymbolRef() )
96  return nullptr;
97 
98  // If symbol is a "multi parts per package" type
99  if( symbol->GetLibSymbolRef()->GetUnitCount() > 1 )
100  {
101  // test if this reference has already been processed, and if so skip
102  if( m_referencesAlreadyFound.Lookup( ref ) )
103  return nullptr;
104  }
105 
106  // record the usage of this library symbol entry.
107  m_libParts.insert( symbol->GetLibSymbolRef().get() ); // rejects non-unique pointers
108 
109  return symbol;
110 }
111 
112 
114 static bool sortPinsByNum( PIN_INFO& aPin1, PIN_INFO& aPin2 )
115 {
116  // return "lhs < rhs"
117  return UTIL::RefDesStringCompare( aPin1.num, aPin2.num ) < 0;
118 }
119 
120 
122  SCH_SHEET_PATH* aSheetPath,
123  bool aKeepUnconnectedPins )
124 {
125  wxString ref( aSymbol->GetRef( aSheetPath ) );
126 
127  // Power symbols and other symbols which have the reference starting with "#" are not
128  // included in netlist (pseudo or virtual symbols)
129 
130  if( ref[0] == wxChar( '#' ) )
131  return;
132 
133  // if( aSymbol->m_FlagControlMulti == 1 )
134  // continue; /* yes */
135  // removed because with multiple instances of one schematic (several sheets pointing to
136  // 1 screen), this will be erroneously be toggled.
137 
138  if( !aSymbol->GetLibSymbolRef() )
139  return;
140 
141  m_sortedSymbolPinList.clear();
142 
143  // If symbol is a "multi parts per package" type
144  if( aSymbol->GetLibSymbolRef()->GetUnitCount() > 1 )
145  {
146  // Collect all pins for this reference designator by searching the entire design for
147  // other parts with the same reference designator.
148  // This is only done once, it would be too expensive otherwise.
149  findAllUnitsOfSymbol( aSymbol, aSymbol->GetLibSymbolRef().get(),
150  aSheetPath, aKeepUnconnectedPins );
151  }
152 
153  else // GetUnitCount() <= 1 means one part per package
154  {
156 
157  for( const SCH_PIN* pin : aSymbol->GetPins( aSheetPath ) )
158  {
159  if( SCH_CONNECTION* conn = pin->Connection( aSheetPath ) )
160  {
161  const wxString& netName = conn->Name();
162 
163  if( !aKeepUnconnectedPins ) // Skip unconnected pins if requested
164  {
165  CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, *aSheetPath );
166 
167  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
168  continue;
169  }
170 
171  m_sortedSymbolPinList.emplace_back( pin->GetShownNumber(), netName );
172  }
173  }
174  }
175 
176  // Sort pins in m_SortedSymbolPinList by pin number
178 
179  // Remove duplicate Pins in m_SortedSymbolPinList
181 
182  // record the usage of this library symbol
183  m_libParts.insert( aSymbol->GetLibSymbolRef().get() ); // rejects non-unique pointers
184 }
185 
186 
188 {
189  for( unsigned ii = 0; ii < m_sortedSymbolPinList.size(); ii++ )
190  {
191  if( m_sortedSymbolPinList[ii].num.empty() ) /* already deleted */
192  continue;
193 
194  /* Search for duplicated pins
195  * If found, remove duplicates. The priority is to keep connected pins
196  * and remove unconnected
197  * - So this allows (for instance when using multi op amps per package
198  * - to connect only one op amp to power
199  * Because the pin list is sorted by m_PinNum value, duplicated pins
200  * are necessary successive in list
201  */
202  int idxref = ii;
203 
204  for( unsigned jj = ii + 1; jj < m_sortedSymbolPinList.size(); jj++ )
205  {
206  if( m_sortedSymbolPinList[jj].num.empty() ) // Already removed
207  continue;
208 
209  // if other pin num, stop search,
210  // because all pins having the same number are consecutive in list.
211  if( m_sortedSymbolPinList[idxref].num != m_sortedSymbolPinList[jj].num )
212  break;
213 
214  m_sortedSymbolPinList[jj].num.clear();
215  }
216  }
217 }
218 
219 
221  SCH_SHEET_PATH* aSheetPath,
222  bool aKeepUnconnectedPins )
223 {
224  wxString ref = aSchSymbol->GetRef( aSheetPath );
225  wxString ref2;
226 
227  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
229 
230  for( unsigned i = 0; i < sheetList.size(); i++ )
231  {
232  SCH_SHEET_PATH& sheet = sheetList[i];
233 
234  for( SCH_ITEM* item : sheetList[i].LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
235  {
236  SCH_SYMBOL* comp2 = static_cast<SCH_SYMBOL*>( item );
237 
238  ref2 = comp2->GetRef( &sheet );
239 
240  if( ref2.CmpNoCase( ref ) != 0 )
241  continue;
242 
243  for( const SCH_PIN* pin : comp2->GetPins( &sheet ) )
244  {
245  if( SCH_CONNECTION* conn = pin->Connection( &sheet ) )
246  {
247  const wxString& netName = conn->Name();
248 
249  if( !aKeepUnconnectedPins ) // Skip unconnected pins if requested
250  {
251  CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, sheet );
252 
253  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
254  continue;
255  }
256 
257  m_sortedSymbolPinList.emplace_back( pin->GetShownNumber(), netName );
258  }
259  }
260  }
261  }
262 }
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.
Collection of utility functions for component reference designators (refdes)
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:431
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.
int RefDesStringCompare(const wxString &aFirst, const wxString &aSecond)
Acts just like the strcmp function but treats numbers within the string text correctly for sorting.
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.
std::vector< SCH_ITEM * > m_items
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.
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
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
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:197
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:856
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113