35#include <wx/wfstream.h>
37#include <nlohmann/json.hpp>
53 wxFFileOutputStream stream( aOutFileName );
61 return xdoc.Save( stream, 2 );
69 xroot->AddAttribute( wxT(
"version" ), wxT(
"E" ) );
102 wxString description;
104 nlohmann::ordered_map<wxString, wxString> fields;
115 wxString ref = aSymbol->
GetRef( &aSheet );
125 wxString ref2 = symbol2->
GetRef( &sheet );
127 if( ref2.CmpNoCase( ref ) != 0 )
137 if( !candidate.IsEmpty() && ( unit < minUnit || value.IsEmpty() ) )
143 if( !candidate.IsEmpty() && ( unit < minUnit || footprint.IsEmpty() ) )
144 footprint = candidate;
151 if( !candidate.IsEmpty() && ( unit < minUnit ||
datasheet.IsEmpty() ) )
159 if( !candidate.IsEmpty() && ( unit < minUnit || description.IsEmpty() ) )
160 description = candidate;
165 if( field.IsMandatory() || field.IsPrivate() )
168 if( unit < minUnit || fields.count( field.GetName() ) == 0 )
171 fields[field.GetName()] = field.GetShownText( &aSheet,
false );
173 fields[field.GetName()] = field.GetText();
177 minUnit = std::min( unit, minUnit );
197 description = descriptionField->
GetShownText( &aSheet,
false );
199 description = descriptionField->
GetText();
203 if( field.IsMandatory() || field.IsPrivate() )
207 fields[field.GetName()] = field.GetShownText( &aSheet,
false );
209 fields[field.GetName()] = field.GetText();
221 aNode->AddChild(
node( wxT(
"value" ), wxT(
"~" ) ) );
223 if( footprint.size() )
229 if( description.size() )
233 aNode->AddChild( xfields =
node( wxT(
"fields" ) ) );
235 for(
const auto& [ fieldName, fieldValue ] : fields )
238 xfield->AddAttribute( wxT(
"name" ),
UnescapeString( fieldName ) );
239 xfields->AddChild( xfield );
246 XNODE* xcomps =
node( wxT(
"components" ) );
267 b->GetRef( &sheet,
false ),
true ) < 0 );
270 std::set<
SCH_SYMBOL*,
decltype( cmp )> ordered_symbols( cmp );
271 std::multiset<
SCH_SYMBOL*,
decltype( cmp )> extra_units( cmp );
276 auto test = ordered_symbols.insert( symbol );
280 if( ( *(
test.first ) )->m_Uuid > symbol->
m_Uuid )
282 extra_units.insert( *(
test.first ) );
283 ordered_symbols.erase(
test.first );
284 ordered_symbols.insert( symbol );
288 extra_units.insert( symbol );
293 for(
EDA_ITEM* item : ordered_symbols )
313 xcomps->AddChild( xcomp =
node( wxT(
"comp" ) ) );
315 xcomp->AddAttribute( wxT(
"ref" ), symbol->
GetRef( &sheet ) );
319 xcomp->AddChild( xlibsource =
node( wxT(
"libsource" ) ) );
337 xlibsource->AddAttribute( wxT(
"lib" ), libName );
340 xlibsource->AddAttribute( wxT(
"part" ), partName );
342 xlibsource->AddAttribute( wxT(
"description" ), symbol->
GetDescription() );
347 std::vector<SCH_FIELD>& fields = symbol->
GetFields();
351 if( field.IsMandatory() || field.IsPrivate() )
354 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
355 xproperty->AddAttribute( wxT(
"name" ), field.GetCanonicalName() );
358 xproperty->AddAttribute( wxT(
"value" ), field.GetShownText( &sheet,
false ) );
360 xproperty->AddAttribute( wxT(
"value" ), field.GetText() );
363 for(
const SCH_FIELD& sheetField : sheet.Last()->GetFields() )
365 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
366 xproperty->AddAttribute( wxT(
"name" ), sheetField.GetCanonicalName() );
371 xproperty->AddAttribute( wxT(
"value" ), sheetField.GetShownText( &sheet,
false ) );
373 xproperty->AddAttribute( wxT(
"value" ), sheetField.GetText() );
378 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
379 xproperty->AddAttribute( wxT(
"name" ), wxT(
"exclude_from_bom" ) );
384 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
385 xproperty->AddAttribute( wxT(
"name" ), wxT(
"exclude_from_board" ) );
388 if( symbol->
GetDNP() || sheet.GetDNP() )
390 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
391 xproperty->AddAttribute( wxT(
"name" ), wxT(
"dnp" ) );
394 if(
const std::unique_ptr<LIB_SYMBOL>& part = symbol->
GetLibSymbolRef() )
396 if( part->GetKeyWords().size() )
398 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
399 xproperty->AddAttribute( wxT(
"name" ), wxT(
"ki_keywords" ) );
400 xproperty->AddAttribute( wxT(
"value" ), part->GetKeyWords() );
403 if( !part->GetFPFilters().IsEmpty() )
407 for(
const wxString&
filter : part->GetFPFilters() )
410 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
411 xproperty->AddAttribute( wxT(
"name" ), wxT(
"ki_fp_filters" ) );
412 xproperty->AddAttribute( wxT(
"value" ), filters.Trim(
false ) );
415 if( part->GetDuplicatePinNumbersAreJumpers() )
416 xcomp->AddChild(
node( wxT(
"duplicate_pin_numbers_are_jumpers" ), wxT(
"1" ) ) );
418 const std::vector<std::set<wxString>>& jumperGroups = part->JumperPinGroups();
420 if( !jumperGroups.empty() )
423 xcomp->AddChild( xproperty =
node( wxT(
"jumper_pin_groups" ) ) );
425 for(
const std::set<wxString>&
group : jumperGroups )
427 xproperty->AddChild( groupNode =
node( wxT(
"group" ) ) );
429 for(
const wxString& padName :
group )
430 groupNode->AddAttribute( wxT(
"pin" ), padName );
436 xcomp->AddChild( xsheetpath =
node( wxT(
"sheetpath" ) ) );
438 xsheetpath->AddAttribute( wxT(
"names" ), sheet.PathHumanReadable() );
439 xsheetpath->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
442 std::vector<wxString> compClassNames =
445 if( compClassNames.size() > 0 )
447 XNODE* xcompclasslist;
448 xcomp->AddChild( xcompclasslist =
node( wxT(
"component_classes" ) ) );
450 for(
const wxString& compClass : compClassNames )
457 xcomp->AddChild( xunits =
node( wxT(
"tstamps" ) ) );
459 auto range = extra_units.equal_range( symbol );
463 for(
auto it = range.first; it != range.second; ++it )
465 uuid = ( *it )->m_Uuid.AsString();
472 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
477 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
495 wxString ref = aSymbol->
GetRef( &aSymbolSheet );
503 wxString ref2 = symbol2->
GetRef( &sheet );
506 if( ref2.CmpNoCase( ref ) != 0 )
509 if( otherUnit == primaryUnit )
512 std::unordered_set<wxString> otherClassNames =
514 compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
519 std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
520 std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
521 [](
const wxString& str1,
const wxString& str2 )
523 return str1.Cmp( str2 ) < 0;
526 return sortedCompClassNames;
533 XNODE* xdesign =
node( wxT(
"design" ) );
539 wxFileName sourceFileName;
551 for(
const std::pair<const wxString, wxString>& prop : properties )
553 xdesign->AddChild( xtextvar =
node( wxT(
"textvar" ), prop.second ) );
554 xtextvar->AddAttribute( wxT(
"name" ), prop.first );
560 unsigned sheetIndex = 1;
564 screen = sheet.LastScreen();
566 xdesign->AddChild( xsheet =
node( wxT(
"sheet" ) ) );
569 sheetTxt.Printf( wxT(
"%u" ), sheetIndex++ );
570 xsheet->AddAttribute( wxT(
"number" ), sheetTxt );
571 xsheet->AddAttribute( wxT(
"name" ), sheet.PathHumanReadable() );
572 xsheet->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
577 xsheet->AddChild( xtitleBlock =
node( wxT(
"title_block" ) ) );
585 sourceFileName = wxFileName( screen->
GetFileName() );
586 xtitleBlock->AddChild(
node( wxT(
"source" ), sourceFileName.GetFullName() ) );
588 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
589 xcomment->AddAttribute( wxT(
"number" ), wxT(
"1" ) );
592 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
593 xcomment->AddAttribute( wxT(
"number" ), wxT(
"2" ) );
596 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
597 xcomment->AddAttribute( wxT(
"number" ), wxT(
"3" ) );
600 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
601 xcomment->AddAttribute( wxT(
"number" ), wxT(
"4" ) );
604 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
605 xcomment->AddAttribute( wxT(
"number" ), wxT(
"5" ) );
608 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
609 xcomment->AddAttribute( wxT(
"number" ), wxT(
"6" ) );
612 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
613 xcomment->AddAttribute( wxT(
"number" ), wxT(
"7" ) );
616 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
617 xcomment->AddAttribute( wxT(
"number" ), wxT(
"8" ) );
620 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
621 xcomment->AddAttribute( wxT(
"number" ), wxT(
"9" ) );
631 XNODE* xlibs =
node( wxT(
"libraries" ) );
636 wxString libNickname = *it;
639 if( symbolLibTable->
HasLibrary( libNickname ) )
641 xlibs->AddChild( xlibrary =
node( wxT(
"library" ) ) );
642 xlibrary->AddAttribute( wxT(
"logical" ), libNickname );
643 xlibrary->AddChild(
node( wxT(
"uri" ), symbolLibTable->
GetFullURI( libNickname ) ) );
655 XNODE* xlibparts =
node( wxT(
"libparts" ) );
656 std::vector<SCH_FIELD*> fieldList;
662 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
665 if( !libNickname.IsEmpty() )
669 xlibparts->AddChild( xlibpart =
node( wxT(
"libpart" ) ) );
670 xlibpart->AddAttribute( wxT(
"lib" ), libNickname );
671 xlibpart->AddAttribute( wxT(
"part" ), lcomp->GetName() );
674 if( !lcomp->GetDescription().IsEmpty() )
675 xlibpart->AddChild(
node( wxT(
"description" ), lcomp->GetDescription() ) );
677 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
678 xlibpart->AddChild(
node( wxT(
"docs" ), lcomp->GetDatasheetField().GetText() ) );
681 if( lcomp->GetFPFilters().GetCount() )
684 xlibpart->AddChild( xfootprints =
node( wxT(
"footprints" ) ) );
686 for(
unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
688 if( !lcomp->GetFPFilters()[i].IsEmpty() )
689 xfootprints->AddChild(
node( wxT(
"fp" ), lcomp->GetFPFilters()[i] ) );
695 lcomp->GetFields( fieldList );
698 xlibpart->AddChild( xfields =
node(
"fields" ) );
700 for(
const SCH_FIELD* field : fieldList )
703 xfields->AddChild( xfield =
node( wxT(
"field" ), field->GetText() ) );
704 xfield->AddAttribute( wxT(
"name" ), field->GetCanonicalName() );
708 std::vector<SCH_PIN*> pinList = lcomp->GetPins( 0, 0 );
720 for(
int ii = 0; ii < (int)pinList.size()-1; ii++ )
722 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
724 pinList.erase(pinList.begin() + ii + 1);
733 xlibpart->AddChild( pins =
node( wxT(
"pins" ) ) );
735 for(
unsigned i=0; i<pinList.size(); ++i )
739 pins->AddChild(
pin =
node( wxT(
"pin" ) ) );
740 pin->AddAttribute( wxT(
"num" ), pinList[i]->GetShownNumber() );
741 pin->AddAttribute( wxT(
"name" ), pinList[i]->GetShownName() );
742 pin->AddAttribute( wxT(
"type" ), pinList[i]->GetCanonicalElectricalTypeName() );
760 XNODE* xnet =
nullptr;
782 NET_RECORD(
const wxString& aName ) :
784 m_HasNoConnect(
false )
790 std::vector<NET_NODE> m_Nodes;
793 std::vector<NET_RECORD*> nets;
797 wxString net_name = key.Name;
798 NET_RECORD* net_record =
nullptr;
803 if( subgraphs.empty() )
806 nets.emplace_back(
new NET_RECORD( net_name ) );
807 net_record = nets.back();
811 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() ==
SCH_NO_CONNECT_T;
814 if( net_record->m_Class.IsEmpty() && subgraph->GetDriver() )
816 if( subgraph->GetDriver()->GetEffectiveNetClass() )
818 net_record->m_Class = subgraph->GetDriver()->GetEffectiveNetClass()->GetName();
824 net_record->m_HasNoConnect =
true;
826 for(
SCH_ITEM* item : subgraph->GetItems() )
844 net_record->m_Nodes.emplace_back(
pin, sheet );
851 std::sort( nets.begin(), nets.end(),
852 [](
const NET_RECORD* a,
const NET_RECORD*b )
854 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
857 for(
int i = 0; i < (int) nets.size(); ++i )
859 NET_RECORD* net_record = nets[i];
864 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
865 [](
const NET_NODE& a,
const NET_NODE& b )
867 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
868 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
871 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
880 [](
const NET_NODE& a,
const NET_NODE& b )
882 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
883 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
885 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
890 bool allNetPinsStacked =
true;
892 if( net_record->m_Nodes.size() > 1 )
894 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
896 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
899 return firstPin->GetParent() == node.m_Pin->GetParent()
900 && firstPin->GetPosition() == node.m_Pin->GetPosition()
901 && firstPin->GetName() == node.m_Pin->GetName();
905 for(
const NET_NODE& netNode : net_record->m_Nodes )
907 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
908 wxString pinText = netNode.m_Pin->GetShownNumber();
911 if( refText[0] == wxChar(
'#' ) )
916 netCodeTxt.Printf( wxT(
"%d" ), i + 1 );
918 xnets->AddChild( xnet =
node( wxT(
"net" ) ) );
919 xnet->AddAttribute( wxT(
"code" ), netCodeTxt );
920 xnet->AddAttribute( wxT(
"name" ), net_record->m_Name );
921 xnet->AddAttribute( wxT(
"class" ), net_record->m_Class );
926 xnet->AddChild( xnode =
node( wxT(
"node" ) ) );
927 xnode->AddAttribute( wxT(
"ref" ), refText );
928 xnode->AddAttribute( wxT(
"pin" ), pinText );
930 wxString pinName = netNode.m_Pin->GetShownName();
931 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
933 if( !pinName.IsEmpty() )
934 xnode->AddAttribute( wxT(
"pinfunction" ), pinName );
936 if( net_record->m_HasNoConnect
937 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
938 pinType += wxT(
"+no_connect" );
940 xnode->AddAttribute( wxT(
"pintype" ), pinType );
944 for( NET_RECORD* record : nets )
952 const wxString& aTextualContent )
954 XNODE* n =
new XNODE( wxXML_ELEMENT_NODE, aName );
956 if( aTextualContent.Len() > 0 )
957 n->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, aTextualContent ) );
wxString GetBuildVersion()
Get the full KiCad version string.
const NET_MAP & GetNetMap() const
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.
virtual const wxString & GetText() const
Return the string associated with the text object.
wxString AsString() const
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
const wxString GetUniStringLibNickname() const
Define a library symbol object.
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.
virtual std::map< wxString, wxString > & GetTextVars() const
A pure virtual class used to derive REPORTER objects from.
PROJECT & Prj() const
Return a reference to the project this schematic is part of.
void SetCurrentSheet(const SCH_SHEET_PATH &aPath)
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
CONNECTION_GRAPH * ConnectionGraph() const
SCH_SHEET_PATH & CurrentSheet() const
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Base class for any item which can be embedded within the SCHEMATIC container class,...
wxString GetShownNumber() const
const wxString & GetFileName() const
const TITLE_BLOCK & GetTitleBlock() const
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
wxString GetDescription() const override
bool UseLibIdLookup() const
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
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()
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.
bool GetExcludedFromBoard() const
bool GetExcludedFromBOM() const
bool GetDNP() const
Set or clear the 'Do Not Populate' flag.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
const wxString & GetCompany() const
const wxString & GetRevision() const
const wxString & GetDate() const
const wxString & GetComment(int aIdx) const
const wxString & GetTitle() const
void Clear()
Erase the record.
Hold an XML or S-expression element.
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
static bool sortPinsByNumber(SCH_PIN *aPin1, SCH_PIN *aPin2)
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.
wxString GetCanonicalFieldName(FIELD_T aFieldType)