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-2020 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 <pgm_base.h>
29 #include <refdes_utils.h>
30 
31 #include <class_library.h>
32 #include <connection_graph.h>
33 #include <sch_reference_list.h>
34 #include <sch_screen.h>
35 #include <schematic.h>
36 
37 
38 wxString NETLIST_EXPORTER_BASE::MakeCommandLine( const wxString& aFormatString,
39  const wxString& aNetlistFile,
40  const wxString& aFinalFile,
41  const wxString& aProjectPath )
42 {
43  // Expand format symbols in the command line:
44  // %B => base filename of selected output file, minus path and extension.
45  // %P => project directory name, without trailing '/' or '\'.
46  // %I => full filename of the input file (the intermediate net file).
47  // %O => complete filename and path (but without extension) of the user chosen output file.
48 
49  wxString ret = aFormatString;
50  wxFileName in = aNetlistFile;
51  wxFileName out = aFinalFile;
52  wxString str_out = out.GetFullPath();
53 
54  ret.Replace( "%P", aProjectPath, true );
55  ret.Replace( "%B", out.GetName(), true );
56  ret.Replace( "%I", in.GetFullPath(), true );
57 
58 #ifdef __WINDOWS__
59  // A ugly hack to run xsltproc that has a serious bug on Window since a long time:
60  // the filename given after -o option (output filename) cannot use '\' in filename
61  // so replace if by '/' if possible (I mean if the filename does not start by "\\"
62  // that is a filename on a Windows server)
63 
64  if( !str_out.StartsWith( "\\\\" ) )
65  str_out.Replace( "\\", "/" );
66 #endif
67 
68  ret.Replace( "%O", str_out, true );
69 
70  return ret;
71 }
72 
73 
75 {
76  wxString ref;
77 
78  if( aItem->Type() != SCH_COMPONENT_T )
79  return nullptr;
80 
81  // found next component
82  SCH_COMPONENT* symbol = (SCH_COMPONENT*) aItem;
83 
84  // Power symbols and other symbols which have the reference starting with "#" are not
85  // included in netlist (pseudo or virtual symbols)
86  ref = symbol->GetRef( aSheetPath );
87 
88  if( ref[0] == wxChar( '#' ) )
89  return nullptr;
90 
91  // if( symbol->m_FlagControlMulti == 1 )
92  // continue; /* yes */
93  // removed because with multiple instances of one schematic (several sheets pointing to
94  // 1 screen), this will be erroneously be toggled.
95 
96  if( !symbol->GetPartRef() )
97  return nullptr;
98 
99  // If component is a "multi parts per package" type
100  if( symbol->GetPartRef()->GetUnitCount() > 1 )
101  {
102  // test if this reference has already been processed, and if so skip
103  if( m_referencesAlreadyFound.Lookup( ref ) )
104  return nullptr;
105  }
106 
107  // record the usage of this library component entry.
108  m_libParts.insert( symbol->GetPartRef().get() ); // rejects non-unique pointers
109 
110  return symbol;
111 }
112 
113 
115 static bool sortPinsByNum( PIN_INFO& aPin1, PIN_INFO& aPin2 )
116 {
117  // return "lhs < rhs"
118  return UTIL::RefDesStringCompare( aPin1.num, aPin2.num ) < 0;
119 }
120 
121 
123 {
124  wxString ref( aSymbol->GetRef( aSheetPath ) );
125 
126  // Power symbols and other symbols which have the reference starting with "#" are not
127  // included in netlist (pseudo or virtual symbols)
128 
129  if( ref[0] == wxChar( '#' ) )
130  return;
131 
132  // if( aSymbol->m_FlagControlMulti == 1 )
133  // continue; /* yes */
134  // removed because with multiple instances of one schematic (several sheets pointing to
135  // 1 screen), this will be erroneously be toggled.
136 
137  if( !aSymbol->GetPartRef() )
138  return;
139 
140  m_sortedSymbolPinList.clear();
141 
142  // If symbol is a "multi parts per package" type
143  if( aSymbol->GetPartRef()->GetUnitCount() > 1 )
144  {
145  // Collect all pins for this reference designator by searching the entire design for
146  // other parts with the same reference designator.
147  // This is only done once, it would be too expensive otherwise.
148  findAllUnitsOfSymbol( aSymbol, aSymbol->GetPartRef().get(), aSheetPath );
149  }
150 
151  else // GetUnitCount() <= 1 means one part per package
152  {
154 
155  for( const SCH_PIN* pin : aSymbol->GetPins( aSheetPath ) )
156  {
157  if( SCH_CONNECTION* conn = pin->Connection( aSheetPath ) )
158  {
159  const wxString& netName = conn->Name();
160 
161  // Skip unconnected pins
162  CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, *aSheetPath );
163 
164  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
165  continue;
166 
167  m_sortedSymbolPinList.emplace_back( pin->GetNumber(), netName );
168  }
169  }
170  }
171 
172  // Sort pins in m_SortedComponentPinList by pin number
174 
175  // Remove duplicate Pins in m_SortedComponentPinList
177 
178  // record the usage of this library component entry.
179  m_libParts.insert( aSymbol->GetPartRef().get() ); // rejects non-unique pointers
180 }
181 
182 
184 {
185  for( unsigned ii = 0; ii < m_sortedSymbolPinList.size(); ii++ )
186  {
187  if( m_sortedSymbolPinList[ii].num.empty() ) /* already deleted */
188  continue;
189 
190  /* Search for duplicated pins
191  * If found, remove duplicates. The priority is to keep connected pins
192  * and remove unconnected
193  * - So this allows (for instance when using multi op amps per package
194  * - to connect only one op amp to power
195  * Because the pin list is sorted by m_PinNum value, duplicated pins
196  * are necessary successive in list
197  */
198  int idxref = ii;
199 
200  for( unsigned jj = ii + 1; jj < m_sortedSymbolPinList.size(); jj++ )
201  {
202  if( m_sortedSymbolPinList[jj].num.empty() ) // Already removed
203  continue;
204 
205  // if other pin num, stop search,
206  // because all pins having the same number are consecutive in list.
207  if( m_sortedSymbolPinList[idxref].num != m_sortedSymbolPinList[jj].num )
208  break;
209 
210  m_sortedSymbolPinList[jj].num.clear();
211  }
212  }
213 }
214 
215 
217  LIB_PART* aPart, SCH_SHEET_PATH* aSheetPath )
218 {
219  wxString ref = aSymbol->GetRef( aSheetPath );
220  wxString ref2;
221 
222  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
224 
225  for( unsigned i = 0; i < sheetList.size(); i++ )
226  {
227  SCH_SHEET_PATH& sheet = sheetList[i];
228 
229  for( SCH_ITEM* item : sheetList[i].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
230  {
231  SCH_COMPONENT* comp2 = static_cast<SCH_COMPONENT*>( item );
232 
233  ref2 = comp2->GetRef( &sheet );
234 
235  if( ref2.CmpNoCase( ref ) != 0 )
236  continue;
237 
238  for( const SCH_PIN* pin : comp2->GetPins( &sheet ) )
239  {
240  if( SCH_CONNECTION* conn = pin->Connection( &sheet ) )
241  {
242  const wxString& netName = conn->Name();
243 
244  // Skip unconnected pins
245  CONNECTION_SUBGRAPH* sg = graph->FindSubgraphByName( netName, sheet );
246 
247  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
248  continue;
249 
250  m_sortedSymbolPinList.emplace_back( pin->GetNumber(), netName );
251  }
252  }
253  }
254  }
255 }
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)
Function Lookup returns true if aString already exists in the set, otherwise returns false and adds a...
void CreatePinList(SCH_COMPONENT *aSymbol, SCH_SHEET_PATH *aSheetPath)
Function findNextSymbolAndCreatePinList finds a symbol from the DrawList and builds its pin list in m...
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()
Function eraseDuplicatePins erase duplicate Pins from m_sortedSymbolPinList (i.e.
Collection of utility functions for component reference designators (refdes)
virtual CONNECTION_GRAPH * ConnectionGraph() const =0
static bool sortPinsByNum(PIN_INFO &aPin1, PIN_INFO &aPin2)
Comparison routine for sorting by pin numbers.
void findAllUnitsOfSymbol(SCH_COMPONENT *aSymbol, LIB_PART *aPart, SCH_SHEET_PATH *aSheetPath)
Function findAllUnitsOfSymbol is used for "multiple parts per package" symbols.
std::set< LIB_PART *, LIB_PART_LESS_THAN > m_libParts
unique library parts used. LIB_PART items are sorted by names
A subgraph is a set of items that are electrically connected on a single sheet.
SCHEMATIC_IFACE * m_schematic
The schematic we're generating a netlist for.
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple parts per package" symbols to avoid processing a lib part 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)
Function MakeCommandLine builds up a string that describes a command line for executing a child proce...
std::vector< SCH_ITEM * > m_items
SCH_COMPONENT * findNextSymbol(EDA_ITEM *aItem, SCH_SHEET_PATH *aSheetPath)
Checks if the given symbol should be processed for netlisting.
Define a library symbol object.
Definition: lib_symbol.h:93
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::unique_ptr< LIB_PART > & GetPartRef()
Definition: sch_symbol.h:206
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieves a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:863
see class PGM_BASE
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
Schematic symbol object.
Definition: sch_symbol.h:79
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:149
Definition for part library class.
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
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:196
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:427