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 ) );
417 xcomp->AddChild( xsheetpath =
node( wxT(
"sheetpath" ) ) );
419 xsheetpath->AddAttribute( wxT(
"names" ), sheet.PathHumanReadable() );
420 xsheetpath->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
423 std::vector<wxString> compClassNames =
426 if( compClassNames.size() > 0 )
428 XNODE* xcompclasslist;
429 xcomp->AddChild( xcompclasslist =
node( wxT(
"component_classes" ) ) );
431 for(
const wxString& compClass : compClassNames )
438 xcomp->AddChild( xunits =
node( wxT(
"tstamps" ) ) );
440 auto range = extra_units.equal_range( symbol );
444 for(
auto it = range.first; it != range.second; ++it )
446 uuid = ( *it )->m_Uuid.AsString();
453 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
458 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
476 wxString ref = aSymbol->
GetRef( &aSymbolSheet );
484 wxString ref2 = symbol2->
GetRef( &sheet );
487 if( ref2.CmpNoCase( ref ) != 0 )
490 if( otherUnit == primaryUnit )
493 std::unordered_set<wxString> otherClassNames =
495 compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
500 std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
501 std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
502 [](
const wxString& str1,
const wxString& str2 )
504 return str1.Cmp( str2 ) < 0;
507 return sortedCompClassNames;
514 XNODE* xdesign =
node( wxT(
"design" ) );
520 wxFileName sourceFileName;
532 for(
const std::pair<const wxString, wxString>& prop : properties )
534 xdesign->AddChild( xtextvar =
node( wxT(
"textvar" ), prop.second ) );
535 xtextvar->AddAttribute( wxT(
"name" ), prop.first );
541 unsigned sheetIndex = 1;
545 screen = sheet.LastScreen();
547 xdesign->AddChild( xsheet =
node( wxT(
"sheet" ) ) );
550 sheetTxt.Printf( wxT(
"%u" ), sheetIndex++ );
551 xsheet->AddAttribute( wxT(
"number" ), sheetTxt );
552 xsheet->AddAttribute( wxT(
"name" ), sheet.PathHumanReadable() );
553 xsheet->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
558 xsheet->AddChild( xtitleBlock =
node( wxT(
"title_block" ) ) );
566 sourceFileName = wxFileName( screen->
GetFileName() );
567 xtitleBlock->AddChild(
node( wxT(
"source" ), sourceFileName.GetFullName() ) );
569 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
570 xcomment->AddAttribute( wxT(
"number" ), wxT(
"1" ) );
573 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
574 xcomment->AddAttribute( wxT(
"number" ), wxT(
"2" ) );
577 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
578 xcomment->AddAttribute( wxT(
"number" ), wxT(
"3" ) );
581 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
582 xcomment->AddAttribute( wxT(
"number" ), wxT(
"4" ) );
585 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
586 xcomment->AddAttribute( wxT(
"number" ), wxT(
"5" ) );
589 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
590 xcomment->AddAttribute( wxT(
"number" ), wxT(
"6" ) );
593 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
594 xcomment->AddAttribute( wxT(
"number" ), wxT(
"7" ) );
597 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
598 xcomment->AddAttribute( wxT(
"number" ), wxT(
"8" ) );
601 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
602 xcomment->AddAttribute( wxT(
"number" ), wxT(
"9" ) );
612 XNODE* xlibs =
node( wxT(
"libraries" ) );
617 wxString libNickname = *it;
620 if( symbolLibTable->
HasLibrary( libNickname ) )
622 xlibs->AddChild( xlibrary =
node( wxT(
"library" ) ) );
623 xlibrary->AddAttribute( wxT(
"logical" ), libNickname );
624 xlibrary->AddChild(
node( wxT(
"uri" ), symbolLibTable->
GetFullURI( libNickname ) ) );
636 XNODE* xlibparts =
node( wxT(
"libparts" ) );
637 std::vector<SCH_FIELD*> fieldList;
643 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
646 if( !libNickname.IsEmpty() )
650 xlibparts->AddChild( xlibpart =
node( wxT(
"libpart" ) ) );
651 xlibpart->AddAttribute( wxT(
"lib" ), libNickname );
652 xlibpart->AddAttribute( wxT(
"part" ), lcomp->GetName() );
655 if( !lcomp->GetDescription().IsEmpty() )
656 xlibpart->AddChild(
node( wxT(
"description" ), lcomp->GetDescription() ) );
658 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
659 xlibpart->AddChild(
node( wxT(
"docs" ), lcomp->GetDatasheetField().GetText() ) );
662 if( lcomp->GetFPFilters().GetCount() )
665 xlibpart->AddChild( xfootprints =
node( wxT(
"footprints" ) ) );
667 for(
unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
668 xfootprints->AddChild(
node( wxT(
"fp" ), lcomp->GetFPFilters()[i] ) );
673 lcomp->GetFields( fieldList );
676 xlibpart->AddChild( xfields =
node(
"fields" ) );
678 for(
const SCH_FIELD* field : fieldList )
681 xfields->AddChild( xfield =
node( wxT(
"field" ), field->GetText() ) );
682 xfield->AddAttribute( wxT(
"name" ), field->GetCanonicalName() );
686 std::vector<SCH_PIN*> pinList = lcomp->GetPins( 0, 0 );
698 for(
int ii = 0; ii < (int)pinList.size()-1; ii++ )
700 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
702 pinList.erase(pinList.begin() + ii + 1);
711 xlibpart->AddChild( pins =
node( wxT(
"pins" ) ) );
713 for(
unsigned i=0; i<pinList.size(); ++i )
717 pins->AddChild(
pin =
node( wxT(
"pin" ) ) );
718 pin->AddAttribute( wxT(
"num" ), pinList[i]->GetShownNumber() );
719 pin->AddAttribute( wxT(
"name" ), pinList[i]->GetShownName() );
720 pin->AddAttribute( wxT(
"type" ), pinList[i]->GetCanonicalElectricalTypeName() );
738 XNODE* xnet =
nullptr;
760 NET_RECORD(
const wxString& aName ) :
762 m_HasNoConnect(
false )
768 std::vector<NET_NODE> m_Nodes;
771 std::vector<NET_RECORD*> nets;
775 wxString net_name = key.Name;
776 NET_RECORD* net_record =
nullptr;
781 if( subgraphs.empty() )
784 nets.emplace_back(
new NET_RECORD( net_name ) );
785 net_record = nets.back();
789 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() ==
SCH_NO_CONNECT_T;
792 if( net_record->m_Class.IsEmpty() && subgraph->GetDriver() )
794 if( subgraph->GetDriver()->GetEffectiveNetClass() )
796 net_record->m_Class = subgraph->GetDriver()->GetEffectiveNetClass()->GetName();
802 net_record->m_HasNoConnect =
true;
804 for(
SCH_ITEM* item : subgraph->GetItems() )
822 net_record->m_Nodes.emplace_back(
pin, sheet );
829 std::sort( nets.begin(), nets.end(),
830 [](
const NET_RECORD* a,
const NET_RECORD*b )
832 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
835 for(
int i = 0; i < (int) nets.size(); ++i )
837 NET_RECORD* net_record = nets[i];
842 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
843 [](
const NET_NODE& a,
const NET_NODE& b )
845 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
846 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
849 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
858 [](
const NET_NODE& a,
const NET_NODE& b )
860 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
861 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
863 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
868 bool allNetPinsStacked =
true;
870 if( net_record->m_Nodes.size() > 1 )
872 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
874 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
877 return firstPin->GetParent() == node.m_Pin->GetParent()
878 && firstPin->GetPosition() == node.m_Pin->GetPosition()
879 && firstPin->GetName() == node.m_Pin->GetName();
883 for(
const NET_NODE& netNode : net_record->m_Nodes )
885 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
886 wxString pinText = netNode.m_Pin->GetShownNumber();
889 if( refText[0] == wxChar(
'#' ) )
894 netCodeTxt.Printf( wxT(
"%d" ), i + 1 );
896 xnets->AddChild( xnet =
node( wxT(
"net" ) ) );
897 xnet->AddAttribute( wxT(
"code" ), netCodeTxt );
898 xnet->AddAttribute( wxT(
"name" ), net_record->m_Name );
899 xnet->AddAttribute( wxT(
"class" ), net_record->m_Class );
904 xnet->AddChild( xnode =
node( wxT(
"node" ) ) );
905 xnode->AddAttribute( wxT(
"ref" ), refText );
906 xnode->AddAttribute( wxT(
"pin" ), pinText );
908 wxString pinName = netNode.m_Pin->GetShownName();
909 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
911 if( !pinName.IsEmpty() )
912 xnode->AddAttribute( wxT(
"pinfunction" ), pinName );
914 if( net_record->m_HasNoConnect
915 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
916 pinType += wxT(
"+no_connect" );
918 xnode->AddAttribute( wxT(
"pintype" ), pinType );
922 for( NET_RECORD* record : nets )
930 const wxString& aTextualContent )
932 XNODE* n =
new XNODE( wxXML_ELEMENT_NODE, aName );
934 if( aTextualContent.Len() > 0 )
935 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".
@ DESCRIPTION_FIELD
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".