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() )
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() )
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 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
352 xproperty->AddAttribute( wxT(
"name" ), fields[jj].GetCanonicalName() );
355 xproperty->AddAttribute( wxT(
"value" ), fields[jj].GetShownText( &sheet,
false ) );
357 xproperty->AddAttribute( wxT(
"value" ), fields[jj].GetText() );
360 for(
const SCH_FIELD& sheetField : sheet.Last()->GetFields() )
362 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
363 xproperty->AddAttribute( wxT(
"name" ), sheetField.GetCanonicalName() );
368 xproperty->AddAttribute( wxT(
"value" ), sheetField.GetShownText( &sheet,
false ) );
370 xproperty->AddAttribute( wxT(
"value" ), sheetField.GetText() );
375 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
376 xproperty->AddAttribute( wxT(
"name" ), wxT(
"exclude_from_bom" ) );
381 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
382 xproperty->AddAttribute( wxT(
"name" ), wxT(
"exclude_from_board" ) );
385 if( symbol->
GetDNP() || sheet.GetDNP() )
387 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
388 xproperty->AddAttribute( wxT(
"name" ), wxT(
"dnp" ) );
391 if(
const std::unique_ptr<LIB_SYMBOL>& part = symbol->
GetLibSymbolRef() )
393 if( part->GetKeyWords().size() )
395 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
396 xproperty->AddAttribute( wxT(
"name" ), wxT(
"ki_keywords" ) );
397 xproperty->AddAttribute( wxT(
"value" ), part->GetKeyWords() );
400 if( !part->GetFPFilters().IsEmpty() )
404 for(
const wxString&
filter : part->GetFPFilters() )
407 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
408 xproperty->AddAttribute( wxT(
"name" ), wxT(
"ki_fp_filters" ) );
409 xproperty->AddAttribute( wxT(
"value" ), filters.Trim(
false ) );
414 xcomp->AddChild( xsheetpath =
node( wxT(
"sheetpath" ) ) );
416 xsheetpath->AddAttribute( wxT(
"names" ), sheet.PathHumanReadable() );
417 xsheetpath->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
420 std::vector<wxString> compClassNames =
423 if( compClassNames.size() > 0 )
425 XNODE* xcompclasslist;
426 xcomp->AddChild( xcompclasslist =
node( wxT(
"component_classes" ) ) );
428 for(
const wxString& compClass : compClassNames )
435 xcomp->AddChild( xunits =
node( wxT(
"tstamps" ) ) );
437 auto range = extra_units.equal_range( symbol );
441 for(
auto it = range.first; it != range.second; ++it )
443 uuid = ( *it )->m_Uuid.AsString();
450 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
455 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
473 wxString ref = aSymbol->
GetRef( &aSymbolSheet );
481 wxString ref2 = symbol2->
GetRef( &sheet );
484 if( ref2.CmpNoCase( ref ) != 0 )
487 if( otherUnit == primaryUnit )
490 std::unordered_set<wxString> otherClassNames =
492 compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
497 std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
498 std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
499 [](
const wxString& str1,
const wxString& str2 )
501 return str1.Cmp( str2 ) < 0;
504 return sortedCompClassNames;
511 XNODE* xdesign =
node( wxT(
"design" ) );
517 wxFileName sourceFileName;
529 for(
const std::pair<const wxString, wxString>& prop : properties )
531 xdesign->AddChild( xtextvar =
node( wxT(
"textvar" ), prop.second ) );
532 xtextvar->AddAttribute( wxT(
"name" ), prop.first );
538 unsigned sheetIndex = 1;
542 screen = sheet.LastScreen();
544 xdesign->AddChild( xsheet =
node( wxT(
"sheet" ) ) );
547 sheetTxt.Printf( wxT(
"%u" ), sheetIndex++ );
548 xsheet->AddAttribute( wxT(
"number" ), sheetTxt );
549 xsheet->AddAttribute( wxT(
"name" ), sheet.PathHumanReadable() );
550 xsheet->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
555 xsheet->AddChild( xtitleBlock =
node( wxT(
"title_block" ) ) );
563 sourceFileName = wxFileName( screen->
GetFileName() );
564 xtitleBlock->AddChild(
node( wxT(
"source" ), sourceFileName.GetFullName() ) );
566 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
567 xcomment->AddAttribute( wxT(
"number" ), wxT(
"1" ) );
570 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
571 xcomment->AddAttribute( wxT(
"number" ), wxT(
"2" ) );
574 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
575 xcomment->AddAttribute( wxT(
"number" ), wxT(
"3" ) );
578 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
579 xcomment->AddAttribute( wxT(
"number" ), wxT(
"4" ) );
582 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
583 xcomment->AddAttribute( wxT(
"number" ), wxT(
"5" ) );
586 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
587 xcomment->AddAttribute( wxT(
"number" ), wxT(
"6" ) );
590 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
591 xcomment->AddAttribute( wxT(
"number" ), wxT(
"7" ) );
594 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
595 xcomment->AddAttribute( wxT(
"number" ), wxT(
"8" ) );
598 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
599 xcomment->AddAttribute( wxT(
"number" ), wxT(
"9" ) );
609 XNODE* xlibs =
node( wxT(
"libraries" ) );
614 wxString libNickname = *it;
617 if( symbolLibTable->
HasLibrary( libNickname ) )
619 xlibs->AddChild( xlibrary =
node( wxT(
"library" ) ) );
620 xlibrary->AddAttribute( wxT(
"logical" ), libNickname );
621 xlibrary->AddChild(
node( wxT(
"uri" ), symbolLibTable->
GetFullURI( libNickname ) ) );
633 XNODE* xlibparts =
node( wxT(
"libparts" ) );
634 std::vector<SCH_FIELD*> fieldList;
640 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
643 if( !libNickname.IsEmpty() )
647 xlibparts->AddChild( xlibpart =
node( wxT(
"libpart" ) ) );
648 xlibpart->AddAttribute( wxT(
"lib" ), libNickname );
649 xlibpart->AddAttribute( wxT(
"part" ), lcomp->GetName() );
652 if( !lcomp->GetDescription().IsEmpty() )
653 xlibpart->AddChild(
node( wxT(
"description" ), lcomp->GetDescription() ) );
655 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
656 xlibpart->AddChild(
node( wxT(
"docs" ), lcomp->GetDatasheetField().GetText() ) );
659 if( lcomp->GetFPFilters().GetCount() )
662 xlibpart->AddChild( xfootprints =
node( wxT(
"footprints" ) ) );
664 for(
unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
665 xfootprints->AddChild(
node( wxT(
"fp" ), lcomp->GetFPFilters()[i] ) );
670 lcomp->GetFields( fieldList );
673 xlibpart->AddChild( xfields =
node(
"fields" ) );
675 for(
const SCH_FIELD* field : fieldList )
678 xfields->AddChild( xfield =
node( wxT(
"field" ), field->GetText() ) );
679 xfield->AddAttribute( wxT(
"name" ), field->GetCanonicalName() );
683 std::vector<SCH_PIN*> pinList = lcomp->GetPins( 0, 0 );
695 for(
int ii = 0; ii < (int)pinList.size()-1; ii++ )
697 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
699 pinList.erase(pinList.begin() + ii + 1);
708 xlibpart->AddChild( pins =
node( wxT(
"pins" ) ) );
710 for(
unsigned i=0; i<pinList.size(); ++i )
714 pins->AddChild(
pin =
node( wxT(
"pin" ) ) );
715 pin->AddAttribute( wxT(
"num" ), pinList[i]->GetShownNumber() );
716 pin->AddAttribute( wxT(
"name" ), pinList[i]->GetShownName() );
717 pin->AddAttribute( wxT(
"type" ), pinList[i]->GetCanonicalElectricalTypeName() );
735 XNODE* xnet =
nullptr;
757 NET_RECORD(
const wxString& aName ) :
759 m_HasNoConnect(
false )
765 std::vector<NET_NODE> m_Nodes;
768 std::vector<NET_RECORD*> nets;
772 wxString net_name = key.Name;
773 NET_RECORD* net_record =
nullptr;
778 if( subgraphs.empty() )
781 nets.emplace_back(
new NET_RECORD( net_name ) );
782 net_record = nets.back();
786 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() ==
SCH_NO_CONNECT_T;
789 if( net_record->m_Class.IsEmpty() && subgraph->GetDriver() )
791 if( subgraph->GetDriver()->GetEffectiveNetClass() )
793 net_record->m_Class = subgraph->GetDriver()->GetEffectiveNetClass()->GetName();
799 net_record->m_HasNoConnect =
true;
801 for(
SCH_ITEM* item : subgraph->GetItems() )
819 net_record->m_Nodes.emplace_back(
pin, sheet );
826 std::sort( nets.begin(), nets.end(),
827 [](
const NET_RECORD* a,
const NET_RECORD*b )
829 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
832 for(
int i = 0; i < (int) nets.size(); ++i )
834 NET_RECORD* net_record = nets[i];
839 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
840 [](
const NET_NODE& a,
const NET_NODE& b )
842 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
843 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
846 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
855 [](
const NET_NODE& a,
const NET_NODE& b )
857 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
858 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
860 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
865 bool allNetPinsStacked =
true;
867 if( net_record->m_Nodes.size() > 1 )
869 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
871 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
874 return firstPin->GetParent() == node.m_Pin->GetParent()
875 && firstPin->GetPosition() == node.m_Pin->GetPosition()
876 && firstPin->GetName() == node.m_Pin->GetName();
880 for(
const NET_NODE& netNode : net_record->m_Nodes )
882 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
883 wxString pinText = netNode.m_Pin->GetShownNumber();
886 if( refText[0] == wxChar(
'#' ) )
891 netCodeTxt.Printf( wxT(
"%d" ), i + 1 );
893 xnets->AddChild( xnet =
node( wxT(
"net" ) ) );
894 xnet->AddAttribute( wxT(
"code" ), netCodeTxt );
895 xnet->AddAttribute( wxT(
"name" ), net_record->m_Name );
896 xnet->AddAttribute( wxT(
"class" ), net_record->m_Class );
901 xnet->AddChild( xnode =
node( wxT(
"node" ) ) );
902 xnode->AddAttribute( wxT(
"ref" ), refText );
903 xnode->AddAttribute( wxT(
"pin" ), pinText );
905 wxString pinName = netNode.m_Pin->GetShownName();
906 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
908 if( !pinName.IsEmpty() )
909 xnode->AddAttribute( wxT(
"pinfunction" ), pinName );
911 if( net_record->m_HasNoConnect
912 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
913 pinType += wxT(
"+no_connect" );
915 xnode->AddAttribute( wxT(
"pintype" ), pinType );
919 for( NET_RECORD* record : nets )
927 const wxString& aTextualContent )
929 XNODE* n =
new XNODE( wxXML_ELEMENT_NODE, aName );
931 if( aTextualContent.Len() > 0 )
932 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.
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.
SCHEMATIC_IFACE * m_schematic
The schematic we're generating a netlist for.
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.
virtual void SetCurrentSheet(const SCH_SHEET_PATH &aPath)=0
virtual wxString GetFileName() const =0
virtual CONNECTION_GRAPH * ConnectionGraph() const =0
virtual SCH_SHEET_PATH & CurrentSheet() const =0
virtual PROJECT & Prj() const =0
virtual SCH_SHEET_LIST Hierarchy() const =0
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
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
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) override
Populate a std::vector with SCH_FIELDs.
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const override
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
Returns the component classes this symbol belongs in.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
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(int idx)
@ DATASHEET_FIELD
name of datasheet
@ FOOTPRINT_FIELD
Field Name Module PCB, i.e. "16DIP300".
@ MANDATORY_FIELDS
The first 5 are mandatory, and must be instantiated in SCH_COMPONENT, LIB_PART, and FOOTPRINT constru...
@ DESCRIPTION_FIELD
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".