KiCad PCB EDA Suite
netlist_exporter.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-2017 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.h>
27 
28 #include <confirm.h>
29 #include <pgm_base.h>
30 #include <refdes_utils.h>
31 
32 #include <class_library.h>
33 #include <connection_graph.h>
34 #include <sch_reference_list.h>
35 #include <sch_screen.h>
36 #include <schematic.h>
37 
38 
39 wxString NETLIST_EXPORTER::MakeCommandLine( const wxString& aFormatString,
40  const wxString& aNetlistFile, const wxString& aFinalFile, 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_COMPONENT_T )
78  return nullptr;
79 
80  // found next component
81  SCH_COMPONENT* comp = (SCH_COMPONENT*) aItem;
82 
83  // Power symbols and other components which have the reference starting
84  // with "#" are not included in netlist (pseudo or virtual components)
85  ref = comp->GetRef( aSheetPath );
86 
87  if( ref[0] == wxChar( '#' ) )
88  return nullptr;
89 
90  // if( Component->m_FlagControlMulti == 1 )
91  // continue; /* yes */
92  // removed because with multiple instances of one schematic
93  // (several sheets pointing to 1 screen), this will be erroneously be
94  // toggled.
95 
96  if( !comp->GetPartRef() )
97  return nullptr;
98 
99  // If component is a "multi parts per package" type
100  if( comp->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( comp->GetPartRef().get() ); // rejects non-unique pointers
109 
110  return comp;
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( comp->GetRef( aSheetPath ) );
125 
126  // Power symbols and other components which have the reference starting
127  // with "#" are not included in netlist (pseudo or virtual components)
128 
129  if( ref[0] == wxChar( '#' ) )
130  return;
131 
132  // if( Component->m_FlagControlMulti == 1 )
133  // continue; /* yes */
134  // removed because with multiple instances of one schematic
135  // (several sheets pointing to 1 screen), this will be erroneously be
136  // toggled.
137 
138  if( !comp->GetPartRef() )
139  return;
140 
141  m_SortedComponentPinList.clear();
142 
143  // If component is a "multi parts per package" type
144  if( comp->GetPartRef()->GetUnitCount() > 1 )
145  {
146  // Collect all pins for this reference designator by searching
147  // the entire design for other parts with the same reference designator.
148  // This is only done once, it would be too expensive otherwise.
149  findAllUnitsOfComponent( comp, comp->GetPartRef().get(), aSheetPath );
150  }
151 
152  else // entry->GetUnitCount() <= 1 means one part per package
153  {
154  for( const auto& pin : comp->GetPins( aSheetPath ) )
155  {
156  if( auto conn = pin->Connection( aSheetPath ) )
157  {
158  const wxString& netName = conn->Name();
159 
160  // Skip unconnected pins
161  CONNECTION_SUBGRAPH* sg =
162  m_schematic->ConnectionGraph()->FindSubgraphByName( netName, *aSheetPath );
163 
164  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
165  continue;
166 
167  m_SortedComponentPinList.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( comp->GetPartRef().get() ); // rejects non-unique pointers
180 }
181 
182 
184 {
185  for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ )
186  {
187  if( m_SortedComponentPinList[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_SortedComponentPinList.size(); jj++ )
201  {
202  if( m_SortedComponentPinList[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_SortedComponentPinList[idxref].num != m_SortedComponentPinList[jj].num )
208  break;
209 
210  m_SortedComponentPinList[jj].num.clear();
211  }
212  }
213 }
214 
215 
217  LIB_PART* aEntry, SCH_SHEET_PATH* aSheetPath )
218 {
219  wxString ref = aComponent->GetRef( aSheetPath );
220  wxString ref2;
221 
222  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
223 
224  for( unsigned i = 0; i < sheetList.size(); i++ )
225  {
226  for( auto item : sheetList[i].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
227  {
228  SCH_COMPONENT* comp2 = static_cast<SCH_COMPONENT*>( item );
229 
230  ref2 = comp2->GetRef( &sheetList[i] );
231 
232  if( ref2.CmpNoCase( ref ) != 0 )
233  continue;
234 
235  for( const auto& pin : comp2->GetPins( aSheetPath ) )
236  {
237  if( auto conn = pin->Connection( aSheetPath ) )
238  {
239  const wxString& netName = conn->Name();
240 
241  // Skip unconnected pins
243  netName, *aSheetPath );
244 
245  if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
246  continue;
247 
248  m_SortedComponentPinList.emplace_back( pin->GetNumber(), netName );
249  }
250  }
251  }
252  }
253 }
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...
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:91
UNIQUE_STRINGS m_ReferencesAlreadyFound
Used for "multi parts per package" components, avoids processing a lib component more than once.
SCHEMATIC * m_schematic
The schematic we're generating a netlist for.
CONNECTION_GRAPH * ConnectionGraph() const
Definition: schematic.h:131
This file is part of the common library.
Collection of utility functions for component reference designators (refdes)
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...
SCH_COMPONENT * findNextComponent(EDA_ITEM *aItem, SCH_SHEET_PATH *aSheetPath)
Checks if the given component should be processed for netlisting.
void findAllUnitsOfComponent(SCH_COMPONENT *aComponent, LIB_PART *aEntry, SCH_SHEET_PATH *aSheetPath)
Function findAllUnitsOfComponent is used for "multiple parts per package" components.
A subgraph is a set of items that are electrically connected on a single sheet.
int RefDesStringCompare(const wxString &aFirst, const wxString &aSecond)
Acts just like the strcmp function but treats numbers within the string text correctly for sorting.
std::set< LIB_PART *, LIB_PART_LESS_THAN > m_LibParts
unique library parts used.
std::vector< SCH_ITEM * > m_items
void CreatePinList(SCH_COMPONENT *aItem, SCH_SHEET_PATH *aSheetPath)
Function findNextComponentAndCreatePinList finds a component from the DrawList and builds its pin lis...
Define a library symbol object.
std::vector< PIN_INFO > m_SortedComponentPinList
Used to temporarily store and filter the list of pins of a schematic component when generating schema...
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()
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieves a list of the SCH_PINs for the given sheet path.
static bool sortPinsByNum(PIN_INFO &aPin1, PIN_INFO &aPin2)
Comparison routine for sorting by pin numbers.
see class PGM_BASE
Schematic symbol object.
Definition: sch_component.h:79
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: eda_item.h:148
Definition for part library class.
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
wxString num
KICAD_T Type() const
Function Type()
Definition: eda_item.h:182
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
void eraseDuplicatePins()
Function eraseDuplicatePins erase duplicate Pins from m_SortedComponentPinList (i....