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 xcomp->AddChild( xunits =
node( wxT(
"tstamps" ) ) );
420 auto range = extra_units.equal_range( symbol );
424 for(
auto it = range.first; it != range.second; ++it )
426 uuid = ( *it )->m_Uuid.AsString();
433 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
438 xunits->AddChild(
new XNODE( wxXML_TEXT_NODE, wxEmptyString, uuid ) );
451 XNODE* xdesign =
node( wxT(
"design" ) );
457 wxFileName sourceFileName;
469 for(
const std::pair<const wxString, wxString>& prop : properties )
471 xdesign->AddChild( xtextvar =
node( wxT(
"textvar" ), prop.second ) );
472 xtextvar->AddAttribute( wxT(
"name" ), prop.first );
478 unsigned sheetIndex = 1;
482 screen = sheet.LastScreen();
484 xdesign->AddChild( xsheet =
node( wxT(
"sheet" ) ) );
487 sheetTxt.Printf( wxT(
"%u" ), sheetIndex++ );
488 xsheet->AddAttribute( wxT(
"number" ), sheetTxt );
489 xsheet->AddAttribute( wxT(
"name" ), sheet.PathHumanReadable() );
490 xsheet->AddAttribute( wxT(
"tstamps" ), sheet.PathAsString() );
495 xsheet->AddChild( xtitleBlock =
node( wxT(
"title_block" ) ) );
503 sourceFileName = wxFileName( screen->
GetFileName() );
504 xtitleBlock->AddChild(
node( wxT(
"source" ), sourceFileName.GetFullName() ) );
506 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
507 xcomment->AddAttribute( wxT(
"number" ), wxT(
"1" ) );
510 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
511 xcomment->AddAttribute( wxT(
"number" ), wxT(
"2" ) );
514 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
515 xcomment->AddAttribute( wxT(
"number" ), wxT(
"3" ) );
518 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
519 xcomment->AddAttribute( wxT(
"number" ), wxT(
"4" ) );
522 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
523 xcomment->AddAttribute( wxT(
"number" ), wxT(
"5" ) );
526 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
527 xcomment->AddAttribute( wxT(
"number" ), wxT(
"6" ) );
530 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
531 xcomment->AddAttribute( wxT(
"number" ), wxT(
"7" ) );
534 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
535 xcomment->AddAttribute( wxT(
"number" ), wxT(
"8" ) );
538 xtitleBlock->AddChild( xcomment =
node( wxT(
"comment" ) ) );
539 xcomment->AddAttribute( wxT(
"number" ), wxT(
"9" ) );
549 XNODE* xlibs =
node( wxT(
"libraries" ) );
554 wxString libNickname = *it;
557 if( symbolLibTable->
HasLibrary( libNickname ) )
559 xlibs->AddChild( xlibrary =
node( wxT(
"library" ) ) );
560 xlibrary->AddAttribute( wxT(
"logical" ), libNickname );
561 xlibrary->AddChild(
node( wxT(
"uri" ), symbolLibTable->
GetFullURI( libNickname ) ) );
573 XNODE* xlibparts =
node( wxT(
"libparts" ) );
574 std::vector<SCH_FIELD*> fieldList;
580 wxString libNickname = lcomp->GetLibId().GetLibNickname();;
583 if( !libNickname.IsEmpty() )
587 xlibparts->AddChild( xlibpart =
node( wxT(
"libpart" ) ) );
588 xlibpart->AddAttribute( wxT(
"lib" ), libNickname );
589 xlibpart->AddAttribute( wxT(
"part" ), lcomp->GetName() );
592 if( !lcomp->GetDescription().IsEmpty() )
593 xlibpart->AddChild(
node( wxT(
"description" ), lcomp->GetDescription() ) );
595 if( !lcomp->GetDatasheetField().GetText().IsEmpty() )
596 xlibpart->AddChild(
node( wxT(
"docs" ), lcomp->GetDatasheetField().GetText() ) );
599 if( lcomp->GetFPFilters().GetCount() )
602 xlibpart->AddChild( xfootprints =
node( wxT(
"footprints" ) ) );
604 for(
unsigned i = 0; i < lcomp->GetFPFilters().GetCount(); ++i )
605 xfootprints->AddChild(
node( wxT(
"fp" ), lcomp->GetFPFilters()[i] ) );
610 lcomp->GetFields( fieldList );
613 xlibpart->AddChild( xfields =
node(
"fields" ) );
615 for(
const SCH_FIELD* field : fieldList )
618 xfields->AddChild( xfield =
node( wxT(
"field" ), field->GetText() ) );
619 xfield->AddAttribute( wxT(
"name" ), field->GetCanonicalName() );
623 std::vector<SCH_PIN*> pinList = lcomp->GetPins( 0, 0 );
635 for(
int ii = 0; ii < (int)pinList.size()-1; ii++ )
637 if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
639 pinList.erase(pinList.begin() + ii + 1);
648 xlibpart->AddChild( pins =
node( wxT(
"pins" ) ) );
650 for(
unsigned i=0; i<pinList.size(); ++i )
654 pins->AddChild(
pin =
node( wxT(
"pin" ) ) );
655 pin->AddAttribute( wxT(
"num" ), pinList[i]->GetShownNumber() );
656 pin->AddAttribute( wxT(
"name" ), pinList[i]->GetShownName() );
657 pin->AddAttribute( wxT(
"type" ), pinList[i]->GetCanonicalElectricalTypeName() );
675 XNODE* xnet =
nullptr;
697 NET_RECORD(
const wxString& aName ) :
699 m_HasNoConnect(
false )
704 std::vector<NET_NODE> m_Nodes;
707 std::vector<NET_RECORD*> nets;
711 wxString net_name = key.Name;
712 NET_RECORD* net_record =
nullptr;
714 if( subgraphs.empty() )
717 nets.emplace_back(
new NET_RECORD( net_name ) );
718 net_record = nets.back();
722 bool nc = subgraph->GetNoConnect() && subgraph->GetNoConnect()->Type() ==
SCH_NO_CONNECT_T;
726 net_record->m_HasNoConnect =
true;
728 for(
SCH_ITEM* item : subgraph->GetItems() )
746 net_record->m_Nodes.emplace_back(
pin, sheet );
753 std::sort( nets.begin(), nets.end(),
754 [](
const NET_RECORD* a,
const NET_RECORD*b )
756 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
759 for(
int i = 0; i < (int) nets.size(); ++i )
761 NET_RECORD* net_record = nets[i];
766 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
767 [](
const NET_NODE& a,
const NET_NODE& b )
769 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
770 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
773 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
782 [](
const NET_NODE& a,
const NET_NODE& b )
784 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
785 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
787 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
792 bool allNetPinsStacked =
true;
794 if( net_record->m_Nodes.size() > 1 )
796 SCH_PIN* firstPin = net_record->m_Nodes.begin()->m_Pin;
798 std::all_of( net_record->m_Nodes.begin() + 1, net_record->m_Nodes.end(),
801 return firstPin->GetParent() == node.m_Pin->GetParent()
802 && firstPin->GetPosition() == node.m_Pin->GetPosition()
803 && firstPin->GetName() == node.m_Pin->GetName();
807 for(
const NET_NODE& netNode : net_record->m_Nodes )
809 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
810 wxString pinText = netNode.m_Pin->GetShownNumber();
813 if( refText[0] == wxChar(
'#' ) )
818 netCodeTxt.Printf( wxT(
"%d" ), i + 1 );
820 xnets->AddChild( xnet =
node( wxT(
"net" ) ) );
821 xnet->AddAttribute( wxT(
"code" ), netCodeTxt );
822 xnet->AddAttribute( wxT(
"name" ), net_record->m_Name );
827 xnet->AddChild( xnode =
node( wxT(
"node" ) ) );
828 xnode->AddAttribute( wxT(
"ref" ), refText );
829 xnode->AddAttribute( wxT(
"pin" ), pinText );
831 wxString pinName = netNode.m_Pin->GetShownName();
832 wxString pinType = netNode.m_Pin->GetCanonicalElectricalTypeName();
834 if( !pinName.IsEmpty() )
835 xnode->AddAttribute( wxT(
"pinfunction" ), pinName );
837 if( net_record->m_HasNoConnect
838 && ( net_record->m_Nodes.size() == 1 || allNetPinsStacked ) )
839 pinType += wxT(
"+no_connect" );
841 xnode->AddAttribute( wxT(
"pintype" ), pinType );
845 for( NET_RECORD* record : nets )
853 const wxString& aTextualContent )
855 XNODE* n =
new XNODE( wxXML_ELEMENT_NODE, aName );
857 if( aTextualContent.Len() > 0 )
858 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.
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 SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const =0
virtual PROJECT & Prj() 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()
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".