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;
167 if( unit < minUnit || fields.count( f.
GetName() ) == 0 )
176 minUnit = std::min( unit, minUnit );
196 description = descriptionField->
GetShownText( &aSheet,
false );
198 description = descriptionField->
GetText();
219 aNode->AddChild(
node( wxT(
"value" ), wxT(
"~" ) ) );
221 if( footprint.size() )
227 if( description.size() )
231 aNode->AddChild( xfields =
node( wxT(
"fields" ) ) );
233 for(
const auto& [ fieldName, fieldValue ] : fields )
236 xfield->AddAttribute( wxT(
"name" ),
UnescapeString( fieldName ) );
237 xfields->AddChild( xfield );
244 XNODE* xcomps =
node( wxT(
"components" ) );
265 b->GetRef( &sheet,
false ),
true ) < 0 );
268 std::set<
SCH_SYMBOL*,
decltype( cmp )> ordered_symbols( cmp );
269 std::multiset<
SCH_SYMBOL*,
decltype( cmp )> extra_units( cmp );
274 auto test = ordered_symbols.insert( symbol );
278 if( ( *(
test.first ) )->m_Uuid > symbol->
m_Uuid )
280 extra_units.insert( *(
test.first ) );
281 ordered_symbols.erase(
test.first );
282 ordered_symbols.insert( symbol );
286 extra_units.insert( symbol );
291 for(
EDA_ITEM* item : ordered_symbols )
311 xcomps->AddChild( xcomp =
node( wxT(
"comp" ) ) );
313 xcomp->AddAttribute( wxT(
"ref" ), symbol->
GetRef( &sheet ) );
317 xcomp->AddChild( xlibsource =
node( wxT(
"libsource" ) ) );
335 xlibsource->AddAttribute( wxT(
"lib" ), libName );
338 xlibsource->AddAttribute( wxT(
"part" ), partName );
340 xlibsource->AddAttribute( wxT(
"description" ), symbol->
GetDescription() );
345 std::vector<SCH_FIELD>& fields = symbol->
GetFields();
349 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
350 xproperty->AddAttribute( wxT(
"name" ), fields[jj].GetCanonicalName() );
353 xproperty->AddAttribute( wxT(
"value" ), fields[jj].GetShownText( &sheet,
false ) );
355 xproperty->AddAttribute( wxT(
"value" ), fields[jj].GetText() );
358 for(
const SCH_FIELD& sheetField : sheet.Last()->GetFields() )
360 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
361 xproperty->AddAttribute( wxT(
"name" ), sheetField.GetCanonicalName() );
366 xproperty->AddAttribute( wxT(
"value" ), sheetField.GetShownText( &sheet,
false ) );
368 xproperty->AddAttribute( wxT(
"value" ), sheetField.GetText() );
373 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
374 xproperty->AddAttribute( wxT(
"name" ), wxT(
"exclude_from_bom" ) );
379 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
380 xproperty->AddAttribute( wxT(
"name" ), wxT(
"exclude_from_board" ) );
385 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
386 xproperty->AddAttribute( wxT(
"name" ), wxT(
"dnp" ) );
389 if(
const std::unique_ptr<LIB_SYMBOL>& part = symbol->
GetLibSymbolRef() )
391 if( part->GetKeyWords().size() )
393 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
394 xproperty->AddAttribute( wxT(
"name" ), wxT(
"ki_keywords" ) );
395 xproperty->AddAttribute( wxT(
"value" ), part->GetKeyWords() );
398 if( !part->GetFPFilters().IsEmpty() )
402 for(
const wxString&
filter : part->GetFPFilters() )
405 xcomp->AddChild( xproperty =
node( wxT(
"property" ) ) );
406 xproperty->AddAttribute( wxT(
"name" ), wxT(
"ki_fp_filters" ) );
407 xproperty->AddAttribute( wxT(
"value" ), filters.Trim(
false ) );
412 xcomp->AddChild( xsheetpath =
node( wxT(
"sheetpath" ) ) );
414 xsheetpath->AddAttribute( wxT(
"names" ), sheet.PathHumanReadable() );
415 xsheetpath->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
418 std::vector<wxString> compClassNames =
421 if( compClassNames.size() > 0 )
423 XNODE* xcompclasslist;
424 xcomp->AddChild( xcompclasslist =
node( wxT(
"component_classes" ) ) );
426 for(
const wxString& compClass : compClassNames )
433 xcomp->AddChild( xunits =
node( wxT(
"tstamps" ) ) );
435 auto range = extra_units.equal_range( symbol );
439 for(
auto it = range.first; it != range.second; ++it )
441 uuid = ( *it )->m_Uuid.AsString();
448 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
453 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
471 wxString ref = aSymbol->
GetRef( &aSymbolSheet );
479 wxString ref2 = symbol2->
GetRef( &sheet );
482 if( ref2.CmpNoCase( ref ) != 0 )
485 if( otherUnit == primaryUnit )
488 std::unordered_set<wxString> otherClassNames =
490 compClassNames.insert( otherClassNames.begin(), otherClassNames.end() );
495 std::vector<wxString> sortedCompClassNames( compClassNames.begin(), compClassNames.end() );
496 std::sort( sortedCompClassNames.begin(), sortedCompClassNames.end(),
497 [](
const wxString& str1,
const wxString& str2 )
499 return str1.Cmp( str2 ) < 0;
502 return sortedCompClassNames;
509 XNODE* xdesign =
node( wxT(
"design" ) );
515 wxFileName sourceFileName;
527 for(
const std::pair<const wxString, wxString>& prop : properties )
529 xdesign->AddChild( xtextvar =
node( wxT(
"textvar" ), prop.second ) );
530 xtextvar->AddAttribute( wxT(
"name" ), prop.first );
536 unsigned sheetIndex = 1;
540 screen = sheet.LastScreen();
542 xdesign->AddChild( xsheet =
node( wxT(
"sheet" ) ) );
545 sheetTxt.Printf( wxT(
"%u" ), sheetIndex++ );
546 xsheet->AddAttribute( wxT(
"number" ), sheetTxt );
547 xsheet->AddAttribute( wxT(
"name" ), sheet.PathHumanReadable() );
548 xsheet->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
553 xsheet->AddChild( xtitleBlock =
node( wxT(
"title_block" ) ) );
561 sourceFileName = wxFileName( screen->
GetFileName() );
562 xtitleBlock->AddChild(
node( wxT(
"source" ), sourceFileName.GetFullName() ) );
564 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
565 xcomment->AddAttribute( wxT(
"number" ), wxT(
"1" ) );
568 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
569 xcomment->AddAttribute( wxT(
"number" ), wxT(
"2" ) );
572 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
573 xcomment->AddAttribute( wxT(
"number" ), wxT(
"3" ) );
576 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
577 xcomment->AddAttribute( wxT(
"number" ), wxT(
"4" ) );
580 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
581 xcomment->AddAttribute( wxT(
"number" ), wxT(
"5" ) );
584 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
585 xcomment->AddAttribute( wxT(
"number" ), wxT(
"6" ) );
588 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
589 xcomment->AddAttribute( wxT(
"number" ), wxT(
"7" ) );
592 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
593 xcomment->AddAttribute( wxT(
"number" ), wxT(
"8" ) );
596 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
597 xcomment->AddAttribute( wxT(
"number" ), wxT(
"9" ) );
607 XNODE* xlibs =
node( wxT(
"libraries" ) );
612 wxString libNickname = *it;
615 if( symbolLibTable->
HasLibrary( libNickname ) )
617 xlibs->AddChild( xlibrary =
node( wxT(
"library" ) ) );
618 xlibrary->AddAttribute( wxT(
"logical" ), libNickname );
619 xlibrary->AddChild(
node( wxT(
"uri" ), symbolLibTable->
GetFullURI( libNickname ) ) );
631 XNODE* xlibparts =
node( wxT(
"libparts" ) );
632 std::vector<SCH_FIELD*> fieldList;
638 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
641 if( !libNickname.IsEmpty() )
645 xlibparts->AddChild( xlibpart =
node( wxT(
"libpart" ) ) );
646 xlibpart->AddAttribute( wxT(
"lib" ), libNickname );
647 xlibpart->AddAttribute( wxT(
"part" ), lcomp->GetName() );
650 if( !lcomp->GetDescription().IsEmpty() )
651 xlibpart->AddChild(
node( wxT(
"description" ), lcomp->GetDescription() ) );
653 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
654 xlibpart->AddChild(
node( wxT(
"docs" ), lcomp->GetDatasheetField().GetText() ) );
657 if( lcomp->GetFPFilters().GetCount() )
660 xlibpart->AddChild( xfootprints =
node( wxT(
"footprints" ) ) );
662 for(
unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
663 xfootprints->AddChild(
node( wxT(
"fp" ), lcomp->GetFPFilters()[i] ) );
668 lcomp->GetFields( fieldList );
671 xlibpart->AddChild( xfields =
node(
"fields" ) );
673 for(
const SCH_FIELD* field : fieldList )
676 xfields->AddChild( xfield =
node( wxT(
"field" ), field->GetText() ) );
677 xfield->AddAttribute( wxT(
"name" ), field->GetCanonicalName() );
681 std::vector<SCH_PIN*> pinList = lcomp->GetPins( 0, 0 );
693 for(
int ii = 0; ii < (int)pinList.size()-1; ii++ )
695 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
697 pinList.erase(pinList.begin() + ii + 1);
706 xlibpart->AddChild( pins =
node( wxT(
"pins" ) ) );
708 for(
unsigned i=0; i<pinList.size(); ++i )
712 pins->AddChild(
pin =
node( wxT(
"pin" ) ) );
713 pin->AddAttribute( wxT(
"num" ), pinList[i]->GetShownNumber() );
714 pin->AddAttribute( wxT(
"name" ), pinList[i]->GetShownName() );
715 pin->AddAttribute( wxT(
"type" ), pinList[i]->GetCanonicalElectricalTypeName() );
733 XNODE* xnet =
nullptr;
755 NET_RECORD(
const wxString& aName ) :
757 m_HasNoConnect(
false )
762 std::vector<NET_NODE> m_Nodes;
765 std::vector<NET_RECORD*> nets;
769 wxString net_name = key.Name;
770 NET_RECORD* net_record =
nullptr;
772 if( subgraphs.empty() )
775 nets.emplace_back(
new NET_RECORD( net_name ) );
776 net_record = nets.back();
780 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() ==
SCH_NO_CONNECT_T;
784 net_record->m_HasNoConnect =
true;
786 for(
SCH_ITEM* item : subgraph->GetItems() )
804 net_record->m_Nodes.emplace_back(
pin, sheet );
811 std::sort( nets.begin(), nets.end(),
812 [](
const NET_RECORD* a,
const NET_RECORD*b )
814 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
817 for(
int i = 0; i < (int) nets.size(); ++i )
819 NET_RECORD* net_record = nets[i];
824 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
825 [](
const NET_NODE& a,
const NET_NODE& b )
827 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
828 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
831 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
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 );
845 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
850 bool allNetPinsStacked =
true;
852 if( net_record->m_Nodes.size() > 1 )
854 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
856 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
859 return firstPin->GetParent() == node.m_Pin->GetParent()
860 && firstPin->GetPosition() == node.m_Pin->GetPosition()
861 && firstPin->GetName() == node.m_Pin->GetName();
865 for(
const NET_NODE& netNode : net_record->m_Nodes )
867 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
868 wxString pinText = netNode.m_Pin->GetShownNumber();
871 if( refText[0] == wxChar(
'#' ) )
876 netCodeTxt.Printf( wxT(
"%d" ), i + 1 );
878 xnets->AddChild( xnet =
node( wxT(
"net" ) ) );
879 xnet->AddAttribute( wxT(
"code" ), netCodeTxt );
880 xnet->AddAttribute( wxT(
"name" ), net_record->m_Name );
885 xnet->AddChild( xnode =
node( wxT(
"node" ) ) );
886 xnode->AddAttribute( wxT(
"ref" ), refText );
887 xnode->AddAttribute( wxT(
"pin" ), pinText );
889 wxString pinName = netNode.m_Pin->GetShownName();
890 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
892 if( !pinName.IsEmpty() )
893 xnode->AddAttribute( wxT(
"pinfunction" ), pinName );
895 if( net_record->m_HasNoConnect
896 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
897 pinType += wxT(
"+no_connect" );
899 xnode->AddAttribute( wxT(
"pintype" ), pinType );
903 for( NET_RECORD* record : nets )
911 const wxString& aTextualContent )
913 XNODE* n =
new XNODE( wxXML_ELEMENT_NODE, aName );
915 if( aTextualContent.Len() > 0 )
916 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 GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
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
int GetFieldCount() const
Return the number of fields in this symbol.
bool UseLibIdLookup() const
wxString GetSchSymbolLibraryName() const
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.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
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' flaga.
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)
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 and LIB_PART constructors.
@ DESCRIPTION_FIELD
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".