KiCad PCB EDA Suite
netlist_exporter_generic.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-2013 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 
27 
28 #include <build_version.h>
29 #include <sch_base_frame.h>
30 #include <class_library.h>
31 #include <kicad_string.h>
32 #include <connection_graph.h>
33 #include <refdes_utils.h>
34 
35 #include <symbol_lib_table.h>
36 
37 
38 static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 );
39 
40 bool NETLIST_EXPORTER_GENERIC::WriteNetlist( const wxString& aOutFileName,
41  unsigned aNetlistOptions )
42 {
43  // output the XML format netlist.
44  wxXmlDocument xdoc;
45 
46  xdoc.SetRoot( makeRoot( GNL_ALL | aNetlistOptions ) );
47 
48  return xdoc.Save( aOutFileName, 2 /* indent bug, today was ignored by wxXml lib */ );
49 }
50 
51 
53 {
54  XNODE* xroot = node( "export" );
55 
56  xroot->AddAttribute( "version", "D" );
57 
58  if( aCtl & GNL_HEADER )
59  // add the "design" header
60  xroot->AddChild( makeDesignHeader() );
61 
62  if( aCtl & GNL_COMPONENTS )
63  xroot->AddChild( makeComponents( aCtl ) );
64 
65  if( aCtl & GNL_PARTS )
66  xroot->AddChild( makeLibParts() );
67 
68  if( aCtl & GNL_LIBRARIES )
69  // must follow makeGenericLibParts()
70  xroot->AddChild( makeLibraries() );
71 
72  if( aCtl & GNL_NETS )
73  xroot->AddChild( makeListOfNets( aCtl ) );
74 
75  return xroot;
76 }
77 
78 
81 {
82  wxString value;
83  wxString datasheet;
84  wxString footprint;
85 
86  std::map< wxString, wxString > f;
87 };
88 
89 
91  SCH_SHEET_PATH* aSheet )
92 {
93  COMP_FIELDS fields;
94 
95  if( comp->GetUnitCount() > 1 )
96  {
97  // Sadly, each unit of a component can have its own unique fields. This
98  // block finds the unit with the lowest number having a non blank field
99  // value and records it. Therefore user is best off setting fields
100  // into only the first unit. But this scavenger algorithm will find
101  // any non blank fields in all units and use the first non-blank field
102  // for each unique field name.
103 
104  wxString ref = comp->GetRef( aSheet );
105 
106  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
107  int minUnit = comp->GetUnit();
108 
109  for( unsigned i = 0; i < sheetList.size(); i++ )
110  {
111  for( auto item : sheetList[i].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
112  {
113  SCH_COMPONENT* comp2 = (SCH_COMPONENT*) item;
114 
115  wxString ref2 = comp2->GetRef( &sheetList[i] );
116 
117  if( ref2.CmpNoCase( ref ) != 0 )
118  continue;
119 
120  int unit = comp2->GetUnit();
121 
122  // The lowest unit number wins. User should only set fields in any one unit.
123  // remark: IsVoid() returns true for empty strings or the "~" string (empty
124  // field value)
125  if( !comp2->GetValue( &sheetList[i] ).IsEmpty()
126  && ( unit < minUnit || fields.value.IsEmpty() ) )
127  {
128  if( m_resolveTextVars )
129  fields.value = comp2->GetValue( &sheetList[i] );
130  else
131  fields.value = comp2->GetField( VALUE )->GetText();
132  }
133 
134  if( !comp2->GetFootprint( &sheetList[i] ).IsEmpty()
135  && ( unit < minUnit || fields.footprint.IsEmpty() ) )
136  {
137  if( m_resolveTextVars )
138  fields.footprint = comp2->GetFootprint( &sheetList[i] );
139  else
140  fields.footprint = comp2->GetField( FOOTPRINT )->GetText();
141  }
142 
143  if( !comp2->GetField( DATASHEET )->IsVoid()
144  && ( unit < minUnit || fields.datasheet.IsEmpty() ) )
145  {
146  if( m_resolveTextVars )
147  fields.datasheet = comp2->GetField( DATASHEET )->GetShownText();
148  else
149  fields.datasheet = comp2->GetField( DATASHEET )->GetText();
150  }
151 
152  for( int fldNdx = MANDATORY_FIELDS; fldNdx < comp2->GetFieldCount(); ++fldNdx )
153  {
154  SCH_FIELD* f = comp2->GetField( fldNdx );
155 
156  if( f->GetText().size()
157  && ( unit < minUnit || fields.f.count( f->GetName() ) == 0 ) )
158  {
159  if( m_resolveTextVars )
160  fields.f[ f->GetName() ] = f->GetShownText();
161  else
162  fields.f[ f->GetName() ] = f->GetText();
163  }
164  }
165 
166  minUnit = std::min( unit, minUnit );
167  }
168  }
169  }
170  else
171  {
172  if( m_resolveTextVars )
173  fields.value = comp->GetField( VALUE )->GetShownText();
174  else
175  fields.value = comp->GetField( VALUE )->GetText();
176 
177  if( m_resolveTextVars )
178  fields.footprint = comp->GetField( FOOTPRINT )->GetShownText();
179  else
180  fields.footprint = comp->GetField( FOOTPRINT )->GetText();
181 
182  if( m_resolveTextVars )
183  fields.datasheet = comp->GetField( DATASHEET )->GetShownText();
184  else
185  fields.datasheet = comp->GetField( DATASHEET )->GetText();
186 
187  for( int fldNdx = MANDATORY_FIELDS; fldNdx < comp->GetFieldCount(); ++fldNdx )
188  {
189  SCH_FIELD* f = comp->GetField( fldNdx );
190 
191  if( f->GetText().size() )
192  {
193  if( m_resolveTextVars )
194  fields.f[ f->GetName() ] = f->GetShownText();
195  else
196  fields.f[ f->GetName() ] = f->GetText();
197  }
198  }
199  }
200 
201  // Do not output field values blank in netlist:
202  if( fields.value.size() )
203  xcomp->AddChild( node( "value", fields.value ) );
204  else // value field always written in netlist
205  xcomp->AddChild( node( "value", "~" ) );
206 
207  if( fields.footprint.size() )
208  xcomp->AddChild( node( "footprint", fields.footprint ) );
209 
210  if( fields.datasheet.size() )
211  xcomp->AddChild( node( "datasheet", fields.datasheet ) );
212 
213  if( fields.f.size() )
214  {
215  XNODE* xfields;
216  xcomp->AddChild( xfields = node( "fields" ) );
217 
218  // non MANDATORY fields are output alphabetically
219  for( std::map< wxString, wxString >::const_iterator it = fields.f.begin();
220  it != fields.f.end(); ++it )
221  {
222  XNODE* xfield;
223  xfields->AddChild( xfield = node( "field", it->second ) );
224  xfield->AddAttribute( "name", it->first );
225  }
226  }
227 }
228 
229 
231 {
232  XNODE* xcomps = node( "components" );
233 
235  m_LibParts.clear();
236 
237  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
238 
239  // Output is xml, so there is no reason to remove spaces from the field values.
240  // And XML element names need not be translated to various languages.
241 
242  for( unsigned ii = 0; ii < sheetList.size(); ii++ )
243  {
244  SCH_SHEET_PATH sheet = sheetList[ii];
245 
246  auto cmp = [sheet]( SCH_COMPONENT* a, SCH_COMPONENT* b )
247  {
248  return ( UTIL::RefDesStringCompare( a->GetRef( &sheet ),
249  b->GetRef( &sheet ) ) < 0 );
250  };
251 
252  std::set<SCH_COMPONENT*, decltype( cmp )> ordered_components( cmp );
253 
254  for( SCH_ITEM* item : sheetList[ii].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
255  {
256  SCH_COMPONENT* comp = static_cast<SCH_COMPONENT*>( item );
257  auto test = ordered_components.insert( comp );
258 
259  if( !test.second )
260  {
261  if( ( *( test.first ) )->GetUnit() > comp->GetUnit() )
262  {
263  ordered_components.erase( test.first );
264  ordered_components.insert( comp );
265  }
266  }
267  }
268 
269  for( EDA_ITEM* item : ordered_components )
270  {
271  SCH_COMPONENT* comp = findNextComponent( item, &sheet );
272 
273  if( !comp
274  || ( ( aCtl & GNL_OPT_BOM ) && !comp->GetIncludeInBom() )
275  || ( ( aCtl & GNL_OPT_KICAD ) && !comp->GetIncludeOnBoard() ) )
276  {
277  continue;
278  }
279 
280  // Output the component's elements in order of expected access frequency.
281  // This may not always look best, but it will allow faster execution
282  // under XSL processing systems which do sequential searching within
283  // an element.
284 
285  XNODE* xcomp; // current component being constructed
286  xcomps->AddChild( xcomp = node( "comp" ) );
287 
288  xcomp->AddAttribute( "ref", comp->GetRef( &sheet ) );
289  addComponentFields( xcomp, comp, &sheetList[ii] );
290 
291  XNODE* xlibsource;
292  xcomp->AddChild( xlibsource = node( "libsource" ) );
293 
294  // "logical" library name, which is in anticipation of a better search
295  // algorithm for parts based on "logical_lib.part" and where logical_lib
296  // is merely the library name minus path and extension.
297  if( comp->GetPartRef() )
298  xlibsource->AddAttribute( "lib", comp->GetPartRef()->GetLibId().GetLibNickname() );
299 
300  // We only want the symbol name, not the full LIB_ID.
301  xlibsource->AddAttribute( "part", comp->GetLibId().GetLibItemName() );
302 
303  xlibsource->AddAttribute( "description", comp->GetDescription() );
304 
305  XNODE* xproperty;
306 
307  std::vector<SCH_FIELD>& fields = comp->GetFields();
308 
309  for( size_t jj = MANDATORY_FIELDS; jj < fields.size(); ++jj )
310  {
311  xcomp->AddChild( xproperty = node( "property" ) );
312  xproperty->AddAttribute( "name", fields[jj].GetName() );
313  xproperty->AddAttribute( "value", fields[jj].GetText() );
314  }
315 
316  for( const SCH_FIELD& sheetField : sheet.Last()->GetFields() )
317  {
318  xcomp->AddChild( xproperty = node( "property" ) );
319  xproperty->AddAttribute( "name", sheetField.GetName() );
320  xproperty->AddAttribute( "value", sheetField.GetText() );
321  }
322 
323  if( !comp->GetIncludeInBom() )
324  {
325  xcomp->AddChild( xproperty = node( "property" ) );
326  xproperty->AddAttribute( "name", "exclude_from_bom" );
327  }
328 
329  if( !comp->GetIncludeOnBoard() )
330  {
331  xcomp->AddChild( xproperty = node( "property" ) );
332  xproperty->AddAttribute( "name", "exclude_from_board" );
333  }
334 
335  XNODE* xsheetpath;
336  xcomp->AddChild( xsheetpath = node( "sheetpath" ) );
337 
338  xsheetpath->AddAttribute( "names", sheet.PathHumanReadable() );
339  xsheetpath->AddAttribute( "tstamps", sheet.PathAsString() );
340  xcomp->AddChild( node( "tstamp", comp->m_Uuid.AsString() ) );
341  }
342  }
343 
344  return xcomps;
345 }
346 
347 
349 {
350  SCH_SCREEN* screen;
351  XNODE* xdesign = node( "design" );
352  XNODE* xtitleBlock;
353  XNODE* xsheet;
354  XNODE* xcomment;
355  XNODE* xtextvar;
356  wxString sheetTxt;
357  wxFileName sourceFileName;
358 
359  // the root sheet is a special sheet, call it source
360  xdesign->AddChild( node( "source", m_schematic->GetFileName() ) );
361 
362  xdesign->AddChild( node( "date", DateAndTime() ) );
363 
364  // which Eeschema tool
365  xdesign->AddChild( node( "tool", wxString( "Eeschema " ) + GetBuildVersion() ) );
366 
367  const std::map<wxString, wxString>& properties = m_schematic->Prj().GetTextVars();
368 
369  for( const std::pair<const wxString, wxString>& prop : properties )
370  {
371  xdesign->AddChild( xtextvar = node( "textvar", prop.second ) );
372  xtextvar->AddAttribute( "name", prop.first );
373  }
374 
375  /*
376  * Export the sheets information
377  */
378  SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
379 
380  for( unsigned i = 0; i < sheetList.size(); i++ )
381  {
382  screen = sheetList[i].LastScreen();
383 
384  xdesign->AddChild( xsheet = node( "sheet" ) );
385 
386  // get the string representation of the sheet index number.
387  // Note that sheet->GetIndex() is zero index base and we need to increment the
388  // number by one to make it human readable
389  sheetTxt.Printf( "%u", i + 1 );
390  xsheet->AddAttribute( "number", sheetTxt );
391  xsheet->AddAttribute( "name", sheetList[i].PathHumanReadable() );
392  xsheet->AddAttribute( "tstamps", sheetList[i].PathAsString() );
393 
394 
395  TITLE_BLOCK tb = screen->GetTitleBlock();
396 
397  xsheet->AddChild( xtitleBlock = node( "title_block" ) );
398 
399  xtitleBlock->AddChild( node( "title", tb.GetTitle() ) );
400  xtitleBlock->AddChild( node( "company", tb.GetCompany() ) );
401  xtitleBlock->AddChild( node( "rev", tb.GetRevision() ) );
402  xtitleBlock->AddChild( node( "date", tb.GetDate() ) );
403 
404  // We are going to remove the fileName directories.
405  sourceFileName = wxFileName( screen->GetFileName() );
406  xtitleBlock->AddChild( node( "source", sourceFileName.GetFullName() ) );
407 
408  xtitleBlock->AddChild( xcomment = node( "comment" ) );
409  xcomment->AddAttribute( "number", "1" );
410  xcomment->AddAttribute( "value", tb.GetComment( 0 ) );
411 
412  xtitleBlock->AddChild( xcomment = node( "comment" ) );
413  xcomment->AddAttribute( "number", "2" );
414  xcomment->AddAttribute( "value", tb.GetComment( 1 ) );
415 
416  xtitleBlock->AddChild( xcomment = node( "comment" ) );
417  xcomment->AddAttribute( "number", "3" );
418  xcomment->AddAttribute( "value", tb.GetComment( 2 ) );
419 
420  xtitleBlock->AddChild( xcomment = node( "comment" ) );
421  xcomment->AddAttribute( "number", "4" );
422  xcomment->AddAttribute( "value", tb.GetComment( 3 ) );
423 
424  xtitleBlock->AddChild( xcomment = node( "comment" ) );
425  xcomment->AddAttribute( "number", "5" );
426  xcomment->AddAttribute( "value", tb.GetComment( 4 ) );
427 
428  xtitleBlock->AddChild( xcomment = node( "comment" ) );
429  xcomment->AddAttribute( "number", "6" );
430  xcomment->AddAttribute( "value", tb.GetComment( 5 ) );
431 
432  xtitleBlock->AddChild( xcomment = node( "comment" ) );
433  xcomment->AddAttribute( "number", "7" );
434  xcomment->AddAttribute( "value", tb.GetComment( 6 ) );
435 
436  xtitleBlock->AddChild( xcomment = node( "comment" ) );
437  xcomment->AddAttribute( "number", "8" );
438  xcomment->AddAttribute( "value", tb.GetComment( 7 ) );
439 
440  xtitleBlock->AddChild( xcomment = node( "comment" ) );
441  xcomment->AddAttribute( "number", "9" );
442  xcomment->AddAttribute( "value", tb.GetComment( 8 ) );
443  }
444 
445  return xdesign;
446 }
447 
448 
450 {
451  XNODE* xlibs = node( "libraries" ); // auto_ptr
452  SYMBOL_LIB_TABLE* symbolLibTable = m_schematic->Prj().SchSymbolLibTable();
453 
454  for( std::set<wxString>::iterator it = m_libraries.begin(); it!=m_libraries.end(); ++it )
455  {
456  wxString libNickname = *it;
457  XNODE* xlibrary;
458 
459  if( symbolLibTable->HasLibrary( libNickname ) )
460  {
461  xlibs->AddChild( xlibrary = node( "library" ) );
462  xlibrary->AddAttribute( "logical", libNickname );
463  xlibrary->AddChild( node( "uri", symbolLibTable->GetFullURI( libNickname ) ) );
464  }
465 
466  // @todo: add more fun stuff here
467  }
468 
469  return xlibs;
470 }
471 
472 
474 {
475  XNODE* xlibparts = node( "libparts" ); // auto_ptr
476 
477  LIB_PINS pinList;
478  LIB_FIELDS fieldList;
479 
480  m_libraries.clear();
481 
482  for( auto lcomp : m_LibParts )
483  {
484  wxString libNickname = lcomp->GetLibId().GetLibNickname();;
485 
486  // The library nickname will be empty if the cache library is used.
487  if( !libNickname.IsEmpty() )
488  m_libraries.insert( libNickname ); // inserts component's library if unique
489 
490  XNODE* xlibpart;
491  xlibparts->AddChild( xlibpart = node( "libpart" ) );
492  xlibpart->AddAttribute( "lib", libNickname );
493  xlibpart->AddAttribute( "part", lcomp->GetName() );
494 
495  //----- show the important properties -------------------------
496  if( !lcomp->GetDescription().IsEmpty() )
497  xlibpart->AddChild( node( "description", lcomp->GetDescription() ) );
498 
499  if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
500  xlibpart->AddChild( node( "docs", lcomp->GetDatasheetField().GetText() ) );
501 
502  // Write the footprint list
503  if( lcomp->GetFootprints().GetCount() )
504  {
505  XNODE* xfootprints;
506  xlibpart->AddChild( xfootprints = node( "footprints" ) );
507 
508  for( unsigned i=0; i<lcomp->GetFootprints().GetCount(); ++i )
509  {
510  xfootprints->AddChild( node( "fp", lcomp->GetFootprints()[i] ) );
511  }
512  }
513 
514  //----- show the fields here ----------------------------------
515  fieldList.clear();
516  lcomp->GetFields( fieldList );
517 
518  XNODE* xfields;
519  xlibpart->AddChild( xfields = node( "fields" ) );
520 
521  for( unsigned i=0; i<fieldList.size(); ++i )
522  {
523  if( !fieldList[i].GetText().IsEmpty() )
524  {
525  XNODE* xfield;
526  xfields->AddChild( xfield = node( "field", fieldList[i].GetText() ) );
527  xfield->AddAttribute( "name", fieldList[i].GetCanonicalName() );
528  }
529  }
530 
531  //----- show the pins here ------------------------------------
532  pinList.clear();
533  lcomp->GetPins( pinList, 0, 0 );
534 
535  /* we must erase redundant Pins references in pinList
536  * These redundant pins exist because some pins
537  * are found more than one time when a component has
538  * multiple parts per package or has 2 representations (DeMorgan conversion)
539  * For instance, a 74ls00 has DeMorgan conversion, with different pin shapes,
540  * and therefore each pin appears 2 times in the list.
541  * Common pins (VCC, GND) can also be found more than once.
542  */
543  sort( pinList.begin(), pinList.end(), sortPinsByNumber );
544  for( int ii = 0; ii < (int)pinList.size()-1; ii++ )
545  {
546  if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
547  { // 2 pins have the same number, remove the redundant pin at index i+1
548  pinList.erase(pinList.begin() + ii + 1);
549  ii--;
550  }
551  }
552 
553  if( pinList.size() )
554  {
555  XNODE* pins;
556 
557  xlibpart->AddChild( pins = node( "pins" ) );
558  for( unsigned i=0; i<pinList.size(); ++i )
559  {
560  XNODE* pin;
561 
562  pins->AddChild( pin = node( "pin" ) );
563  pin->AddAttribute( "num", pinList[i]->GetNumber() );
564  pin->AddAttribute( "name", pinList[i]->GetName() );
565  pin->AddAttribute( "type", pinList[i]->GetCanonicalElectricalTypeName() );
566 
567  // caution: construction work site here, drive slowly
568  }
569  }
570  }
571 
572  return xlibparts;
573 }
574 
575 
577 {
578  XNODE* xnets = node( "nets" ); // auto_ptr if exceptions ever get used.
579  wxString netCodeTxt;
580  wxString netName;
581  wxString ref;
582 
583  XNODE* xnet = 0;
584 
585  /* output:
586  <net code="123" name="/cfcard.sch/WAIT#">
587  <node ref="R23" pin="1"/>
588  <node ref="U18" pin="12"/>
589  </net>
590  */
591 
592  int code = 0;
593 
594  for( const auto& it : m_schematic->ConnectionGraph()->GetNetMap() )
595  {
596  bool added = false;
597  wxString net_name = it.first.first;
598  auto subgraphs = it.second;
599 
600  // Code starts at 1
601  code++;
602 
603  XNODE* xnode;
604  std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>> sorted_items;
605 
606  for( CONNECTION_SUBGRAPH* subgraph : subgraphs )
607  {
608  const SCH_SHEET_PATH& sheet = subgraph->m_sheet;
609 
610  for( SCH_ITEM* item : subgraph->m_items )
611  {
612  if( item->Type() == SCH_PIN_T )
613  {
614  SCH_PIN* pin = static_cast<SCH_PIN*>( item );
615  SCH_COMPONENT* comp = pin->GetParentComponent();
616 
617  if( !comp
618  || ( ( aCtl & GNL_OPT_BOM ) && !comp->GetIncludeInBom() )
619  || ( ( aCtl & GNL_OPT_KICAD ) && !comp->GetIncludeOnBoard() ) )
620  {
621  continue;
622  }
623 
624  sorted_items.emplace_back( pin, sheet );
625  }
626  }
627  }
628 
629  // Netlist ordering: Net name, then ref des, then pin name
630  std::sort( sorted_items.begin(), sorted_items.end(),
631  []( const std::pair<SCH_PIN*, SCH_SHEET_PATH>& a,
632  const std::pair<SCH_PIN*, SCH_SHEET_PATH>& b )
633  {
634  wxString ref_a = a.first->GetParentComponent()->GetRef( &a.second );
635  wxString ref_b = b.first->GetParentComponent()->GetRef( &b.second );
636 
637  if( ref_a == ref_b )
638  return a.first->GetNumber() < b.first->GetNumber();
639 
640  return ref_a < ref_b;
641  } );
642 
643  // Some duplicates can exist, for example on multi-unit parts with duplicated
644  // pins across units. If the user connects the pins on each unit, they will
645  // appear on separate subgraphs. Remove those here:
646  sorted_items.erase( std::unique( sorted_items.begin(), sorted_items.end(),
647  []( const std::pair<SCH_PIN*, SCH_SHEET_PATH>& a,
648  const std::pair<SCH_PIN*, SCH_SHEET_PATH>& b )
649  {
650  wxString ref_a = a.first->GetParentComponent()->GetRef( &a.second );
651  wxString ref_b = b.first->GetParentComponent()->GetRef( &b.second );
652 
653  return ref_a == ref_b && a.first->GetNumber() == b.first->GetNumber();
654  } ),
655  sorted_items.end() );
656 
657  for( const std::pair<SCH_PIN*, SCH_SHEET_PATH>& pair : sorted_items )
658  {
659  SCH_PIN* pin = pair.first;
660  SCH_SHEET_PATH sheet = pair.second;
661 
662  wxString refText = pin->GetParentComponent()->GetRef( &sheet );
663  wxString pinText = pin->GetNumber();
664 
665  // Skip power symbols and virtual components
666  if( refText[0] == wxChar( '#' ) )
667  continue;
668 
669  if( !added )
670  {
671  xnets->AddChild( xnet = node( "net" ) );
672  netCodeTxt.Printf( "%d", code );
673  xnet->AddAttribute( "code", netCodeTxt );
674  xnet->AddAttribute( "name", net_name );
675 
676  added = true;
677  }
678 
679  xnet->AddChild( xnode = node( "node" ) );
680  xnode->AddAttribute( "ref", refText );
681  xnode->AddAttribute( "pin", pinText );
682 
683  wxString pinName;
684 
685  if( pin->GetName() != "~" ) // ~ is a char used to code empty strings in libs.
686  pinName = pin->GetName();
687 
688  if( !pinName.IsEmpty() )
689  xnode->AddAttribute( "pinfunction", pinName );
690  }
691  }
692 
693  return xnets;
694 }
695 
696 
697 XNODE* NETLIST_EXPORTER_GENERIC::node( const wxString& aName,
698  const wxString& aTextualContent /* = wxEmptyString*/ )
699 {
700  XNODE* n = new XNODE( wxXML_ELEMENT_NODE, aName );
701 
702  if( aTextualContent.Len() > 0 ) // excludes wxEmptyString, the parameter's default value
703  n->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, aTextualContent ) );
704 
705  return n;
706 }
707 
708 
709 static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 )
710 {
711  // return "lhs < rhs"
712  return UTIL::RefDesStringCompare( aPin1->GetNumber(), aPin2->GetNumber() ) < 0;
713 }
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
bool WriteNetlist(const wxString &aOutFileName, unsigned aNetlistOptions) override
Write generic netlist to aOutFileName.
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
VTBL_ENTRY std::map< wxString, wxString > & GetTextVars() const
Definition: project.cpp:77
const wxString & GetFileName() const
Definition: sch_screen.h:186
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
name of datasheet
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.
XNODE * node(const wxString &aName, const wxString &aTextualContent=wxEmptyString)
A convenience function that creates a new XNODE with an optional textual child.
SCHEMATIC * m_schematic
The schematic we're generating a netlist for.
CONNECTION_GRAPH * ConnectionGraph() const
Definition: schematic.h:131
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
std::set< wxString > m_libraries
bool GetIncludeOnBoard() const
const wxString & GetComment(int aIdx) const
Definition: title_block.h:110
std::vector< LIB_PIN * > LIB_PINS
Helper for defining a list of pin object pointers.
Definition: lib_item.h:56
wxString PathHumanReadable(bool aUseShortRootName=true) const
Return the sheet path in a human readable form made from thesheet names.
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
int GetUnitCount() const
Return the number of units per package of the symbol.
Collection of utility functions for component reference designators (refdes)
wxString AsString() const
Definition: kiid.cpp:174
const TITLE_BLOCK & GetTitleBlock() const
Definition: sch_screen.h:191
wxString PathAsString() const
Return the path of time stamps which do not changes even when editing sheet parameters.
const wxString GetValue(const SCH_SHEET_PATH *sheet) const
wxString GetDescription() const
Return information about the aliased parts.
wxString GetNumber() const
Definition: sch_pin.h:116
void Clear()
Function Clear erases the record.
SCH_COMPONENT * findNextComponent(EDA_ITEM *aItem, SCH_SHEET_PATH *aSheetPath)
Checks if the given component should be processed for netlisting.
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:118
TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout,...
Definition: title_block.h:40
A subgraph is a set of items that are electrically connected on a single sheet.
Field Name Module PCB, i.e. "16DIP300".
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: sch_field.cpp:100
bool IsVoid() const
Function IsVoid returns true if the field is either empty or holds "~".
Definition: sch_field.cpp:309
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populates a std::vector with SCH_FIELDs.
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::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:270
std::set< LIB_PART *, LIB_PART_LESS_THAN > m_LibParts
unique library parts used.
int GetUnit() const
void addComponentFields(XNODE *xcomp, SCH_COMPONENT *comp, SCH_SHEET_PATH *aSheet)
const wxString GetFootprint(const SCH_SHEET_PATH *sheet) const
wxString GetBuildVersion()
Get the full KiCad version string.
const wxString & GetRevision() const
Definition: title_block.h:89
XNODE * makeRoot(unsigned aCtl=GNL_ALL)
Build the entire document tree for the generic export.
wxString GetFullURI(const wxString &aLibNickname, bool aExpandEnvVars=true) const
Return the full URI of the library mapped to aLibNickname.
const wxString & GetCompany() const
Definition: title_block.h:99
XNODE * makeDesignHeader()
Fills out a project "design" header into an XML node.
const NET_MAP & GetNetMap() const
Holder for multi-unit component fields.
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()
bool GetIncludeInBom() const
int GetFieldCount() const
Return the number of fields in this symbol.
XNODE * makeComponents(unsigned aCtl)
const KIID m_Uuid
Definition: eda_item.h:151
XNODE holds an XML or S-expression element.
Definition: xnode.h:43
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
Field Value of part, i.e. "3.3K".
const wxString & GetDate() const
Definition: title_block.h:79
const wxString & GetNumber() const
Definition: lib_pin.h:165
XNODE * makeListOfNets(unsigned aCtl)
Fill out an XML node with a list of nets and returns it.
std::vector< LIB_FIELD > LIB_FIELDS
Definition: lib_field.h:218
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:440
#define GNL_ALL
Schematic symbol object.
Definition: sch_component.h:79
PROJECT & Prj() const
Return a reference to the project this schematic is part of.
Definition: schematic.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
XNODE * makeLibraries()
Fill out an XML node with a list of used libraries and returns it.
std::map< wxString, wxString > f
const wxString & GetTitle() const
Definition: title_block.h:65
Definition for part library class.
static bool sortPinsByNumber(LIB_PIN *aPin1, LIB_PIN *aPin2)
const LIB_ID & GetLibId() const
SCH_COMPONENT * GetParentComponent() const
Definition: sch_pin.cpp:142
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
wxString DateAndTime()
Definition: string.cpp:400
wxString GetName() const
Definition: sch_pin.cpp:80
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.
XNODE * makeLibParts()
Fill out an XML node with the unique library parts and returns it.