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, see <https://www.gnu.org/licenses/>.
20 */
21
23
24#include <algorithm>
25#include <build_version.h>
26#include <gal/color4d.h>
27#include <common.h> // for ExpandTextVars
28#include <sch_base_frame.h>
29#include <sch_group.h>
30#include <sch_sheet.h>
31#include <string_utils.h>
32#include <connection_graph.h>
33#include <pgm_base.h>
34#include <core/kicad_algo.h>
35#include <wx/wfstream.h>
36#include <xnode.h> // also nests: <wx/xml/xml.h>
37#include <json_common.h>
38#include <project_sch.h>
41#include <sch_rule_area.h>
42#include <trace_helpers.h>
43
44#include <map>
45#include <set>
47#include <sch_sheet_path.h>
48
49static bool sortPinsByNumber( SCH_PIN* aPin1, SCH_PIN* aPin2 );
50
51bool NETLIST_EXPORTER_XML::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions,
52 REPORTER& aReporter )
53{
54 // output the XML format netlist.
55
56 // declare the stream ourselves to use the buffered FILE api
57 // instead of letting wx use the syscall variant
58 wxFFileOutputStream stream( aOutFileName );
59
60 if( !stream.IsOk() )
61 return false;
62
63 wxXmlDocument xdoc;
64 xdoc.SetRoot( makeRoot( GNL_ALL | aNetlistOptions ) );
65
66 return xdoc.Save( stream, 2 /* indent bug, today was ignored by wxXml lib */ );
67}
68
69
71{
72 XNODE* xroot = node( wxT( "export" ) );
73
74 xroot->AddAttribute( wxT( "version" ), wxT( "E" ) );
75
76 if( aCtl & GNL_HEADER )
77 // add the "design" header
78 xroot->AddChild( makeDesignHeader() );
79
80 if( aCtl & GNL_SYMBOLS )
81 {
82 xroot->AddChild( makeSymbols( aCtl ) );
83
84 if( aCtl & GNL_OPT_KICAD )
85 {
86 xroot->AddChild( makeGroups() );
87 xroot->AddChild( makeVariants() );
88 }
89 }
90
91 if( aCtl & GNL_PARTS )
92 xroot->AddChild( makeLibParts() );
93
94 if( aCtl & GNL_LIBRARIES )
95 // must follow makeGenericLibParts()
96 xroot->AddChild( makeLibraries() );
97
98 if( aCtl & GNL_NETS )
99 {
100 xroot->AddChild( makeListOfNets( aCtl ) );
101
102 // Net chains are a KiCad-internal extension that is not part of the public XML
103 // netlist schema (version "E"). Emit them only for the KiCad-internal consumer
104 // (eeschema -> pcbnew via NETLIST_EXPORTER_KICAD) so that generic XML, KiCost and
105 // other schema-validating tools do not see an unexpected element.
106 if( aCtl & GNL_OPT_KICAD )
107 {
108 if( XNODE* xchains = makeNetChains() )
109 xroot->AddChild( xchains );
110 }
111 }
112
113 return xroot;
114}
115
116
118
119
121 const SCH_SHEET_PATH& aSheet,
122 const SCH_SHEET_LIST& aSheetList )
123{
124 wxString value;
125 wxString footprint;
126 wxString datasheet;
127 wxString description;
128 wxString candidate;
129 nlohmann::ordered_map<wxString, wxString> fields;
130
131 if( aSymbol->GetUnitCount() > 1 )
132 {
133 // Sadly, each unit of a symbol can have its own unique fields. This
134 // block finds the unit with the lowest number having a non blank field
135 // value and records it. Therefore user is best off setting fields
136 // into only the first unit. But this scavenger algorithm will find
137 // any non blank fields in all units and use the first non-blank field
138 // for each unique field name.
139
140 wxString ref = aSymbol->GetRef( &aSheet );
141
142 int minUnit = aSymbol->GetUnitSelection( &aSheet );
143
144 for( const SCH_SHEET_PATH& sheet : aSheetList )
145 {
146 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
147 {
148 SCH_SYMBOL* symbol2 = static_cast<SCH_SYMBOL*>( item );
149
150 wxString ref2 = symbol2->GetRef( &sheet );
151
152 if( ref2.CmpNoCase( ref ) != 0 )
153 continue;
154
155 int unit = symbol2->GetUnitSelection( &aSheet );
156
157 // The lowest unit number wins. User should only set fields in any one unit.
158
159 // Value
160 candidate = symbol2->GetValue( m_resolveTextVars, &sheet, false );
161
162 if( !candidate.IsEmpty() && ( unit < minUnit || value.IsEmpty() ) )
163 value = candidate;
164
165 // Footprint
166 candidate = symbol2->GetFootprintFieldText( m_resolveTextVars, &sheet, false );
167
168 if( !candidate.IsEmpty() && ( unit < minUnit || footprint.IsEmpty() ) )
169 footprint = candidate;
170
171 // Datasheet
172 candidate = m_resolveTextVars ? symbol2->GetField( FIELD_T::DATASHEET )->GetShownText( &sheet, false )
173 : symbol2->GetField( FIELD_T::DATASHEET )->GetText();
174
175 if( !candidate.IsEmpty() && ( unit < minUnit || datasheet.IsEmpty() ) )
176 datasheet = candidate;
177
178 // Description
179 candidate = m_resolveTextVars ? symbol2->GetField( FIELD_T::DESCRIPTION )->GetShownText( &sheet, false )
180 : symbol2->GetField( FIELD_T::DESCRIPTION )->GetText();
181
182 if( !candidate.IsEmpty() && ( unit < minUnit || description.IsEmpty() ) )
183 description = candidate;
184
185 // All non-mandatory fields
186 for( SCH_FIELD& field : symbol2->GetFields() )
187 {
188 if( field.IsMandatory() || field.IsPrivate() )
189 continue;
190
191 if( unit < minUnit || fields.count( field.GetName() ) == 0 )
192 {
194 fields[field.GetName()] = field.GetShownText( &aSheet, false );
195 else
196 fields[field.GetName()] = field.GetText();
197 }
198 }
199
200 minUnit = std::min( unit, minUnit );
201 }
202 }
203 }
204 else
205 {
206 value = aSymbol->GetValue( m_resolveTextVars, &aSheet, false );
207 footprint = aSymbol->GetFootprintFieldText( m_resolveTextVars, &aSheet, false );
208
209 SCH_FIELD* datasheetField = aSymbol->GetField( FIELD_T::DATASHEET );
210 SCH_FIELD* descriptionField = aSymbol->GetField( FIELD_T::DESCRIPTION );
211
212 // Datasheet
214 datasheet = datasheetField->GetShownText( &aSheet, false );
215 else
216 datasheet = datasheetField->GetText();
217
218 // Description
220 description = descriptionField->GetShownText( &aSheet, false );
221 else
222 description = descriptionField->GetText();
223
224 for( SCH_FIELD& field : aSymbol->GetFields() )
225 {
226 if( field.IsMandatory() || field.IsPrivate() )
227 continue;
228
230 fields[field.GetName()] = field.GetShownText( &aSheet, false );
231 else
232 fields[field.GetName()] = field.GetText();
233 }
234 }
235
236 fields[GetCanonicalFieldName( FIELD_T::FOOTPRINT )] = footprint;
238 fields[GetCanonicalFieldName( FIELD_T::DESCRIPTION )] = description;
239
240 // Do not output field values blank in netlist:
241 if( value.size() )
242 aNode->AddChild( node( wxT( "value" ), UnescapeString( value ) ) );
243 else // value field always written in netlist
244 aNode->AddChild( node( wxT( "value" ), wxT( "~" ) ) );
245
246 if( footprint.size() )
247 aNode->AddChild( node( wxT( "footprint" ), UnescapeString( footprint ) ) );
248
249 if( datasheet.size() )
250 aNode->AddChild( node( wxT( "datasheet" ), UnescapeString( datasheet ) ) );
251
252 if( description.size() )
253 aNode->AddChild( node( wxT( "description" ), UnescapeString( description ) ) );
254
255 XNODE* xfields;
256 aNode->AddChild( xfields = node( wxT( "fields" ) ) );
257
258 for( const auto& [ fieldName, fieldValue ] : fields )
259 {
260 XNODE* xfield = node( wxT( "field" ), UnescapeString( fieldValue ) );
261 xfield->AddAttribute( wxT( "name" ), UnescapeString( fieldName ) );
262 xfields->AddChild( xfield );
263 }
264}
265
266
268{
269 XNODE* xcomps = node( wxT( "components" ) );
270
272 m_libParts.clear();
274
275 SCH_SHEET_PATH currentSheet = m_schematic->CurrentSheet();
276 SCH_SHEET_LIST sheetList = m_schematic->Hierarchy();
277
278 // Output is xml, so there is no reason to remove spaces from the field values.
279 // And XML element names need not be translated to various languages.
280
281 for( const SCH_SHEET_PATH& sheet : sheetList )
282 {
283 // Change schematic CurrentSheet in each iteration to allow hierarchical
284 // resolution of text variables in sheet fields.
285 m_schematic->SetCurrentSheet( sheet );
286
287 auto cmp =
288 [&sheet]( SCH_SYMBOL* a, SCH_SYMBOL* b )
289 {
290 return ( StrNumCmp( a->GetRef( &sheet, false ),
291 b->GetRef( &sheet, false ), true ) < 0 );
292 };
293
294 std::set<SCH_SYMBOL*, decltype( cmp )> ordered_symbols( cmp );
295 std::multiset<SCH_SYMBOL*, decltype( cmp )> extra_units( cmp );
296
297 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
298 {
299 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
300 auto test = ordered_symbols.insert( symbol );
301
302 if( !test.second )
303 {
304 if( ( *( test.first ) )->m_Uuid > symbol->m_Uuid )
305 {
306 extra_units.insert( *( test.first ) );
307 ordered_symbols.erase( test.first );
308 ordered_symbols.insert( symbol );
309 }
310 else
311 {
312 extra_units.insert( symbol );
313 }
314 }
315 }
316
317 for( EDA_ITEM* item : ordered_symbols )
318 {
319 SCH_SYMBOL* symbol = findNextSymbol( item, sheet );
320 bool forBOM = aCtl & GNL_OPT_BOM;
321 bool forBoard = aCtl & GNL_OPT_KICAD;
322
323 if( !symbol )
324 continue;
325
326 if( forBOM && ( sheet.GetExcludedFromBOM() || symbol->ResolveExcludedFromBOM() ) )
327 continue;
328
329 if( forBoard && ( sheet.GetExcludedFromBoard() || symbol->ResolveExcludedFromBoard() ) )
330 continue;
331
332 // Output the symbol's elements in order of expected access frequency. This may
333 // not always look best, but it will allow faster execution under XSL processing
334 // systems which do sequential searching within an element.
335
336 XNODE* xcomp; // current symbol being constructed
337 xcomps->AddChild( xcomp = node( wxT( "comp" ) ) );
338
339 xcomp->AddAttribute( wxT( "ref" ), symbol->GetRef( &sheet ) );
340 addSymbolFields( xcomp, symbol, sheet, sheetList );
341
342 XNODE* xlibsource;
343 xcomp->AddChild( xlibsource = node( wxT( "libsource" ) ) );
344
345 // "logical" library name, which is in anticipation of a better search algorithm
346 // for parts based on "logical_lib.part" and where logical_lib is merely the library
347 // name minus path and extension.
348 wxString libName;
349 wxString partName;
350
351 if( symbol->UseLibIdLookup() )
352 {
353 libName = symbol->GetLibId().GetUniStringLibNickname();
354 partName = symbol->GetLibId().GetUniStringLibItemName();
355 }
356 else
357 {
358 partName = symbol->GetSchSymbolLibraryName();
359 }
360
361 xlibsource->AddAttribute( wxT( "lib" ), libName );
362
363 // We only want the symbol name, not the full LIB_ID.
364 xlibsource->AddAttribute( wxT( "part" ), partName );
365
367 xlibsource->AddAttribute( wxT( "description" ), symbol->GetShownDescription() );
368 else
369 xlibsource->AddAttribute( wxT( "description" ), symbol->GetDescription() );
370
371 /* Add the symbol properties. */
372 XNODE* xproperty;
373
374 std::vector<SCH_FIELD>& fields = symbol->GetFields();
375
376 for( SCH_FIELD& field : fields )
377 {
378 if( field.IsMandatory() || field.IsPrivate() )
379 continue;
380
381 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
382 xproperty->AddAttribute( wxT( "name" ), field.GetCanonicalName() );
383
385 xproperty->AddAttribute( wxT( "value" ), field.GetShownText( &sheet, false ) );
386 else
387 xproperty->AddAttribute( wxT( "value" ), field.GetText() );
388 }
389
390 for( const SCH_FIELD& sheetField : sheet.Last()->GetFields() )
391 {
392 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
393 xproperty->AddAttribute( wxT( "name" ), sheetField.GetCanonicalName() );
394
396 // do not allow GetShownText() to add any prefix useful only when displaying
397 // the field on screen
398 xproperty->AddAttribute( wxT( "value" ), sheetField.GetShownText( &sheet, false ) );
399 else
400 xproperty->AddAttribute( wxT( "value" ), sheetField.GetText() );
401 }
402
403 const bool baseExcludedFromBOM = symbol->ResolveExcludedFromBOM( &sheet ) || sheet.GetExcludedFromBOM();
404
405 if( baseExcludedFromBOM )
406 {
407 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
408 xproperty->AddAttribute( wxT( "name" ), wxT( "exclude_from_bom" ) );
409 }
410
411 if( symbol->ResolveExcludedFromBoard( &sheet ) || sheet.GetExcludedFromBoard() )
412 {
413 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
414 xproperty->AddAttribute( wxT( "name" ), wxT( "exclude_from_board" ) );
415 }
416
417 const bool baseExcludedFromPosFiles = symbol->ResolveExcludedFromPosFiles( &sheet );
418
419 if( baseExcludedFromPosFiles )
420 {
421 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
422 xproperty->AddAttribute( wxT( "name" ), wxT( "exclude_from_pos_files" ) );
423 }
424
425 const bool baseDnp = symbol->ResolveDNP( &sheet ) || sheet.GetDNP();
426
427 if( baseDnp )
428 {
429 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
430 xproperty->AddAttribute( wxT( "name" ), wxT( "dnp" ) );
431 }
432
433 // Iterate all variants in the schematic, not just those in the symbol instance,
434 // because a sheet can have variant-specific attributes even if the symbol does not.
435 const std::set<wxString>& variantNames = m_schematic->GetVariantNames();
436
437 if( !variantNames.empty() )
438 {
439 const bool baseExcludedFromSim = symbol->ResolveExcludedFromSim( &sheet ) || sheet.GetExcludedFromSim();
440 XNODE* xvariants = nullptr;
441
442 for( const auto& variantName : variantNames )
443 {
444 XNODE* xvariant = nullptr;
445
446 auto addToVariant = [this, &xvariant, &variantName]( XNODE* child ) -> void
447 {
448 if( !child )
449 return;
450
451 if( !xvariant )
452 {
453 xvariant = node( wxT( "variant" ) );
454 xvariant->AddAttribute( wxT( "name" ), variantName );
455 }
456 xvariant->AddChild( child );
457 };
458
459 auto addBinaryProp = [this, &addToVariant]( wxString const& name, bool base,
460 bool effective ) -> void
461 {
462 if( base == effective )
463 return;
464
465 XNODE* xvarprop = node( wxT( "property" ) );
466 xvarprop->AddAttribute( wxT( "name" ), name );
467 xvarprop->AddAttribute( wxT( "value" ), effective ? wxT( "1" ) : wxT( "0" ) );
468 addToVariant( xvarprop );
469 };
470
471 bool effectiveDnp = symbol->ResolveDNP( &sheet, variantName ) || sheet.GetDNP( variantName );
472 addBinaryProp( wxT( "dnp" ), baseDnp, effectiveDnp );
473
474 bool effectiveExcludedFromBOM = symbol->ResolveExcludedFromBOM( &sheet, variantName )
475 || sheet.GetExcludedFromBOM( variantName );
476 addBinaryProp( wxT( "exclude_from_bom" ), baseExcludedFromBOM, effectiveExcludedFromBOM );
477
478 bool effectiveExcludedFromSim = symbol->ResolveExcludedFromSim( &sheet, variantName )
479 || sheet.GetExcludedFromSim( variantName );
480 addBinaryProp( wxT( "exclude_from_sim" ), baseExcludedFromSim, effectiveExcludedFromSim );
481
482 bool effectiveExcludedFromPosFiles = symbol->ResolveExcludedFromPosFiles( &sheet, variantName );
483 addBinaryProp( wxT( "exclude_from_pos_files" ), baseExcludedFromPosFiles,
484 effectiveExcludedFromPosFiles );
485
486 SCH_SYMBOL_INSTANCE instance;
487 const SCH_SYMBOL_VARIANT* variant = nullptr;
488
489 if( symbol->GetInstance( instance, sheet.Path() ) && instance.m_Variants.contains( variantName ) )
490 variant = &instance.m_Variants.at( variantName );
491
492 if( variant && variant->m_SymbolOverride )
493 {
494 XNODE* xprop = node( wxT( "property" ) );
495 xprop->AddAttribute( wxT( "name" ), wxT( "symbol_override" ) );
496 xprop->AddAttribute( wxT( "value" ), variant->m_SymbolOverride->Format() );
497 addToVariant( xprop );
498 }
499
500 if( variant && ( !variant->m_Fields.empty() || variant->m_SymbolOverride ) )
501 {
502 XNODE* xfields = nullptr;
503
504 for( const auto& [fieldName, fieldValue] : variant->m_Fields )
505 {
506 const wxString baseValue =
507 symbol->GetFieldText( fieldName, &sheet, wxEmptyString );
508
509 if( fieldValue == baseValue )
510 continue;
511
512 if( !xfields )
513 xfields = node( wxT( "fields" ) );
514
515 wxString resolvedValue = fieldValue;
516
518 resolvedValue = symbol->ResolveText( fieldValue, &sheet );
519
520 XNODE* xfield = node( wxT( "field" ), UnescapeString( resolvedValue ) );
521 xfield->AddAttribute( wxT( "name" ), UnescapeString( fieldName ) );
522 xfields->AddChild( xfield );
523 }
524
525 // Emit fields resolved from the alternate library symbol where the
526 // value differs from the base symbol. Explicit overrides in
527 // variant->m_Fields were already handled above.
528 if( variant->m_SymbolOverride )
529 {
530 for( const SCH_FIELD& baseField : symbol->GetFields() )
531 {
532 const wxString& fieldName = baseField.GetName();
533
534 if( variant->m_Fields.contains( fieldName ) )
535 continue;
536
537 const wxString baseValue =
538 symbol->GetFieldText( fieldName, &sheet, wxEmptyString );
539 const wxString variantValue =
540 symbol->GetFieldText( fieldName, &sheet, variantName );
541
542 if( variantValue == baseValue )
543 continue;
544
545 if( !xfields )
546 xfields = node( wxT( "fields" ) );
547
548 wxString resolvedValue = variantValue;
549
551 resolvedValue = symbol->ResolveText( variantValue, &sheet );
552
553 XNODE* xfield =
554 node( wxT( "field" ), UnescapeString( resolvedValue ) );
555 xfield->AddAttribute( wxT( "name" ),
556 UnescapeString( baseField.GetCanonicalName() ) );
557 xfields->AddChild( xfield );
558 }
559
560 // Emit fields that exist only on the alternate library symbol so the
561 // netlist reflects the full atomic part, not just the base field set.
562 if( LIB_SYMBOL* altSymbol = symbol->GetVariantLibSymbol( variantName, sheet ) )
563 {
564 std::vector<SCH_FIELD*> altFields;
565 altSymbol->GetFields( altFields );
566
567 for( const SCH_FIELD* altField : altFields )
568 {
569 const wxString& fieldName = altField->GetName();
570
571 if( symbol->GetField( fieldName )
572 || variant->m_Fields.contains( fieldName )
573 || altField->GetText().IsEmpty() )
574 {
575 continue;
576 }
577
578 if( !xfields )
579 xfields = node( wxT( "fields" ) );
580
581 wxString resolvedValue = altField->GetText();
582
584 resolvedValue = symbol->ResolveText( resolvedValue, &sheet );
585
586 XNODE* xfield =
587 node( wxT( "field" ), UnescapeString( resolvedValue ) );
588 xfield->AddAttribute( wxT( "name" ), UnescapeString( fieldName ) );
589 xfields->AddChild( xfield );
590 }
591 }
592 }
593
594 addToVariant( xfields );
595 }
596
597 if( xvariant )
598 {
599 if( !xvariants )
600 xvariants = node( wxT( "variants" ) );
601
602 xvariants->AddChild( xvariant );
603 }
604 }
605
606 if( xvariants )
607 xcomp->AddChild( xvariants );
608 }
609
610 if( const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef() )
611 {
612 if( part->GetKeyWords().size() )
613 {
614 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
615 xproperty->AddAttribute( wxT( "name" ), wxT( "ki_keywords" ) );
616 xproperty->AddAttribute( wxT( "value" ), part->GetKeyWords() );
617 }
618
619 if( !part->GetFPFilters().IsEmpty() )
620 {
621 wxString filters;
622
623 for( const wxString& filter : part->GetFPFilters() )
624 filters += ' ' + filter;
625
626 xcomp->AddChild( xproperty = node( wxT( "property" ) ) );
627 xproperty->AddAttribute( wxT( "name" ), wxT( "ki_fp_filters" ) );
628 xproperty->AddAttribute( wxT( "value" ), filters.Trim( false ) );
629 }
630
631 if( part->GetDuplicatePinNumbersAreJumpers() )
632 xcomp->AddChild( node( wxT( "duplicate_pin_numbers_are_jumpers" ), wxT( "1" ) ) );
633
634 const std::vector<std::set<wxString>>& jumperGroups = part->JumperPinGroups();
635
636 if( !jumperGroups.empty() )
637 {
638 XNODE* groupNode;
639 xcomp->AddChild( xproperty = node( wxT( "jumper_pin_groups" ) ) );
640
641 for( const std::set<wxString>& group : jumperGroups )
642 {
643 xproperty->AddChild( groupNode = node( wxT( "group" ) ) );
644
645 for( const wxString& pinName : group )
646 groupNode->AddChild( node( wxT( "pin" ), pinName ) );
647 }
648 }
649 }
650
651 XNODE* xsheetpath;
652 xcomp->AddChild( xsheetpath = node( wxT( "sheetpath" ) ) );
653
654 xsheetpath->AddAttribute( wxT( "names" ), sheet.PathHumanReadable() );
655 xsheetpath->AddAttribute( wxT( "tstamps" ), sheet.PathAsString() );
656
657 // Node for component class
658 std::vector<wxString> compClassNames =
659 getComponentClassNamesForAllSymbolUnits( symbol, sheet, sheetList );
660
661 if( compClassNames.size() > 0 )
662 {
663 XNODE* xcompclasslist;
664 xcomp->AddChild( xcompclasslist = node( wxT( "component_classes" ) ) );
665
666 for( const wxString& compClass : compClassNames )
667 {
668 xcompclasslist->AddChild( node( wxT( "class" ), UnescapeString( compClass ) ) );
669 }
670 }
671
672 XNODE* xunits; // Node for extra units
673 xcomp->AddChild( xunits = node( wxT( "tstamps" ) ) );
674
675 auto range = extra_units.equal_range( symbol );
676 wxString uuid;
677
678 // Output a series of children with all UUIDs associated with the REFDES
679 for( auto it = range.first; it != range.second; ++it )
680 {
681 uuid = ( *it )->m_Uuid.AsString();
682
683 // Add a space between UUIDs, if not in KICAD mode (i.e.
684 // using wxXmlDocument::Save()). KICAD MODE has its own XNODE::Format function.
685 if( !( aCtl & GNL_OPT_KICAD ) ) // i.e. for .xml format
686 uuid += ' ';
687
688 xunits->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
689 }
690
691 // Output the primary UUID
692 uuid = symbol->m_Uuid.AsString();
693 xunits->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
694
695 // Emit unit information (per-unit name and pins) after tstamps
696 XNODE* xunitInfo;
697 xcomp->AddChild( xunitInfo = node( wxT( "units" ) ) );
698
699 const std::unique_ptr<LIB_SYMBOL>& libSym = symbol->GetLibSymbolRef();
700
701 if( libSym )
702 {
703 // A multi-unit symbol can resolve to a different lib symbol per placed unit
704 // after unit-specific edits. For instane, if you have units A B C in a multi-unit
705 // symbol, and you edit only unit B, unit B will point to new, modified lib symbol
706 // but A and C will point to the original lib symbol.
707 //
708 // Export the unit metadata from the actual unit instances's lib symbols so the PCB
709 // footprint metadata matches during backannotation, which always works per unit.
710 //
711 // However, the user isn't required to place all units, so keep a fallback default unit info.
712 const std::vector<LIB_SYMBOL::UNIT_PIN_INFO>& defaultUnitInfo = libSym->GetUnitPinInfo();
713 std::map<int, SCH_SYMBOL*> symbolByUnit;
714
715 auto addUnitSymbol =
716 [&]( SCH_SYMBOL* aUnitSymbol )
717 {
718 if( !aUnitSymbol )
719 return;
720
721 int unit = aUnitSymbol->GetUnitSelection( &sheet );
722
723 if( unit > 0 )
724 symbolByUnit.try_emplace( unit, aUnitSymbol );
725 };
726
727 addUnitSymbol( symbol );
728
729 auto extraUnitRange = extra_units.equal_range( symbol );
730
731 // Collect the other placed units that share this reference so each unit number
732 // can be resolved back to the specific SCH_SYMBOL instance on the sheet.
733 for( auto it = extraUnitRange.first; it != extraUnitRange.second; ++it )
734 addUnitSymbol( *it );
735
736 // Emit every unit slot from the default library symbol, but override that slot's
737 // metadata with the placed unit's resolved library symbol when one exists.
738 for( size_t unitIdx = 0; unitIdx < defaultUnitInfo.size(); ++unitIdx )
739 {
740 LIB_SYMBOL::UNIT_PIN_INFO unitInfo = defaultUnitInfo[unitIdx];
741 auto symbolIt = symbolByUnit.find( unitIdx + 1 );
742
743 if( symbolIt != symbolByUnit.end() )
744 {
745 const std::unique_ptr<LIB_SYMBOL>& unitLibSym = symbolIt->second->GetLibSymbolRef();
746
747 if( unitLibSym )
748 {
749 const std::vector<LIB_SYMBOL::UNIT_PIN_INFO>& unitSpecificInfo =
750 unitLibSym->GetUnitPinInfo();
751
752 if( unitIdx < unitSpecificInfo.size() )
753 unitInfo = unitSpecificInfo[unitIdx];
754 }
755 }
756
757 XNODE* xunit;
758 xunitInfo->AddChild( xunit = node( wxT( "unit" ) ) );
759 xunit->AddAttribute( wxT( "name" ), unitInfo.m_unitName );
760
761 XNODE* xpins;
762 xunit->AddChild( xpins = node( wxT( "pins" ) ) );
763
764 for( const wxString& number : unitInfo.m_pinNumbers )
765 {
766 XNODE* xpin;
767 xpins->AddChild( xpin = node( wxT( "pin" ) ) );
768 xpin->AddAttribute( wxT( "num" ), number );
769 }
770 }
771 }
772 }
773 }
774
775 m_schematic->SetCurrentSheet( currentSheet );
776
777 return xcomps;
778}
779
780
782{
783 XNODE* xcomps = node( wxT( "groups" ) );
784
786 // Do not clear m_libParts here: it is populated in makeSymbols() and used later by
787 // makeLibParts() to emit the libparts section for CvPcb and other consumers.
788
789 SCH_SHEET_PATH currentSheet = m_schematic->CurrentSheet();
790 SCH_SHEET_LIST sheetList = m_schematic->Hierarchy();
791 std::map<SCH_SCREEN*, int> screenVisits;
792
793 for( const SCH_SHEET_PATH& sheet : sheetList )
794 screenVisits[sheet.LastScreen()]++;
795
796 for( const SCH_SHEET_PATH& sheet : sheetList )
797 {
798 // Change schematic CurrentSheet in each iteration to allow hierarchical
799 // resolution of text variables in sheet fields.
800 m_schematic->SetCurrentSheet( sheet );
801
802 wxString instancePrefix = sheet.PathAsString();
803
804 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_GROUP_T ) )
805 {
806 SCH_GROUP* group = static_cast<SCH_GROUP*>( item );
807 wxString groupName = group->GetName();
808
809 if( screenVisits[sheet.LastScreen()] > 1 )
810 groupName = wxString::Format( wxT( "%s (%s)" ), groupName, sheet.PathHumanReadable() );
811
812 XNODE* xgroup; // current symbol being constructed
813 xcomps->AddChild( xgroup = node( wxT( "group" ) ) );
814
815 xgroup->AddAttribute( wxT( "name" ), groupName );
816 xgroup->AddAttribute( wxT( "uuid" ), instancePrefix + group->m_Uuid.AsString() );
817 xgroup->AddAttribute( wxT( "lib_id" ), group->GetDesignBlockLibId().Format() );
818
819 XNODE* xmembers;
820 xgroup->AddChild( xmembers = node( wxT( "members" ) ) );
821
822 for( EDA_ITEM* member : group->GetItems() )
823 {
824 if( member->Type() == SCH_SYMBOL_T )
825 {
826 XNODE* xmember;
827 xmembers->AddChild( xmember = node( wxT( "member" ) ) );
828 xmember->AddAttribute( wxT( "uuid" ), instancePrefix + member->m_Uuid.AsString() );
829 }
830 else if( member->Type() == SCH_GROUP_T )
831 {
832 // Emit nested groups so the board side can rebuild the nesting.
833 XNODE* xmember;
834 xmembers->AddChild( xmember = node( wxT( "member" ) ) );
835 xmember->AddAttribute( wxT( "uuid" ), instancePrefix + member->m_Uuid.AsString() );
836 }
837 else if( member->Type() == SCH_SHEET_T )
838 {
839 SCH_SHEET_PATH subSheetPath = sheet;
840 std::vector<SCH_SHEET_PATH> descendantSheets;
841
842 subSheetPath.push_back( static_cast<SCH_SHEET*>( member ) );
843 sheetList.GetSheetsWithinPath( descendantSheets, subSheetPath );
844
845 for( const SCH_SHEET_PATH& descendantSheet : descendantSheets )
846 {
847 for( SCH_ITEM* descendantItem : descendantSheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
848 {
849 XNODE* xmember;
850 xmembers->AddChild( xmember = node( wxT( "member" ) ) );
851 xmember->AddAttribute( wxT( "uuid" ),
852 descendantSheet.PathAsString() + descendantItem->m_Uuid.AsString() );
853 }
854 }
855 }
856 }
857 }
858 }
859
860 m_schematic->SetCurrentSheet( currentSheet );
861
862 return xcomps;
863}
864
865
867{
868 XNODE* xvariants = node( wxT( "variants" ) );
869
870 std::set<wxString> variantNames = m_schematic->GetVariantNames();
871
872 for( const wxString& variantName : variantNames )
873 {
874 XNODE* xvariant;
875 xvariants->AddChild( xvariant = node( wxT( "variant" ) ) );
876 xvariant->AddAttribute( wxT( "name" ), variantName );
877
878 wxString description = m_schematic->GetVariantDescription( variantName );
879
880 if( !description.IsEmpty() )
881 xvariant->AddAttribute( wxT( "description" ), description );
882 }
883
884 return xvariants;
885}
886
887
889 SCH_SYMBOL* aSymbol, const SCH_SHEET_PATH& aSymbolSheet, const SCH_SHEET_LIST& aSheetList )
890{
891 std::vector<SCH_SHEET_PATH> symbolSheets;
892 symbolSheets.push_back( aSymbolSheet );
893
894 std::unordered_set<wxString> compClassNames = aSymbol->GetComponentClassNames( &aSymbolSheet );
895 int primaryUnit = aSymbol->GetUnitSelection( &aSymbolSheet );
896
897 if( aSymbol->GetUnitCount() > 1 )
898 {
899 const wxString ref = aSymbol->GetRef( &aSymbolSheet );
900
901 for( const SCH_SHEET_PATH& sheet : aSheetList )
902 {
903 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
904 {
905 const SCH_SYMBOL* symbol2 = static_cast<SCH_SYMBOL*>( item );
906
907 wxString ref2 = symbol2->GetRef( &sheet );
908 const int otherUnit = symbol2->GetUnitSelection( &sheet );
909
910 if( ref2.CmpNoCase( ref ) != 0 )
911 continue;
912
913 if( otherUnit == primaryUnit )
914 continue;
915
916 symbolSheets.push_back( sheet );
917
918 std::unordered_set<wxString> otherClassNames =
919 symbol2->GetComponentClassNames( &sheet );
920 compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
921 }
922 }
923 }
924
925 // Add sheet-level component classes
926 for( auto& [sheetPath, sheetCompClasses] : m_sheetComponentClasses )
927 {
928 for( SCH_SHEET_PATH& symbolSheetPath : symbolSheets )
929 {
930 if( symbolSheetPath.IsContainedWithin( sheetPath ) )
931 {
932 compClassNames.insert( sheetCompClasses.begin(), sheetCompClasses.end() );
933 }
934 }
935 }
936
937 std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
938 std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
939 []( const wxString& str1, const wxString& str2 )
940 {
941 return str1.Cmp( str2 ) < 0;
942 } );
943
944 return sortedCompClassNames;
945}
946
947
949{
950 SCH_SCREEN* screen;
951 XNODE* xdesign = node( wxT( "design" ) );
952 XNODE* xtitleBlock;
953 XNODE* xsheet;
954 XNODE* xcomment;
955 XNODE* xtextvar;
956 wxString sheetTxt;
957 wxFileName sourceFileName;
958
959 // the root sheet is a special sheet, call it source
960 xdesign->AddChild( node( wxT( "source" ), m_schematic->GetFileName() ) );
961
962 xdesign->AddChild( node( wxT( "date" ), GetISO8601CurrentDateTime() ) );
963
964 // which Eeschema tool
965 xdesign->AddChild( node( wxT( "tool" ), wxT( "Eeschema " ) + GetBuildVersion() ) );
966
967 const std::map<wxString, wxString>& properties = m_schematic->Project().GetTextVars();
968
969 for( const std::pair<const wxString, wxString>& prop : properties )
970 {
971 xdesign->AddChild( xtextvar = node( wxT( "textvar" ), prop.second ) );
972 xtextvar->AddAttribute( wxT( "name" ), prop.first );
973 }
974
975 /*
976 * Export the sheets information
977 */
978 unsigned sheetIndex = 1; // Human readable index
979
980 for( const SCH_SHEET_PATH& sheet : m_schematic->Hierarchy() )
981 {
982 screen = sheet.LastScreen();
983
984 xdesign->AddChild( xsheet = node( wxT( "sheet" ) ) );
985
986 // get the string representation of the sheet index number.
987 sheetTxt.Printf( wxT( "%u" ), sheetIndex++ );
988 xsheet->AddAttribute( wxT( "number" ), sheetTxt );
989 xsheet->AddAttribute( wxT( "name" ), sheet.PathHumanReadable() );
990 xsheet->AddAttribute( wxT( "tstamps" ), sheet.PathAsString() );
991
992 TITLE_BLOCK tb = screen->GetTitleBlock();
993 PROJECT* prj = &m_schematic->Project();
994
995 xsheet->AddChild( xtitleBlock = node( wxT( "title_block" ) ) );
996
997 xtitleBlock->AddChild( node( wxT( "title" ), ExpandTextVars( tb.GetTitle(), prj ) ) );
998 xtitleBlock->AddChild( node( wxT( "company" ), ExpandTextVars( tb.GetCompany(), prj ) ) );
999 xtitleBlock->AddChild( node( wxT( "rev" ), ExpandTextVars( tb.GetRevision(), prj ) ) );
1000 xtitleBlock->AddChild( node( wxT( "date" ), ExpandTextVars( tb.GetDate(), prj ) ) );
1001
1002 // We are going to remove the fileName directories.
1003 sourceFileName = wxFileName( screen->GetFileName() );
1004 xtitleBlock->AddChild( node( wxT( "source" ), sourceFileName.GetFullName() ) );
1005
1006 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1007 xcomment->AddAttribute( wxT( "number" ), wxT( "1" ) );
1008 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 0 ), prj ) );
1009
1010 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1011 xcomment->AddAttribute( wxT( "number" ), wxT( "2" ) );
1012 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 1 ), prj ) );
1013
1014 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1015 xcomment->AddAttribute( wxT( "number" ), wxT( "3" ) );
1016 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 2 ), prj ) );
1017
1018 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1019 xcomment->AddAttribute( wxT( "number" ), wxT( "4" ) );
1020 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 3 ), prj ) );
1021
1022 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1023 xcomment->AddAttribute( wxT( "number" ), wxT( "5" ) );
1024 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 4 ), prj ) );
1025
1026 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1027 xcomment->AddAttribute( wxT( "number" ), wxT( "6" ) );
1028 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 5 ), prj ) );
1029
1030 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1031 xcomment->AddAttribute( wxT( "number" ), wxT( "7" ) );
1032 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 6 ), prj ) );
1033
1034 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1035 xcomment->AddAttribute( wxT( "number" ), wxT( "8" ) );
1036 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 7 ), prj ) );
1037
1038 xtitleBlock->AddChild( xcomment = node( wxT( "comment" ) ) );
1039 xcomment->AddAttribute( wxT( "number" ), wxT( "9" ) );
1040 xcomment->AddAttribute( wxT( "value" ), ExpandTextVars( tb.GetComment( 8 ), prj ) );
1041 }
1042
1043 return xdesign;
1044}
1045
1046
1048{
1049 XNODE* xlibs = node( wxT( "libraries" ) ); // auto_ptr
1050 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1051
1052 for( std::set<wxString>::iterator it = m_libraries.begin(); it!=m_libraries.end(); ++it )
1053 {
1054 wxString libNickname = *it;
1055 XNODE* xlibrary;
1056
1057 std::optional<wxString> uri = manager.GetFullURI( LIBRARY_TABLE_TYPE::SYMBOL, libNickname );
1058
1059 if( uri )
1060 {
1061 xlibs->AddChild( xlibrary = node( wxT( "library" ) ) );
1062 xlibrary->AddAttribute( wxT( "logical" ), libNickname );
1063 xlibrary->AddChild( node( wxT( "uri" ), *uri ) );
1064 }
1065
1066 // @todo: add more fun stuff here
1067 }
1068
1069 return xlibs;
1070}
1071
1072
1074{
1075 XNODE* xlibparts = node( wxT( "libparts" ) ); // auto_ptr
1076 std::vector<SCH_FIELD*> fieldList;
1077
1078 m_libraries.clear();
1079
1080 for( LIB_SYMBOL* lcomp : m_libParts )
1081 {
1082 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
1083
1084 // The library nickname will be empty if the cache library is used.
1085 if( !libNickname.IsEmpty() )
1086 m_libraries.insert( libNickname ); // inserts symbol's library if unique
1087
1088 XNODE* xlibpart;
1089 xlibparts->AddChild( xlibpart = node( wxT( "libpart" ) ) );
1090 xlibpart->AddAttribute( wxT( "lib" ), libNickname );
1091 xlibpart->AddAttribute( wxT( "part" ), lcomp->GetName() );
1092
1093 //----- show the important properties -------------------------
1094 if( !lcomp->GetDescription().IsEmpty() )
1095 xlibpart->AddChild( node( wxT( "description" ), lcomp->GetDescription() ) );
1096
1097 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
1098 xlibpart->AddChild( node( wxT( "docs" ), lcomp->GetDatasheetField().GetText() ) );
1099
1100 // Write the footprint list
1101 if( lcomp->GetFPFilters().GetCount() )
1102 {
1103 XNODE* xfootprints;
1104 xlibpart->AddChild( xfootprints = node( wxT( "footprints" ) ) );
1105
1106 for( unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
1107 {
1108 if( !lcomp->GetFPFilters()[i].IsEmpty() )
1109 xfootprints->AddChild( node( wxT( "fp" ), lcomp->GetFPFilters()[i] ) );
1110 }
1111 }
1112
1113 //----- show the fields here ----------------------------------
1114 fieldList.clear();
1115 lcomp->GetFields( fieldList );
1116
1117 XNODE* xfields;
1118 xlibpart->AddChild( xfields = node( "fields" ) );
1119
1120 for( const SCH_FIELD* field : fieldList )
1121 {
1122 XNODE* xfield;
1123 xfields->AddChild( xfield = node( wxT( "field" ), field->GetText() ) );
1124 xfield->AddAttribute( wxT( "name" ), field->GetCanonicalName() );
1125 }
1126
1127 //----- show the pins here ------------------------------------
1128 // NOTE: Expand stacked-pin notation into individual pins so downstream
1129 // tools (e.g. CvPcb) see the actual number of footprint pins.
1130 std::vector<SCH_PIN*> pinList = lcomp->GetGraphicalPins( 0, 0 );
1131
1132 /*
1133 * We must erase redundant Pins references in pinList
1134 * These redundant pins exist because some pins are found more than one time when a
1135 * symbol has multiple parts per package or has 2 representations (DeMorgan conversion).
1136 * For instance, a 74ls00 has DeMorgan conversion, with different pin shapes, and
1137 * therefore each pin appears 2 times in the list. Common pins (VCC, GND) can also be
1138 * found more than once.
1139 */
1140 sort( pinList.begin(), pinList.end(), sortPinsByNumber );
1141
1142 for( int ii = 0; ii < (int)pinList.size()-1; ii++ )
1143 {
1144 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
1145 { // 2 pins have the same number, remove the redundant pin at index i+1
1146 pinList.erase(pinList.begin() + ii + 1);
1147 ii--;
1148 }
1149 }
1150
1151 wxLogTrace( "CVPCB_PINCOUNT",
1152 wxString::Format( "makeLibParts: lib='%s' part='%s' pinList(size)=%zu",
1153 libNickname, lcomp->GetName(), pinList.size() ) );
1154
1155 if( pinList.size() )
1156 {
1157 XNODE* pins;
1158
1159 xlibpart->AddChild( pins = node( wxT( "pins" ) ) );
1160
1161 for( unsigned i=0; i<pinList.size(); ++i )
1162 {
1163 SCH_PIN* basePin = pinList[i];
1164
1165 bool stackedValid = false;
1166 std::vector<wxString> expandedNums = basePin->GetStackedPinNumbers( &stackedValid );
1167
1168 // If stacked notation detected and valid, emit one libparts pin per expanded number.
1169 if( stackedValid && !expandedNums.empty() )
1170 {
1171 for( const wxString& num : expandedNums )
1172 {
1173 XNODE* pin;
1174 pins->AddChild( pin = node( wxT( "pin" ) ) );
1175 pin->AddAttribute( wxT( "num" ), num );
1176 pin->AddAttribute( wxT( "name" ), basePin->GetShownName() );
1177 pin->AddAttribute( wxT( "type" ), basePin->GetCanonicalElectricalTypeName() );
1178
1179 wxLogTrace( "CVPCB_PINCOUNT",
1180 wxString::Format( "makeLibParts: -> pin num='%s' name='%s' (expanded)",
1181 num, basePin->GetShownName() ) );
1182 }
1183 }
1184 else
1185 {
1186 XNODE* pin;
1187 pins->AddChild( pin = node( wxT( "pin" ) ) );
1188 pin->AddAttribute( wxT( "num" ), basePin->GetShownNumber() );
1189 pin->AddAttribute( wxT( "name" ), basePin->GetShownName() );
1190 pin->AddAttribute( wxT( "type" ), basePin->GetCanonicalElectricalTypeName() );
1191
1192 wxLogTrace( "CVPCB_PINCOUNT",
1193 wxString::Format( "makeLibParts: -> pin num='%s' name='%s'",
1194 basePin->GetShownNumber(),
1195 basePin->GetShownName() ) );
1196 }
1197
1198 // caution: construction work site here, drive slowly
1199 }
1200 }
1201 }
1202
1203 return xlibparts;
1204}
1205
1206
1208{
1209 wxString netCodeTxt;
1210 XNODE* xnets = node( wxT( "nets" ) ); // auto_ptr if exceptions ever get used.
1211 XNODE* xnet = nullptr;
1212
1213 /* output:
1214 <net code="123" name="/cfcard.sch/WAIT#" class="signal">
1215 <node ref="R23" pin="1"/>
1216 <node ref="U18" pin="12"/>
1217 </net>
1218 */
1219
1220 struct NET_NODE
1221 {
1222 NET_NODE( SCH_PIN* aPin, const SCH_SHEET_PATH& aSheet ) :
1223 m_Pin( aPin ),
1224 m_Sheet( aSheet )
1225 {}
1226
1227 SCH_PIN* m_Pin;
1228 SCH_SHEET_PATH m_Sheet;
1229 };
1230
1231 struct NET_RECORD
1232 {
1233 NET_RECORD( const wxString& aName ) :
1234 m_Name( aName ),
1235 m_HasNoConnect( false )
1236 {};
1237
1238 wxString m_Name;
1239 wxString m_Class;
1240 bool m_HasNoConnect;
1241 std::vector<NET_NODE> m_Nodes;
1242 };
1243
1244 std::vector<NET_RECORD*> nets;
1245
1246 std::shared_ptr<NET_SETTINGS> netSettings;
1247
1248 if( m_schematic )
1249 netSettings = m_schematic->Project().GetProjectFile().NetSettings();
1250
1251 for( const auto& [ key, subgraphs ] : m_schematic->ConnectionGraph()->GetNetMap() )
1252 {
1253 wxString net_name = key.Name;
1254 NET_RECORD* net_record = nullptr;
1255
1256 if( !( aCtl & GNL_OPT_KICAD ) )
1257 net_name = UnescapeString( net_name );
1258
1259 if( subgraphs.empty() )
1260 continue;
1261
1262 nets.emplace_back( new NET_RECORD( net_name ) );
1263 net_record = nets.back();
1264
1265 // Resolve the effective netclass by net name through NET_SETTINGS. This matches
1266 // the lookup used by the schematic painter and avoids relying on the subgraph's
1267 // driver item, which is not set for bus-member subgraphs and which falls back to
1268 // the schematic's current sheet path when looking up its connection (the exporter
1269 // is not tied to any particular sheet view).
1270 if( netSettings )
1271 {
1272 std::shared_ptr<NETCLASS> nc = netSettings->GetEffectiveNetClass( key.Name );
1273
1274 if( nc )
1275 net_record->m_Class = UnescapeString( nc->GetName() );
1276 }
1277
1278 for( CONNECTION_SUBGRAPH* subgraph : subgraphs )
1279 {
1280 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() == SCH_NO_CONNECT_T;
1281 const SCH_SHEET_PATH& sheet = subgraph->GetSheet();
1282
1283 if( nc )
1284 net_record->m_HasNoConnect = true;
1285
1286 for( SCH_ITEM* item : subgraph->GetItems() )
1287 {
1288 if( item->Type() == SCH_PIN_T )
1289 {
1290 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
1291 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( pin->GetParentSymbol() );
1292 bool forBOM = aCtl & GNL_OPT_BOM;
1293 bool forBoard = aCtl & GNL_OPT_KICAD;
1294
1295 if( !symbol )
1296 continue;
1297
1298 if( forBOM && ( sheet.GetExcludedFromBOM() || symbol->ResolveExcludedFromBOM() ) )
1299 continue;
1300
1301 if( forBoard && ( sheet.GetExcludedFromBoard() || symbol->ResolveExcludedFromBoard() ) )
1302 continue;
1303
1304 net_record->m_Nodes.emplace_back( pin, sheet );
1305 }
1306 }
1307 }
1308 }
1309
1310 // Netlist ordering: Net name, then ref des, then pin name
1311 std::sort( nets.begin(), nets.end(),
1312 []( const NET_RECORD* a, const NET_RECORD*b )
1313 {
1314 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
1315 } );
1316
1317 for( int i = 0; i < (int) nets.size(); ++i )
1318 {
1319 NET_RECORD* net_record = nets[i];
1320 bool added = false;
1321 XNODE* xnode;
1322
1323 // Netlist ordering: Net name, then ref des, then pin name
1324 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
1325 []( const NET_NODE& a, const NET_NODE& b )
1326 {
1327 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
1328 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
1329
1330 if( refA == refB )
1331 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
1332
1333 return refA < refB;
1334 } );
1335
1336 // Some duplicates can exist, for example on multi-unit parts with duplicated pins across
1337 // units. If the user connects the pins on each unit, they will appear on separate
1338 // subgraphs. Remove those here:
1339 alg::remove_duplicates( net_record->m_Nodes,
1340 []( const NET_NODE& a, const NET_NODE& b )
1341 {
1342 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
1343 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
1344
1345 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
1346 } );
1347
1348 // Determine if all pins in the net are stacked (nets with only one pin are implicitly
1349 // taken to be stacked)
1350 bool allNetPinsStacked = true;
1351
1352 if( net_record->m_Nodes.size() > 1 )
1353 {
1354 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
1355 allNetPinsStacked =
1356 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
1357 [=]( auto& node )
1358 {
1359 return firstPin->GetParent() == node.m_Pin->GetParent()
1360 && firstPin->GetPosition() == node.m_Pin->GetPosition()
1361 && firstPin->GetName() == node.m_Pin->GetName();
1362 } );
1363 }
1364
1365 for( const NET_NODE& netNode : net_record->m_Nodes )
1366 {
1367 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
1368
1369 // Skip power symbols and virtual symbols
1370 if( refText[0] == wxChar( '#' ) )
1371 continue;
1372
1373 // Emit the resolved footprint pad number(s), not the raw symbol pin number, so a
1374 // remapped pin's net lands on the right pad when the board reads this netlist
1375 // (issue #2282). Shared with the PIN_INFO path via resolvePadNumbers.
1376 std::vector<wxString> nums = resolvePadNumbers( netNode.m_Pin, netNode.m_Sheet );
1377
1378 // An unmapped pin contributes no pad, so skip it and do not open an empty net for it.
1379 if( nums.empty() )
1380 continue;
1381
1382 wxString baseName = netNode.m_Pin->GetShownName();
1383 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
1384
1385 if( !added )
1386 {
1387 netCodeTxt.Printf( wxT( "%d" ), i + 1 );
1388
1389 xnets->AddChild( xnet = node( wxT( "net" ) ) );
1390 xnet->AddAttribute( wxT( "code" ), netCodeTxt );
1391 xnet->AddAttribute( wxT( "name" ), net_record->m_Name );
1392 xnet->AddAttribute( wxT( "class" ), net_record->m_Class );
1393
1394 added = true;
1395 }
1396
1397 for( const wxString& num : nums )
1398 {
1399 xnet->AddChild( xnode = node( wxT( "node" ) ) );
1400 xnode->AddAttribute( wxT( "ref" ), refText );
1401 xnode->AddAttribute( wxT( "pin" ), num );
1402
1403 wxString fullName = baseName.IsEmpty() ? num : baseName + wxT( "_" ) + num;
1404
1405 if( !baseName.IsEmpty() || nums.size() > 1 )
1406 xnode->AddAttribute( wxT( "pinfunction" ), fullName );
1407
1408 wxString typeAttr = pinType;
1409
1410 if( net_record->m_HasNoConnect
1411 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
1412 {
1413 typeAttr += wxT( "+no_connect" );
1414 }
1415
1416 xnode->AddAttribute( wxT( "pintype" ), typeAttr );
1417 }
1418 }
1419 }
1420
1421 for( NET_RECORD* record : nets )
1422 delete record;
1423
1424 return xnets;
1425}
1426
1428{
1429 const auto& committed = m_schematic->ConnectionGraph()->GetCommittedNetChains();
1430
1431 if( committed.empty() )
1432 return nullptr;
1433
1434 XNODE* xchains = node( wxT( "net_chains" ) );
1435
1436 for( const std::unique_ptr<SCH_NETCHAIN>& chain : committed )
1437 {
1438 if( !chain )
1439 continue;
1440
1441 XNODE* xchain;
1442 xchains->AddChild( xchain = node( wxT( "net_chain" ) ) );
1443 xchain->AddAttribute( wxT( "name" ), chain->GetName() );
1444
1445 if( !chain->GetNetClass().IsEmpty() )
1446 xchain->AddAttribute( wxT( "net_class" ), chain->GetNetClass() );
1447
1448 // Carry the chain's class assignment (from project's NET_SETTINGS) so
1449 // that downstream consumers of the netlist can see chain hierarchy
1450 // without having to also parse the .kicad_pro file.
1451 if( m_schematic )
1452 {
1453 PROJECT_FILE& pf = m_schematic->Project().GetProjectFile();
1454 const std::shared_ptr<NET_SETTINGS>& ns = pf.NetSettings();
1455
1456 if( ns )
1457 {
1458 wxString className = ns->GetNetChainClass( chain->GetName() );
1459
1460 if( !className.IsEmpty() )
1461 xchain->AddAttribute( wxT( "net_chain_class" ), className );
1462 }
1463 }
1464
1465 if( chain->GetColor() != COLOR4D::UNSPECIFIED )
1466 {
1467 const COLOR4D& c = chain->GetColor();
1468 xchain->AddAttribute( wxT( "color" ),
1469 wxString::Format( wxT( "#%02X%02X%02X%02X" ),
1470 (int) std::clamp( KiROUND( c.r * 255.0 ), 0, 255 ),
1471 (int) std::clamp( KiROUND( c.g * 255.0 ), 0, 255 ),
1472 (int) std::clamp( KiROUND( c.b * 255.0 ), 0, 255 ),
1473 (int) std::clamp( KiROUND( c.a * 255.0 ), 0, 255 ) ) );
1474 }
1475
1476 XNODE* xmembers;
1477 xchain->AddChild( xmembers = node( wxT( "members" ) ) );
1478
1479 // Synthetic per-run subgraph names (__SG_*) embed run-specific subgraph codes
1480 // that do not survive a reload, and downstream consumers cannot resolve them
1481 // back to a real net. Mirror the sexpr writer's filter so the XML output is
1482 // limited to nets that have stable, user-visible names.
1483 for( const wxString& net : chain->GetNets() )
1484 {
1485 if( net.IsEmpty() || net.StartsWith( SCH_NETCHAIN::SYNTHETIC_NET_PREFIX ) )
1486 continue;
1487
1488 XNODE* xmember;
1489 xmembers->AddChild( xmember = node( wxT( "member" ) ) );
1490 xmember->AddAttribute( wxT( "net" ), net );
1491 }
1492
1493 if( !chain->GetTerminalRef( 0 ).IsEmpty() || !chain->GetTerminalRef( 1 ).IsEmpty() )
1494 {
1495 XNODE* xterms;
1496 xchain->AddChild( xterms = node( wxT( "terminal_pins" ) ) );
1497
1498 for( int i = 0; i < 2; ++i )
1499 {
1500 if( chain->GetTerminalRef( i ).IsEmpty() )
1501 continue;
1502
1503 XNODE* xterm;
1504 xterms->AddChild( xterm = node( wxT( "terminal_pin" ) ) );
1505 xterm->AddAttribute( wxT( "ref" ), chain->GetTerminalRef( i ) );
1506 xterm->AddAttribute( wxT( "pin" ), chain->GetTerminalPinNum( i ) );
1507 }
1508 }
1509 }
1510
1511 return xchains;
1512}
1513
1514
1515XNODE* NETLIST_EXPORTER_XML::node( const wxString& aName,
1516 const wxString& aTextualContent /* = wxEmptyString*/ )
1517{
1518 XNODE* n = new XNODE( wxXML_ELEMENT_NODE, aName );
1519
1520 if( aTextualContent.Len() > 0 ) // excludes wxEmptyString, the parameter's default value
1521 n->AddChild( new XNODE( wxXML_TEXT_NODE, wxEmptyString, aTextualContent ) );
1522
1523 return n;
1524}
1525
1526
1527static bool sortPinsByNumber( SCH_PIN* aPin1, SCH_PIN* aPin2 )
1528{
1529 // return "lhs < rhs"
1530 return StrNumCmp( aPin1->GetShownNumber(), aPin2->GetShownNumber(), true ) < 0;
1531}
1533{
1535
1536 SCH_SHEET_LIST sheetList = m_schematic->Hierarchy();
1537
1538 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields, const SCH_SHEET_PATH* sheetPath )
1539 {
1540 std::unordered_set<wxString> componentClasses;
1541
1542 for( const SCH_FIELD& field : fields )
1543 {
1544 if( field.GetCanonicalName() == wxT( "Component Class" ) )
1545 {
1546 if( field.GetShownText( sheetPath, false ) != wxEmptyString )
1547 componentClasses.insert( field.GetShownText( sheetPath, false ) );
1548 }
1549 }
1550
1551 return componentClasses;
1552 };
1553
1554 for( const SCH_SHEET_PATH& sheet : sheetList )
1555 {
1556 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SHEET_T ) )
1557 {
1558 SCH_SHEET* sheetItem = static_cast<SCH_SHEET*>( item );
1559 std::unordered_set<wxString> sheetComponentClasses;
1560 const std::unordered_set<SCH_RULE_AREA*>& sheetRuleAreas = sheetItem->GetRuleAreaCache();
1561
1562 for( const SCH_RULE_AREA* ruleArea : sheetRuleAreas )
1563 {
1564 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
1565 {
1566 std::unordered_set<wxString> ruleAreaComponentClasses =
1567 getComponentClassFields( label->GetFields(), &sheet );
1568 sheetComponentClasses.insert( ruleAreaComponentClasses.begin(), ruleAreaComponentClasses.end() );
1569 }
1570 }
1571
1572 SCH_SHEET_PATH newPath = sheet;
1573 newPath.push_back( sheetItem );
1574 wxASSERT( !m_sheetComponentClasses.contains( newPath ) );
1575
1576 m_sheetComponentClasses[newPath] = sheetComponentClasses;
1577 }
1578 }
1579}
const char * name
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
wxString GetBuildVersion()
Get the full KiCad version string.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:398
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:96
const KIID m_Uuid
Definition eda_item.h:531
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:389
double g
Green component.
Definition color4d.h:390
double a
Alpha component.
Definition color4d.h:392
double b
Blue component.
Definition color4d.h:391
wxString AsString() const
Definition kiid.cpp:264
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const wxString GetUniStringLibNickname() const
Definition lib_id.h:84
Define a library symbol object.
Definition lib_symbol.h:114
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
std::vector< wxString > resolvePadNumbers(const SCH_PIN *aPin, const SCH_SHEET_PATH &aSheetPath) const
Resolve aPin to its effective pad number(s) for every netlist path (issue #2282).
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
std::map< SCH_SHEET_PATH, std::unordered_set< wxString > > m_sheetComponentClasses
Map of all sheets to component classes covering the whole sheet.
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.
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:126
The backing store for a PROJECT, in JSON format.
std::shared_ptr< NET_SETTINGS > & NetSettings()
Container for project specific data.
Definition project.h:63
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:72
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:48
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
bool ResolveExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:346
const std::unordered_set< SCH_RULE_AREA * > & GetRuleAreaCache() const
Get the cache of rule areas enclosing this item.
Definition sch_item.h:681
bool ResolveExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:314
wxString ResolveText(const wxString &aText, const SCH_SHEET_PATH *aPath, int aDepth=0) const
Definition sch_item.cpp:377
bool ResolveExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:330
bool ResolveDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:362
bool ResolveExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.cpp:298
static constexpr char SYNTHETIC_NET_PREFIX[]
Prefix used when synthesising net names for unnamed subgraphs.
std::vector< wxString > GetStackedPinNumbers(bool *aValid=nullptr) const
Definition sch_pin.cpp:693
wxString GetCanonicalElectricalTypeName() const
Definition sch_pin.cpp:439
const wxString & GetShownName() const
Definition sch_pin.cpp:676
const wxString & GetShownNumber() const
Definition sch_pin.cpp:687
const wxString & GetFileName() const
Definition sch_screen.h:150
TITLE_BLOCK & GetTitleBlock()
Definition sch_screen.h:161
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void GetSheetsWithinPath(std::vector< SCH_SHEET_PATH > &aSheets, const SCH_SHEET_PATH &aSheetPath) const
Add a SCH_SHEET_PATH object to aSheets for each sheet in the list that are contained within aSheetPat...
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
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
Variant information for a schematic symbol.
std::optional< LIB_ID > m_SymbolOverride
Alternate library symbol to substitute for the base symbol in this variant, if any.
Schematic symbol object.
Definition sch_symbol.h:69
wxString GetDescription() const override
bool UseLibIdLookup() const
Definition sch_symbol.h:175
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) const
wxString GetSchSymbolLibraryName() const
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) 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 wxString &aVariantName=wxEmptyString) const
wxString GetShownDescription(int aDepth=0) const override
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:158
LIB_SYMBOL * GetVariantLibSymbol(const wxString &aVariantName, const SCH_SHEET_PATH &aPath) const
Resolve the alternate library symbol for a given variant.
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
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:177
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:37
const wxString & GetCompany() const
Definition title_block.h:92
const wxString & GetRevision() const
Definition title_block.h:82
const wxString & GetDate() const
Definition title_block.h:72
const wxString & GetComment(int aIdx) const
const wxString & GetTitle() const
Definition title_block.h:59
std::map< wxString, wxString > m_Fields
An extension of wxXmlNode that can format its contents as KiCad-style s-expressions.
Definition xnode.h:67
void AddAttribute(const wxString &aName, const wxString &aValue) override
Definition xnode.cpp:88
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:157
static bool sortPinsByNumber(SCH_PIN *aPin1, SCH_PIN *aPin2)
#define GNL_ALL
@ GNL_LIBRARIES
@ GNL_OPT_KICAD
@ GNL_SYMBOLS
@ GNL_OPT_BOM
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
Class to handle a set of SCH_ITEMs.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString UnescapeString(const wxString &aSource)
wxString GetISO8601CurrentDateTime()
std::vector< wxString > m_pinNumbers
Definition lib_symbol.h:699
One refdes -> net membership row collected from the NETDEF section.
A simple container for schematic symbol instance information.
std::map< wxString, SCH_SYMBOL_VARIANT > m_Variants
A list of symbol variants.
@ 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)
KIBIS_PIN * pin
const SHAPE_LINE_CHAIN chain
wxLogTrace helper definitions.
@ SCH_GROUP_T
Definition typeinfo.h:170
@ SCH_NO_CONNECT_T
Definition typeinfo.h:157
@ SCH_SYMBOL_T
Definition typeinfo.h:169
@ SCH_SHEET_T
Definition typeinfo.h:172
@ SCH_PIN_T
Definition typeinfo.h:150