KiCad PCB EDA Suite
Loading...
Searching...
No Matches
netlist_exporter_xml.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 <[email protected]>
6 * Copyright The 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 <common.h> // for ExpandTextVars
30#include <sch_base_frame.h>
31#include <sch_group.h>
32#include <symbol_library.h>
33#include <string_utils.h>
34#include <connection_graph.h>
35#include <core/kicad_algo.h>
36#include <wx/wfstream.h>
37#include <xnode.h> // also nests: <wx/xml/xml.h>
38#include <json_common.h>
39#include <project_sch.h>
40
41#include <symbol_lib_table.h>
42
43#include <set>
44
45static bool sortPinsByNumber( SCH_PIN* aPin1, SCH_PIN* aPin2 );
46
47bool NETLIST_EXPORTER_XML::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions,
48 REPORTER& aReporter )
49{
50 // output the XML format netlist.
51
52 // declare the stream ourselves to use the buffered FILE api
53 // instead of letting wx use the syscall variant
54 wxFFileOutputStream stream( aOutFileName );
55
56 if( !stream.IsOk() )
57 return false;
58
59 wxXmlDocument xdoc;
60 xdoc.SetRoot( makeRoot( GNL_ALL | aNetlistOptions ) );
61
62 return xdoc.Save( stream, 2 /* indent bug, today was ignored by wxXml lib */ );
63}
64
65
67{
68 XNODE* xroot = node( wxT( "export" ) );
69
70 xroot->AddAttribute( wxT( "version" ), wxT( "E" ) );
71
72 if( aCtl & GNL_HEADER )
73 // add the "design" header
74 xroot->AddChild( makeDesignHeader() );
75
76 if( aCtl & GNL_SYMBOLS )
77 {
78 xroot->AddChild( makeSymbols( aCtl ) );
79
80 if( aCtl & GNL_OPT_KICAD )
81 xroot->AddChild( makeGroups() );
82 }
83
84 if( aCtl & GNL_PARTS )
85 xroot->AddChild( makeLibParts() );
86
87 if( aCtl & GNL_LIBRARIES )
88 // must follow makeGenericLibParts()
89 xroot->AddChild( makeLibraries() );
90
91 if( aCtl & GNL_NETS )
92 xroot->AddChild( makeListOfNets( aCtl ) );
93
94 return xroot;
95}
96
97
99
100
102 const SCH_SHEET_PATH& aSheet,
103 const SCH_SHEET_LIST& aSheetList )
104{
105 wxString value;
106 wxString footprint;
107 wxString datasheet;
108 wxString description;
109 wxString candidate;
110 nlohmann::ordered_map<wxString, wxString> fields;
111
112 if( aSymbol->GetUnitCount() > 1 )
113 {
114 // Sadly, each unit of a symbol can have its own unique fields. This
115 // block finds the unit with the lowest number having a non blank field
116 // value and records it. Therefore user is best off setting fields
117 // into only the first unit. But this scavenger algorithm will find
118 // any non blank fields in all units and use the first non-blank field
119 // for each unique field name.
120
121 wxString ref = aSymbol->GetRef( &aSheet );
122
123 int minUnit = aSymbol->GetUnitSelection( &aSheet );
124
125 for( const SCH_SHEET_PATH& sheet : aSheetList )
126 {
127 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
128 {
129 SCH_SYMBOL* symbol2 = static_cast<SCH_SYMBOL*>( item );
130
131 wxString ref2 = symbol2->GetRef( &sheet );
132
133 if( ref2.CmpNoCase( ref ) != 0 )
134 continue;
135
136 int unit = symbol2->GetUnitSelection( &aSheet );
137
138 // The lowest unit number wins. User should only set fields in any one unit.
139
140 // Value
141 candidate = symbol2->GetValue( m_resolveTextVars, &sheet, false );
142
143 if( !candidate.IsEmpty() && ( unit < minUnit || value.IsEmpty() ) )
144 value = candidate;
145
146 // Footprint
147 candidate = symbol2->GetFootprintFieldText( m_resolveTextVars, &sheet, false );
148
149 if( !candidate.IsEmpty() && ( unit < minUnit || footprint.IsEmpty() ) )
150 footprint = candidate;
151
152 // Datasheet
153 candidate = m_resolveTextVars
154 ? symbol2->GetField( FIELD_T::DATASHEET )->GetShownText( &sheet, false )
155 : symbol2->GetField( FIELD_T::DATASHEET )->GetText();
156
157 if( !candidate.IsEmpty() && ( unit < minUnit || datasheet.IsEmpty() ) )
158 datasheet = candidate;
159
160 // Description
161 candidate = m_resolveTextVars
162 ? symbol2->GetField( FIELD_T::DESCRIPTION )->GetShownText( &sheet, false )
163 : symbol2->GetField( FIELD_T::DESCRIPTION )->GetText();
164
165 if( !candidate.IsEmpty() && ( unit < minUnit || description.IsEmpty() ) )
166 description = candidate;
167
168 // All non-mandatory fields
169 for( SCH_FIELD& field : symbol2->GetFields() )
170 {
171 if( field.IsMandatory() || field.IsPrivate() )
172 continue;
173
174 if( unit < minUnit || fields.count( field.GetName() ) == 0 )
175 {
177 fields[field.GetName()] = field.GetShownText( &aSheet, false );
178 else
179 fields[field.GetName()] = field.GetText();
180 }
181 }
182
183 minUnit = std::min( unit, minUnit );
184 }
185 }
186 }
187 else
188 {
189 value = aSymbol->GetValue( m_resolveTextVars, &aSheet, false );
190 footprint = aSymbol->GetFootprintFieldText( m_resolveTextVars, &aSheet, false );
191
192 SCH_FIELD* datasheetField = aSymbol->GetField( FIELD_T::DATASHEET );
193 SCH_FIELD* descriptionField = aSymbol->GetField( FIELD_T::DESCRIPTION );
194
195 // Datasheet
197 datasheet = datasheetField->GetShownText( &aSheet, false );
198 else
199 datasheet = datasheetField->GetText();
200
201 // Description
203 description = descriptionField->GetShownText( &aSheet, false );
204 else
205 description = descriptionField->GetText();
206
207 for( SCH_FIELD& field : aSymbol->GetFields() )
208 {
209 if( field.IsMandatory() || field.IsPrivate() )
210 continue;
211
213 fields[field.GetName()] = field.GetShownText( &aSheet, false );
214 else
215 fields[field.GetName()] = field.GetText();
216 }
217 }
218
219 fields[GetCanonicalFieldName( FIELD_T::FOOTPRINT )] = footprint;
221 fields[GetCanonicalFieldName( FIELD_T::DESCRIPTION )] = description;
222
223 // Do not output field values blank in netlist:
224 if( value.size() )
225 aNode->AddChild( node( wxT( "value" ), UnescapeString( value ) ) );
226 else // value field always written in netlist
227 aNode->AddChild( node( wxT( "value" ), wxT( "~" ) ) );
228
229 if( footprint.size() )
230 aNode->AddChild( node( wxT( "footprint" ), UnescapeString( footprint ) ) );
231
232 if( datasheet.size() )
233 aNode->AddChild( node( wxT( "datasheet" ), UnescapeString( datasheet ) ) );
234
235 if( description.size() )
236 aNode->AddChild( node( wxT( "description" ), UnescapeString( description ) ) );
237
238 XNODE* xfields;
239 aNode->AddChild( xfields = node( wxT( "fields" ) ) );
240
241 for( const auto& [ fieldName, fieldValue ] : fields )
242 {
243 XNODE* xfield = node( wxT( "field" ), UnescapeString( fieldValue ) );
244 xfield->AddAttribute( wxT( "name" ), UnescapeString( fieldName ) );
245 xfields->AddChild( xfield );
246 }
247}
248
249
251{
252 XNODE* xcomps = node( wxT( "components" ) );
253
255 m_libParts.clear();
256
257 SCH_SHEET_PATH currentSheet = m_schematic->CurrentSheet();
258 SCH_SHEET_LIST sheetList = m_schematic->Hierarchy();
259
260 // Output is xml, so there is no reason to remove spaces from the field values.
261 // And XML element names need not be translated to various languages.
262
263 for( const SCH_SHEET_PATH& sheet : sheetList )
264 {
265 // Change schematic CurrentSheet in each iteration to allow hierarchical
266 // resolution of text variables in sheet fields.
267 m_schematic->SetCurrentSheet( sheet );
268
269 auto cmp =
270 [&sheet]( SCH_SYMBOL* a, SCH_SYMBOL* b )
271 {
272 return ( StrNumCmp( a->GetRef( &sheet, false ),
273 b->GetRef( &sheet, false ), true ) < 0 );
274 };
275
276 std::set<SCH_SYMBOL*, decltype( cmp )> ordered_symbols( cmp );
277 std::multiset<SCH_SYMBOL*, decltype( cmp )> extra_units( cmp );
278
279 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
280 {
281 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
282 auto test = ordered_symbols.insert( symbol );
283
284 if( !test.second )
285 {
286 if( ( *( test.first ) )->m_Uuid > symbol->m_Uuid )
287 {
288 extra_units.insert( *( test.first ) );
289 ordered_symbols.erase( test.first );
290 ordered_symbols.insert( symbol );
291 }
292 else
293 {
294 extra_units.insert( symbol );
295 }
296 }
297 }
298
299 for( EDA_ITEM* item : ordered_symbols )
300 {
301 SCH_SYMBOL* symbol = findNextSymbol( item, sheet );
302 bool forBOM = aCtl & GNL_OPT_BOM;
303 bool forBoard = aCtl & GNL_OPT_KICAD;
304
305 if( !symbol )
306 continue;
307
308 if( forBOM && ( sheet.GetExcludedFromBOM() || symbol->ResolveExcludedFromBOM() ) )
309 continue;
310
311 if( forBoard && ( sheet.GetExcludedFromBoard() || symbol->ResolveExcludedFromBoard() ) )
312 continue;
313
314 // Output the symbol's elements in order of expected access frequency. This may
315 // not always look best, but it will allow faster execution under XSL processing
316 // systems which do sequential searching within an element.
317
318 XNODE* xcomp; // current symbol being constructed
319 xcomps->AddChild( xcomp = node( wxT( "comp" ) ) );
320
321 xcomp->AddAttribute( wxT( "ref" ), symbol->GetRef( &sheet ) );
322 addSymbolFields( xcomp, symbol, sheet, sheetList );
323
324 XNODE* xlibsource;
325 xcomp->AddChild( xlibsource = node( wxT( "libsource" ) ) );
326
327 // "logical" library name, which is in anticipation of a better search algorithm
328 // for parts based on "logical_lib.part" and where logical_lib is merely the library
329 // name minus path and extension.
330 wxString libName;
331 wxString partName;
332
333 if( symbol->UseLibIdLookup() )
334 {
335 libName = symbol->GetLibId().GetUniStringLibNickname();
336 partName = symbol->GetLibId().GetUniStringLibItemName();
337 }
338 else
339 {
340 partName = symbol->GetSchSymbolLibraryName();
341 }
342
343 xlibsource->AddAttribute( wxT( "lib" ), libName );
344
345 // We only want the symbol name, not the full LIB_ID.
346 xlibsource->AddAttribute( wxT( "part" ), partName );
347
348 xlibsource->AddAttribute( wxT( "description" ), symbol->GetDescription() );
349
350 /* Add the symbol properties. */
351 XNODE* xproperty;
352
353 std::vector<SCH_FIELD>& fields = symbol->GetFields();
354
355 for( SCH_FIELD& field : fields )
356 {
357 if( field.IsMandatory() || field.IsPrivate() )
358 continue;
359
360 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
361 xproperty->AddAttribute( wxT( "name" ), field.GetCanonicalName() );
362
364 xproperty->AddAttribute( wxT( "value" ), field.GetShownText( &sheet, false ) );
365 else
366 xproperty->AddAttribute( wxT( "value" ), field.GetText() );
367 }
368
369 for( const SCH_FIELD& sheetField : sheet.Last()->GetFields() )
370 {
371 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
372 xproperty->AddAttribute( wxT( "name" ), sheetField.GetCanonicalName() );
373
375 // do not allow GetShownText() to add any prefix useful only when displaying
376 // the field on screen
377 xproperty->AddAttribute( wxT( "value" ), sheetField.GetShownText( &sheet, false ) );
378 else
379 xproperty->AddAttribute( wxT( "value" ), sheetField.GetText() );
380 }
381
382 if( symbol->ResolveExcludedFromBOM() || sheet.GetExcludedFromBOM() )
383 {
384 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
385 xproperty->AddAttribute( wxT( "name" ), wxT( "exclude_from_bom" ) );
386 }
387
388 if( symbol->ResolveExcludedFromBoard() || sheet.GetExcludedFromBoard() )
389 {
390 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
391 xproperty->AddAttribute( wxT( "name" ), wxT( "exclude_from_board" ) );
392 }
393
394 if( symbol->ResolveDNP() || sheet.GetDNP() )
395 {
396 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
397 xproperty->AddAttribute( wxT( "name" ), wxT( "dnp" ) );
398 }
399
400 if( const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef() )
401 {
402 if( part->GetKeyWords().size() )
403 {
404 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
405 xproperty->AddAttribute( wxT( "name" ), wxT( "ki_keywords" ) );
406 xproperty->AddAttribute( wxT( "value" ), part->GetKeyWords() );
407 }
408
409 if( !part->GetFPFilters().IsEmpty() )
410 {
411 wxString filters;
412
413 for( const wxString& filter : part->GetFPFilters() )
414 filters += ' ' + filter;
415
416 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
417 xproperty->AddAttribute( wxT( "name" ), wxT( "ki_fp_filters" ) );
418 xproperty->AddAttribute( wxT( "value" ), filters.Trim( false ) );
419 }
420
421 if( part->GetDuplicatePinNumbersAreJumpers() )
422 xcomp->AddChild( node( wxT( "duplicate_pin_numbers_are_jumpers" ), wxT( "1" ) ) );
423
424 const std::vector<std::set<wxString>>& jumperGroups = part->JumperPinGroups();
425
426 if( !jumperGroups.empty() )
427 {
428 XNODE* groupNode;
429 xcomp->AddChild( xproperty = node( wxT( "jumper_pin_groups" ) ) );
430
431 for( const std::set<wxString>& group : jumperGroups )
432 {
433 xproperty->AddChild( groupNode = node( wxT( "group" ) ) );
434
435 for( const wxString& padName : group )
436 groupNode->AddAttribute( wxT( "pin" ), padName );
437 }
438 }
439 }
440
441 XNODE* xsheetpath;
442 xcomp->AddChild( xsheetpath = node( wxT( "sheetpath" ) ) );
443
444 xsheetpath->AddAttribute( wxT( "names" ), sheet.PathHumanReadable() );
445 xsheetpath->AddAttribute( wxT( "tstamps" ), sheet.PathAsString() );
446
447 // Node for component class
448 std::vector<wxString> compClassNames =
449 getComponentClassNamesForAllSymbolUnits( symbol, sheet, sheetList );
450
451 if( compClassNames.size() > 0 )
452 {
453 XNODE* xcompclasslist;
454 xcomp->AddChild( xcompclasslist = node( wxT( "component_classes" ) ) );
455
456 for( const wxString& compClass : compClassNames )
457 {
458 xcompclasslist->AddChild( node( wxT( "class" ), UnescapeString( compClass ) ) );
459 }
460 }
461
462 XNODE* xunits; // Node for extra units
463 xcomp->AddChild( xunits = node( wxT( "tstamps" ) ) );
464
465 auto range = extra_units.equal_range( symbol );
466 wxString uuid;
467
468 // Output a series of children with all UUIDs associated with the REFDES
469 for( auto it = range.first; it != range.second; ++it )
470 {
471 uuid = ( *it )->m_Uuid.AsString();
472
473 // Add a space between UUIDs, if not in KICAD mode (i.e.
474 // using wxXmlDocument::Save()). KICAD MODE has its own XNODE::Format function.
475 if( !( aCtl & GNL_OPT_KICAD ) ) // i.e. for .xml format
476 uuid += ' ';
477
478 xunits->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
479 }
480
481 // Output the primary UUID
482 uuid = symbol->m_Uuid.AsString();
483 xunits->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
484
485 // Emit unit information (per-unit name and pins) after tstamps
486 XNODE* xunitInfo;
487 xcomp->AddChild( xunitInfo = node( wxT( "units" ) ) );
488
489 // Emit all units defined by the library symbol, independent of placement
490 const std::unique_ptr<LIB_SYMBOL>& libSym = symbol->GetLibSymbolRef();
491
492 if( libSym )
493 {
494 for( const LIB_SYMBOL::UNIT_PIN_INFO& unitInfo : libSym->GetUnitPinInfo() )
495 {
496 XNODE* xunit;
497 xunitInfo->AddChild( xunit = node( wxT( "unit" ) ) );
498 xunit->AddAttribute( wxT( "name" ), unitInfo.m_unitName );
499
500 XNODE* xpins;
501 xunit->AddChild( xpins = node( wxT( "pins" ) ) );
502
503 for( const wxString& number : unitInfo.m_pinNumbers )
504 {
505 XNODE* xpin;
506 xpins->AddChild( xpin = node( wxT( "pin" ) ) );
507 xpin->AddAttribute( wxT( "num" ), number );
508 }
509 }
510 }
511 }
512 }
513
514 m_schematic->SetCurrentSheet( currentSheet );
515
516 return xcomps;
517}
518
519
521{
522 XNODE* xcomps = node( wxT( "groups" ) );
523
525 // Do not clear m_libParts here: it is populated in makeSymbols() and used later by
526 // makeLibParts() to emit the libparts section for CvPcb and other consumers.
527
528 SCH_SHEET_PATH currentSheet = m_schematic->CurrentSheet();
529 SCH_SHEET_LIST sheetList = m_schematic->Hierarchy();
530
531 for( const SCH_SHEET_PATH& sheet : sheetList )
532 {
533 // Change schematic CurrentSheet in each iteration to allow hierarchical
534 // resolution of text variables in sheet fields.
535 m_schematic->SetCurrentSheet( sheet );
536
537 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_GROUP_T ) )
538 {
539 SCH_GROUP* group = static_cast<SCH_GROUP*>( item );
540
541 XNODE* xgroup; // current symbol being constructed
542 xcomps->AddChild( xgroup = node( wxT( "group" ) ) );
543
544 xgroup->AddAttribute( wxT( "name" ), group->GetName() );
545 xgroup->AddAttribute( wxT( "uuid" ), group->m_Uuid.AsString() );
546 xgroup->AddAttribute( wxT( "lib_id" ), group->GetDesignBlockLibId().Format() );
547
548 XNODE* xmembers;
549 xgroup->AddChild( xmembers = node( wxT( "members" ) ) );
550
551 for( EDA_ITEM* member : group->GetItems() )
552 {
553 if( member->Type() == SCH_SYMBOL_T )
554 {
555 XNODE* xmember;
556 xmembers->AddChild( xmember = node( wxT( "member" ) ) );
557 xmember->AddAttribute( wxT( "uuid" ), member->m_Uuid.AsString() );
558 }
559 }
560 }
561 }
562
563 m_schematic->SetCurrentSheet( currentSheet );
564
565 return xcomps;
566}
567
568
570 SCH_SYMBOL* aSymbol, const SCH_SHEET_PATH& aSymbolSheet, const SCH_SHEET_LIST& aSheetList )
571{
572 std::unordered_set<wxString> compClassNames = aSymbol->GetComponentClassNames( &aSymbolSheet );
573 int primaryUnit = aSymbol->GetUnitSelection( &aSymbolSheet );
574
575 if( aSymbol->GetUnitCount() > 1 )
576 {
577 wxString ref = aSymbol->GetRef( &aSymbolSheet );
578
579 for( const SCH_SHEET_PATH& sheet : aSheetList )
580 {
581 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
582 {
583 SCH_SYMBOL* symbol2 = static_cast<SCH_SYMBOL*>( item );
584
585 wxString ref2 = symbol2->GetRef( &sheet );
586 int otherUnit = symbol2->GetUnitSelection( &sheet );
587
588 if( ref2.CmpNoCase( ref ) != 0 )
589 continue;
590
591 if( otherUnit == primaryUnit )
592 continue;
593
594 std::unordered_set<wxString> otherClassNames =
595 symbol2->GetComponentClassNames( &sheet );
596 compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
597 }
598 }
599 }
600
601 std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
602 std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
603 []( const wxString& str1, const wxString& str2 )
604 {
605 return str1.Cmp( str2 ) < 0;
606 } );
607
608 return sortedCompClassNames;
609}
610
611
613{
614 SCH_SCREEN* screen;
615 XNODE* xdesign = node( wxT( "design" ) );
616 XNODE* xtitleBlock;
617 XNODE* xsheet;
618 XNODE* xcomment;
619 XNODE* xtextvar;
620 wxString sheetTxt;
621 wxFileName sourceFileName;
622
623 // the root sheet is a special sheet, call it source
624 xdesign->AddChild( node( wxT( "source" ), m_schematic->GetFileName() ) );
625
626 xdesign->AddChild( node( wxT( "date" ), GetISO8601CurrentDateTime() ) );
627
628 // which Eeschema tool
629 xdesign->AddChild( node( wxT( "tool" ), wxT( "Eeschema " ) + GetBuildVersion() ) );
630
631 const std::map<wxString, wxString>& properties = m_schematic->Project().GetTextVars();
632
633 for( const std::pair<const wxString, wxString>& prop : properties )
634 {
635 xdesign->AddChild( xtextvar = node( wxT( "textvar" ), prop.second ) );
636 xtextvar->AddAttribute( wxT( "name" ), prop.first );
637 }
638
639 /*
640 * Export the sheets information
641 */
642 unsigned sheetIndex = 1; // Human readable index
643
644 for( const SCH_SHEET_PATH& sheet : m_schematic->Hierarchy() )
645 {
646 screen = sheet.LastScreen();
647
648 xdesign->AddChild( xsheet = node( wxT( "sheet" ) ) );
649
650 // get the string representation of the sheet index number.
651 sheetTxt.Printf( wxT( "%u" ), sheetIndex++ );
652 xsheet->AddAttribute( wxT( "number" ), sheetTxt );
653 xsheet->AddAttribute( wxT( "name" ), sheet.PathHumanReadable() );
654 xsheet->AddAttribute( wxT( "tstamps" ), sheet.PathAsString() );
655
656 TITLE_BLOCK tb = screen->GetTitleBlock();
657 PROJECT* prj = &m_schematic->Project();
658
659 xsheet->AddChild( xtitleBlock = node( wxT( "title_block" ) ) );
660
661 xtitleBlock->AddChild( node( wxT( "title" ), ExpandTextVars( tb.GetTitle(), prj ) ) );
662 xtitleBlock->AddChild( node( wxT( "company" ), ExpandTextVars( tb.GetCompany(), prj ) ) );
663 xtitleBlock->AddChild( node( wxT( "rev" ), ExpandTextVars( tb.GetRevision(), prj ) ) );
664 xtitleBlock->AddChild( node( wxT( "date" ), ExpandTextVars( tb.GetDate(), prj ) ) );
665
666 // We are going to remove the fileName directories.
667 sourceFileName = wxFileName( screen->GetFileName() );
668 xtitleBlock->AddChild( node( wxT( "source" ), sourceFileName.GetFullName() ) );
669
670 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
671 xcomment->AddAttribute( wxT( "number" ), wxT( "1" ) );
672 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 0 ), prj ) );
673
674 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
675 xcomment->AddAttribute( wxT( "number" ), wxT( "2" ) );
676 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 1 ), prj ) );
677
678 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
679 xcomment->AddAttribute( wxT( "number" ), wxT( "3" ) );
680 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 2 ), prj ) );
681
682 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
683 xcomment->AddAttribute( wxT( "number" ), wxT( "4" ) );
684 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 3 ), prj ) );
685
686 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
687 xcomment->AddAttribute( wxT( "number" ), wxT( "5" ) );
688 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 4 ), prj ) );
689
690 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
691 xcomment->AddAttribute( wxT( "number" ), wxT( "6" ) );
692 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 5 ), prj ) );
693
694 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
695 xcomment->AddAttribute( wxT( "number" ), wxT( "7" ) );
696 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 6 ), prj ) );
697
698 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
699 xcomment->AddAttribute( wxT( "number" ), wxT( "8" ) );
700 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 7 ), prj ) );
701
702 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
703 xcomment->AddAttribute( wxT( "number" ), wxT( "9" ) );
704 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 8 ), prj ) );
705 }
706
707 return xdesign;
708}
709
710
712{
713 XNODE* xlibs = node( wxT( "libraries" ) ); // auto_ptr
714 SYMBOL_LIB_TABLE* symbolLibTable = PROJECT_SCH::SchSymbolLibTable( &m_schematic->Project() );
715
716 for( std::set<wxString>::iterator it = m_libraries.begin(); it!=m_libraries.end(); ++it )
717 {
718 wxString libNickname = *it;
719 XNODE* xlibrary;
720
721 if( symbolLibTable->HasLibrary( libNickname ) )
722 {
723 xlibs->AddChild( xlibrary = node( wxT( "library" ) ) );
724 xlibrary->AddAttribute( wxT( "logical" ), libNickname );
725 xlibrary->AddChild( node( wxT( "uri" ), symbolLibTable->GetFullURI( libNickname ) ) );
726 }
727
728 // @todo: add more fun stuff here
729 }
730
731 return xlibs;
732}
733
734
736{
737 XNODE* xlibparts = node( wxT( "libparts" ) ); // auto_ptr
738 std::vector<SCH_FIELD*> fieldList;
739
740 m_libraries.clear();
741
742 for( LIB_SYMBOL* lcomp : m_libParts )
743 {
744 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
745
746 // The library nickname will be empty if the cache library is used.
747 if( !libNickname.IsEmpty() )
748 m_libraries.insert( libNickname ); // inserts symbol's library if unique
749
750 XNODE* xlibpart;
751 xlibparts->AddChild( xlibpart = node( wxT( "libpart" ) ) );
752 xlibpart->AddAttribute( wxT( "lib" ), libNickname );
753 xlibpart->AddAttribute( wxT( "part" ), lcomp->GetName() );
754
755 //----- show the important properties -------------------------
756 if( !lcomp->GetDescription().IsEmpty() )
757 xlibpart->AddChild( node( wxT( "description" ), lcomp->GetDescription() ) );
758
759 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
760 xlibpart->AddChild( node( wxT( "docs" ), lcomp->GetDatasheetField().GetText() ) );
761
762 // Write the footprint list
763 if( lcomp->GetFPFilters().GetCount() )
764 {
765 XNODE* xfootprints;
766 xlibpart->AddChild( xfootprints = node( wxT( "footprints" ) ) );
767
768 for( unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
769 {
770 if( !lcomp->GetFPFilters()[i].IsEmpty() )
771 xfootprints->AddChild( node( wxT( "fp" ), lcomp->GetFPFilters()[i] ) );
772 }
773 }
774
775 //----- show the fields here ----------------------------------
776 fieldList.clear();
777 lcomp->GetFields( fieldList );
778
779 XNODE* xfields;
780 xlibpart->AddChild( xfields = node( "fields" ) );
781
782 for( const SCH_FIELD* field : fieldList )
783 {
784 XNODE* xfield;
785 xfields->AddChild( xfield = node( wxT( "field" ), field->GetText() ) );
786 xfield->AddAttribute( wxT( "name" ), field->GetCanonicalName() );
787 }
788
789 //----- show the pins here ------------------------------------
790 // NOTE: Expand stacked-pin notation into individual pins so downstream
791 // tools (e.g. CvPcb) see the actual number of footprint pins.
792 std::vector<SCH_PIN*> pinList = lcomp->GetGraphicalPins( 0, 0 );
793
794 /*
795 * We must erase redundant Pins references in pinList
796 * These redundant pins exist because some pins are found more than one time when a
797 * symbol has multiple parts per package or has 2 representations (DeMorgan conversion).
798 * For instance, a 74ls00 has DeMorgan conversion, with different pin shapes, and
799 * therefore each pin appears 2 times in the list. Common pins (VCC, GND) can also be
800 * found more than once.
801 */
802 sort( pinList.begin(), pinList.end(), sortPinsByNumber );
803
804 for( int ii = 0; ii < (int)pinList.size()-1; ii++ )
805 {
806 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
807 { // 2 pins have the same number, remove the redundant pin at index i+1
808 pinList.erase(pinList.begin() + ii + 1);
809 ii--;
810 }
811 }
812
813 wxLogTrace( "CVPCB_PINCOUNT",
814 wxString::Format( "makeLibParts: lib='%s' part='%s' pinList(size)=%zu",
815 libNickname, lcomp->GetName(), pinList.size() ) );
816
817 if( pinList.size() )
818 {
819 XNODE* pins;
820
821 xlibpart->AddChild( pins = node( wxT( "pins" ) ) );
822
823 for( unsigned i=0; i<pinList.size(); ++i )
824 {
825 SCH_PIN* basePin = pinList[i];
826
827 bool stackedValid = false;
828 std::vector<wxString> expandedNums = basePin->GetStackedPinNumbers( &stackedValid );
829
830 // If stacked notation detected and valid, emit one libparts pin per expanded number.
831 if( stackedValid && !expandedNums.empty() )
832 {
833 for( const wxString& num : expandedNums )
834 {
835 XNODE* pin;
836 pins->AddChild( pin = node( wxT( "pin" ) ) );
837 pin->AddAttribute( wxT( "num" ), num );
838 pin->AddAttribute( wxT( "name" ), basePin->GetShownName() );
839 pin->AddAttribute( wxT( "type" ), basePin->GetCanonicalElectricalTypeName() );
840
841 wxLogTrace( "CVPCB_PINCOUNT",
842 wxString::Format( "makeLibParts: -> pin num='%s' name='%s' (expanded)",
843 num, basePin->GetShownName() ) );
844 }
845 }
846 else
847 {
848 XNODE* pin;
849 pins->AddChild( pin = node( wxT( "pin" ) ) );
850 pin->AddAttribute( wxT( "num" ), basePin->GetShownNumber() );
851 pin->AddAttribute( wxT( "name" ), basePin->GetShownName() );
852 pin->AddAttribute( wxT( "type" ), basePin->GetCanonicalElectricalTypeName() );
853
854 wxLogTrace( "CVPCB_PINCOUNT",
855 wxString::Format( "makeLibParts: -> pin num='%s' name='%s'",
856 basePin->GetShownNumber(),
857 basePin->GetShownName() ) );
858 }
859
860 // caution: construction work site here, drive slowly
861 }
862 }
863 }
864
865 return xlibparts;
866}
867
868
870{
871 wxString netCodeTxt;
872 XNODE* xnets = node( wxT( "nets" ) ); // auto_ptr if exceptions ever get used.
873 XNODE* xnet = nullptr;
874
875 /* output:
876 <net code="123" name="/cfcard.sch/WAIT#" class="signal">
877 <node ref="R23" pin="1"/>
878 <node ref="U18" pin="12"/>
879 </net>
880 */
881
882 struct NET_NODE
883 {
884 NET_NODE( SCH_PIN* aPin, const SCH_SHEET_PATH& aSheet ) :
885 m_Pin( aPin ),
886 m_Sheet( aSheet )
887 {}
888
889 SCH_PIN* m_Pin;
890 SCH_SHEET_PATH m_Sheet;
891 };
892
893 struct NET_RECORD
894 {
895 NET_RECORD( const wxString& aName ) :
896 m_Name( aName ),
897 m_HasNoConnect( false )
898 {};
899
900 wxString m_Name;
901 wxString m_Class;
902 bool m_HasNoConnect;
903 std::vector<NET_NODE> m_Nodes;
904 };
905
906 std::vector<NET_RECORD*> nets;
907
908 for( const auto& [ key, subgraphs ] : m_schematic->ConnectionGraph()->GetNetMap() )
909 {
910 wxString net_name = key.Name;
911 NET_RECORD* net_record = nullptr;
912
913 if( !( aCtl & GNL_OPT_KICAD ) )
914 net_name = UnescapeString( net_name );
915
916 if( subgraphs.empty() )
917 continue;
918
919 nets.emplace_back( new NET_RECORD( net_name ) );
920 net_record = nets.back();
921
922 for( CONNECTION_SUBGRAPH* subgraph : subgraphs )
923 {
924 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() == SCH_NO_CONNECT_T;
925 const SCH_SHEET_PATH& sheet = subgraph->GetSheet();
926
927 if( net_record->m_Class.IsEmpty() && subgraph->GetDriver() )
928 {
929 if( subgraph->GetDriver()->GetEffectiveNetClass() )
930 {
931 net_record->m_Class = subgraph->GetDriver()->GetEffectiveNetClass()->GetName();
932 net_record->m_Class = UnescapeString( net_record->m_Class );
933 }
934 }
935
936 if( nc )
937 net_record->m_HasNoConnect = true;
938
939 for( SCH_ITEM* item : subgraph->GetItems() )
940 {
941 if( item->Type() == SCH_PIN_T )
942 {
943 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
944 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( pin->GetParentSymbol() );
945 bool forBOM = aCtl & GNL_OPT_BOM;
946 bool forBoard = aCtl & GNL_OPT_KICAD;
947
948 if( !symbol )
949 continue;
950
951 if( forBOM && ( sheet.GetExcludedFromBOM() || symbol->ResolveExcludedFromBOM() ) )
952 continue;
953
954 if( forBoard && ( sheet.GetExcludedFromBoard() || symbol->ResolveExcludedFromBoard() ) )
955 continue;
956
957 net_record->m_Nodes.emplace_back( pin, sheet );
958 }
959 }
960 }
961 }
962
963 // Netlist ordering: Net name, then ref des, then pin name
964 std::sort( nets.begin(), nets.end(),
965 []( const NET_RECORD* a, const NET_RECORD*b )
966 {
967 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
968 } );
969
970 for( int i = 0; i < (int) nets.size(); ++i )
971 {
972 NET_RECORD* net_record = nets[i];
973 bool added = false;
974 XNODE* xnode;
975
976 // Netlist ordering: Net name, then ref des, then pin name
977 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
978 []( const NET_NODE& a, const NET_NODE& b )
979 {
980 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
981 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
982
983 if( refA == refB )
984 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
985
986 return refA < refB;
987 } );
988
989 // Some duplicates can exist, for example on multi-unit parts with duplicated pins across
990 // units. If the user connects the pins on each unit, they will appear on separate
991 // subgraphs. Remove those here:
992 alg::remove_duplicates( net_record->m_Nodes,
993 []( const NET_NODE& a, const NET_NODE& b )
994 {
995 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
996 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
997
998 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
999 } );
1000
1001 // Determine if all pins in the net are stacked (nets with only one pin are implicitly
1002 // taken to be stacked)
1003 bool allNetPinsStacked = true;
1004
1005 if( net_record->m_Nodes.size() > 1 )
1006 {
1007 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
1008 allNetPinsStacked =
1009 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
1010 [=]( auto& node )
1011 {
1012 return firstPin->GetParent() == node.m_Pin->GetParent()
1013 && firstPin->GetPosition() == node.m_Pin->GetPosition()
1014 && firstPin->GetName() == node.m_Pin->GetName();
1015 } );
1016 }
1017
1018 for( const NET_NODE& netNode : net_record->m_Nodes )
1019 {
1020 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
1021
1022 // Skip power symbols and virtual symbols
1023 if( refText[0] == wxChar( '#' ) )
1024 continue;
1025
1026 if( !added )
1027 {
1028 netCodeTxt.Printf( wxT( "%d" ), i + 1 );
1029
1030 xnets->AddChild( xnet = node( wxT( "net" ) ) );
1031 xnet->AddAttribute( wxT( "code" ), netCodeTxt );
1032 xnet->AddAttribute( wxT( "name" ), net_record->m_Name );
1033 xnet->AddAttribute( wxT( "class" ), net_record->m_Class );
1034
1035 added = true;
1036 }
1037
1038 std::vector<wxString> nums = netNode.m_Pin->GetStackedPinNumbers();
1039 wxString baseName = netNode.m_Pin->GetShownName();
1040 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
1041
1042 wxLogTrace( "KICAD_STACKED_PINS",
1043 wxString::Format( "XML: net='%s' ref='%s' base='%s' shownNum='%s' expand=%zu",
1044 net_record->m_Name, refText, baseName,
1045 netNode.m_Pin->GetShownNumber(), nums.size() ) );
1046
1047 for( const wxString& num : nums )
1048 {
1049 xnet->AddChild( xnode = node( wxT( "node" ) ) );
1050 xnode->AddAttribute( wxT( "ref" ), refText );
1051 xnode->AddAttribute( wxT( "pin" ), num );
1052
1053 wxString fullName = baseName.IsEmpty() ? num : baseName + wxT( "_" ) + num;
1054
1055 if( !baseName.IsEmpty() || nums.size() > 1 )
1056 xnode->AddAttribute( wxT( "pinfunction" ), fullName );
1057
1058 wxString typeAttr = pinType;
1059
1060 if( net_record->m_HasNoConnect
1061 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
1062 {
1063 typeAttr += wxT( "+no_connect" );
1064 wxLogTrace( "KICAD_STACKED_PINS",
1065 wxString::Format( "XML: marking node ref='%s' pin='%s' as no_connect",
1066 refText, num ) );
1067 }
1068
1069 xnode->AddAttribute( wxT( "pintype" ), typeAttr );
1070 }
1071 }
1072 }
1073
1074 for( NET_RECORD* record : nets )
1075 delete record;
1076
1077 return xnets;
1078}
1079
1080
1081XNODE* NETLIST_EXPORTER_XML::node( const wxString& aName,
1082 const wxString& aTextualContent /* = wxEmptyString*/ )
1083{
1084 XNODE* n = new XNODE( wxXML_ELEMENT_NODE, aName );
1085
1086 if( aTextualContent.Len() > 0 ) // excludes wxEmptyString, the parameter's default value
1087 n->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, aTextualContent ) );
1088
1089 return n;
1090}
1091
1092
1093static bool sortPinsByNumber( SCH_PIN* aPin1, SCH_PIN* aPin2 )
1094{
1095 // return "lhs < rhs"
1096 return StrNumCmp( aPin1->GetShownNumber(), aPin2->GetShownNumber(), true ) < 0;
1097}
wxString GetBuildVersion()
Get the full KiCad version string.
A subgraph is a set of items that are electrically connected on a single sheet.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:516
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
wxString AsString() const
Definition kiid.cpp:246
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:112
const wxString GetUniStringLibNickname() const
Definition lib_id.h:88
Define a library symbol object.
Definition lib_symbol.h:87
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
wxString GetFullURI(const wxString &aLibNickname, bool aExpandEnvVars=true) const
Return the full URI of the library mapped to aLibNickname.
SCHEMATIC * m_schematic
The schematic we're generating a netlist for.
SCH_SYMBOL * findNextSymbol(EDA_ITEM *aItem, const SCH_SHEET_PATH &aSheetPath)
Check if the given symbol should be processed for netlisting.
std::set< LIB_SYMBOL *, LIB_SYMBOL_LESS_THAN > m_libParts
unique library symbols used. LIB_SYMBOL items are sorted by names
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
XNODE * makeDesignHeader()
Fill out a project "design" header into an XML node.
XNODE * makeLibraries()
Fill out an XML node with a list of used libraries and returns it.
bool WriteNetlist(const wxString &aOutFileName, unsigned aNetlistOptions, REPORTER &aReporter) override
Write generic netlist to aOutFileName.
XNODE * node(const wxString &aName, const wxString &aTextualContent=wxEmptyString)
A convenience function that creates a new XNODE with an optional textual child.
XNODE * makeListOfNets(unsigned aCtl)
Fill out an XML node with a list of nets and returns it.
void addSymbolFields(XNODE *aNode, SCH_SYMBOL *aSymbol, const SCH_SHEET_PATH &aSheet, const SCH_SHEET_LIST &aSheetList)
Holder for multi-unit symbol fields.
std::vector< wxString > getComponentClassNamesForAllSymbolUnits(SCH_SYMBOL *aSymbol, const SCH_SHEET_PATH &aSymbolSheet, const SCH_SHEET_LIST &aSheetList)
Finds all component class names attached to any sub-unit of a given symbol.
XNODE * makeSymbols(unsigned aCtl)
XNODE * makeRoot(unsigned aCtl=GNL_ALL)
Build the entire document tree for the generic export.
std::set< wxString > m_libraries
XNODE * makeLibParts()
Fill out an XML node with the unique library parts and returns it.
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
Container for project specific data.
Definition project.h:65
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
bool ResolveExcludedFromBoard() const
Definition sch_item.cpp:306
bool ResolveExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:290
bool ResolveDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:321
wxString GetShownNumber() const
Definition sch_pin.cpp:587
std::vector< wxString > GetStackedPinNumbers(bool *aValid=nullptr) const
Definition sch_pin.cpp:593
wxString GetCanonicalElectricalTypeName() const
Definition sch_pin.cpp:342
wxString GetShownName() const
Definition sch_pin.cpp:576
const wxString & GetFileName() const
Definition sch_screen.h:152
const TITLE_BLOCK & GetTitleBlock() const
Definition sch_screen.h:163
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool GetExcludedFromBOM() const
const SCH_SHEET * GetSheet(unsigned aIndex) const
bool GetExcludedFromBoard() const
Schematic symbol object.
Definition sch_symbol.h:75
wxString GetDescription() const override
bool UseLibIdLookup() const
Definition sch_symbol.h:181
wxString GetSchSymbolLibraryName() const
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const override
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
int GetUnitCount() const override
Return the number of units per package of the symbol.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:183
std::unordered_set< wxString > GetComponentClassNames(const SCH_SHEET_PATH *aPath) const
Return the component classes this symbol belongs in.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:41
const wxString & GetCompany() const
Definition title_block.h:96
const wxString & GetRevision() const
Definition title_block.h:86
const wxString & GetDate() const
Definition title_block.h:76
const wxString & GetComment(int aIdx) const
const wxString & GetTitle() const
Definition title_block.h:63
Hold an XML or S-expression element.
Definition xnode.h:43
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:59
The common library.
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition kicad_algo.h:161
static bool sortPinsByNumber(SCH_PIN *aPin1, SCH_PIN *aPin2)
#define GNL_ALL
@ GNL_LIBRARIES
@ GNL_OPT_KICAD
@ GNL_SYMBOLS
@ GNL_OPT_BOM
Class to handle a set of SCH_ITEMs.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
Definition for symbol library class.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
wxString GetCanonicalFieldName(FIELD_T aFieldType)
@ SCH_GROUP_T
Definition typeinfo.h:177
@ SCH_NO_CONNECT_T
Definition typeinfo.h:164
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_PIN_T
Definition typeinfo.h:157