From 744452d092354fb03b1163a72b025dc357509d45 Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Mon, 31 Jul 2023 10:38:02 -0400 Subject: [PATCH] Sch/PCB: allow back-updating schematic fields from PCB Fixes: https://gitlab.com/kicad/code/kicad/-/issues/15285 --- eeschema/dialogs/dialog_update_from_pcb.cpp | 7 +- eeschema/dialogs/dialog_update_from_pcb.h | 1 + .../dialogs/dialog_update_from_pcb_base.cpp | 7 ++ .../dialogs/dialog_update_from_pcb_base.fbp | 65 +++++++++++ .../dialogs/dialog_update_from_pcb_base.h | 1 + .../netlist_exporter_xml.cpp | 38 ++++++- eeschema/tools/backannotate.cpp | 106 +++++++++++++++++- eeschema/tools/backannotate.h | 11 +- pcbnew/cross-probing.cpp | 6 + .../netlist_reader/board_netlist_updater.cpp | 11 ++ pcbnew/netlist_reader/pcb_netlist.cpp | 9 ++ pcbnew/tools/board_editor_control.cpp | 6 + 12 files changed, 260 insertions(+), 8 deletions(-) diff --git a/eeschema/dialogs/dialog_update_from_pcb.cpp b/eeschema/dialogs/dialog_update_from_pcb.cpp index c59885d271..7bef08733b 100644 --- a/eeschema/dialogs/dialog_update_from_pcb.cpp +++ b/eeschema/dialogs/dialog_update_from_pcb.cpp @@ -31,7 +31,7 @@ // Saved dialog settings DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB_SAVED_STATE - DIALOG_UPDATE_FROM_PCB::s_savedDialogState{ false, true, true, true, false, true }; + DIALOG_UPDATE_FROM_PCB::s_savedDialogState{ false, true, true, true, false, true, true }; DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB( SCH_EDIT_FRAME* aParent ) @@ -62,6 +62,7 @@ DIALOG_UPDATE_FROM_PCB::DIALOG_UPDATE_FROM_PCB( SCH_EDIT_FRAME* aParent ) m_cbUpdateValues->SetValue( s_savedDialogState.UpdateValues ); m_cbUpdateNetNames->SetValue( s_savedDialogState.UpdateNetNames ); m_cbUpdateAttributes->SetValue( s_savedDialogState.UpdateAttributes ); + m_cbUpdateOtherFields->SetValue( s_savedDialogState.UpdateOtherFields ); SetupStandardButtons( { { wxID_OK, _( "Update Schematic" ) }, { wxID_CANCEL, _( "Close" ) } } ); @@ -82,6 +83,7 @@ void DIALOG_UPDATE_FROM_PCB::updateData() m_cbUpdateReferences->GetValue(), m_cbUpdateNetNames->GetValue(), m_cbUpdateAttributes->GetValue(), + m_cbUpdateOtherFields->GetValue(), true ); std::string netlist; @@ -135,6 +137,8 @@ void DIALOG_UPDATE_FROM_PCB::OnOptionChanged( wxCommandEvent& event ) s_savedDialogState.UpdateNetNames = m_cbUpdateNetNames->GetValue(); else if( event.GetEventObject() == m_cbUpdateAttributes ) s_savedDialogState.UpdateAttributes = m_cbUpdateAttributes->GetValue(); + else if( event.GetEventObject() == m_cbUpdateOtherFields ) + s_savedDialogState.UpdateOtherFields = m_cbUpdateOtherFields->GetValue(); } @@ -150,6 +154,7 @@ void DIALOG_UPDATE_FROM_PCB::OnUpdateClick( wxCommandEvent& event ) m_cbUpdateReferences->GetValue(), m_cbUpdateNetNames->GetValue(), m_cbUpdateAttributes->GetValue(), + m_cbUpdateOtherFields->GetValue(), false ); if( backAnno.FetchNetlistFromPCB( netlist ) && backAnno.BackAnnotateSymbols( netlist ) ) diff --git a/eeschema/dialogs/dialog_update_from_pcb.h b/eeschema/dialogs/dialog_update_from_pcb.h index 887dd5545f..b8669743e7 100644 --- a/eeschema/dialogs/dialog_update_from_pcb.h +++ b/eeschema/dialogs/dialog_update_from_pcb.h @@ -56,6 +56,7 @@ private: bool UpdateValues; bool UpdateNetNames; bool UpdateAttributes; + bool UpdateOtherFields; }; static DIALOG_UPDATE_FROM_PCB_SAVED_STATE s_savedDialogState; diff --git a/eeschema/dialogs/dialog_update_from_pcb_base.cpp b/eeschema/dialogs/dialog_update_from_pcb_base.cpp index 0ec152401e..1237bdf40d 100644 --- a/eeschema/dialogs/dialog_update_from_pcb_base.cpp +++ b/eeschema/dialogs/dialog_update_from_pcb_base.cpp @@ -72,6 +72,11 @@ DIALOG_UPDATE_FROM_PCB_BASE::DIALOG_UPDATE_FROM_PCB_BASE( wxWindow* parent, wxWi m_cbUpdateAttributes = new wxCheckBox( sbSizer2->GetStaticBox(), wxID_ANY, _("Attributes"), wxDefaultPosition, wxDefaultSize, 0 ); fgSizer2->Add( m_cbUpdateAttributes, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); + m_cbUpdateOtherFields = new wxCheckBox( sbSizer2->GetStaticBox(), wxID_ANY, _("Other fields"), wxDefaultPosition, wxDefaultSize, 0 ); + m_cbUpdateOtherFields->SetToolTip( _("Update all other fields in the symbol from the footprint") ); + + fgSizer2->Add( m_cbUpdateOtherFields, 0, wxBOTTOM|wxLEFT|wxRIGHT, 5 ); + sbSizer2->Add( fgSizer2, 1, wxEXPAND, 5 ); @@ -112,6 +117,7 @@ DIALOG_UPDATE_FROM_PCB_BASE::DIALOG_UPDATE_FROM_PCB_BASE( wxWindow* parent, wxWi m_cbUpdateValues->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateNetNames->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateAttributes->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); + m_cbUpdateOtherFields->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnUpdateClick ), NULL, this ); } @@ -124,6 +130,7 @@ DIALOG_UPDATE_FROM_PCB_BASE::~DIALOG_UPDATE_FROM_PCB_BASE() m_cbUpdateValues->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateNetNames->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_cbUpdateAttributes->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); + m_cbUpdateOtherFields->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnOptionChanged ), NULL, this ); m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_UPDATE_FROM_PCB_BASE::OnUpdateClick ), NULL, this ); } diff --git a/eeschema/dialogs/dialog_update_from_pcb_base.fbp b/eeschema/dialogs/dialog_update_from_pcb_base.fbp index 90729b156d..f0e59a19c4 100644 --- a/eeschema/dialogs/dialog_update_from_pcb_base.fbp +++ b/eeschema/dialogs/dialog_update_from_pcb_base.fbp @@ -520,6 +520,71 @@ OnOptionChanged + + 5 + wxBOTTOM|wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Other fields + + 0 + + + 0 + + 1 + m_cbUpdateOtherFields + 1 + + + protected + 1 + + Resizable + 1 + + + ; forward_declare + 0 + Update all other fields in the symbol from the footprint + + wxFILTER_NONE + wxDefaultValidator + + + + + OnOptionChanged + + diff --git a/eeschema/dialogs/dialog_update_from_pcb_base.h b/eeschema/dialogs/dialog_update_from_pcb_base.h index 54b8b056cf..35ac77838f 100644 --- a/eeschema/dialogs/dialog_update_from_pcb_base.h +++ b/eeschema/dialogs/dialog_update_from_pcb_base.h @@ -41,6 +41,7 @@ class DIALOG_UPDATE_FROM_PCB_BASE : public DIALOG_SHIM wxCheckBox* m_cbUpdateValues; wxCheckBox* m_cbUpdateNetNames; wxCheckBox* m_cbUpdateAttributes; + wxCheckBox* m_cbUpdateOtherFields; WX_HTML_REPORT_PANEL* m_messagePanel; wxStdDialogButtonSizer* m_sdbSizer; wxButton* m_sdbSizerOK; diff --git a/eeschema/netlist_exporters/netlist_exporter_xml.cpp b/eeschema/netlist_exporters/netlist_exporter_xml.cpp index 0d2584e75e..c0b935e010 100644 --- a/eeschema/netlist_exporters/netlist_exporter_xml.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_xml.cpp @@ -94,8 +94,9 @@ void NETLIST_EXPORTER_XML::addSymbolFields( XNODE* aNode, SCH_SYMBOL* aSymbol, SCH_SHEET_PATH* aSheet ) { wxString value; - wxString datasheet; wxString footprint; + wxString datasheet; + wxString description; wxString candidate; std::map userFields; @@ -127,16 +128,20 @@ void NETLIST_EXPORTER_XML::addSymbolFields( XNODE* aNode, SCH_SYMBOL* aSymbol, int unit = symbol2->GetUnitSelection( aSheet ); // The lowest unit number wins. User should only set fields in any one unit. + + // Value candidate = symbol2->GetValueFieldText( m_resolveTextVars, &sheetList[i], false ); if( !candidate.IsEmpty() && ( unit < minUnit || value.IsEmpty() ) ) value = candidate; + // Footprint candidate = symbol2->GetFootprintFieldText( m_resolveTextVars, &sheetList[i], false ); if( !candidate.IsEmpty() && ( unit < minUnit || footprint.IsEmpty() ) ) footprint = candidate; + // Datasheet candidate = m_resolveTextVars ? symbol2->GetField( DATASHEET_FIELD )->GetShownText( &sheetList[i], false ) : symbol2->GetField( DATASHEET_FIELD )->GetText(); @@ -144,6 +149,15 @@ void NETLIST_EXPORTER_XML::addSymbolFields( XNODE* aNode, SCH_SYMBOL* aSymbol, if( !candidate.IsEmpty() && ( unit < minUnit || datasheet.IsEmpty() ) ) datasheet = candidate; + // Description + candidate = m_resolveTextVars + ? symbol2->GetField( DESCRIPTION_FIELD )->GetShownText( &sheetList[i], false ) + : symbol2->GetField( DESCRIPTION_FIELD )->GetText(); + + if( !candidate.IsEmpty() && ( unit < minUnit || description.IsEmpty() ) ) + description = candidate; + + // All non-mandatory fields for( int ii = MANDATORY_FIELDS; ii < symbol2->GetFieldCount(); ++ii ) { const SCH_FIELD& f = symbol2->GetFields()[ ii ]; @@ -167,11 +181,18 @@ void NETLIST_EXPORTER_XML::addSymbolFields( XNODE* aNode, SCH_SYMBOL* aSymbol, value = aSymbol->GetValueFieldText( m_resolveTextVars, aSheet, false ); footprint = aSymbol->GetFootprintFieldText( m_resolveTextVars, aSheet, false ); + // Datasheet if( m_resolveTextVars ) datasheet = aSymbol->GetField( DATASHEET_FIELD )->GetShownText( aSheet, false ); else datasheet = aSymbol->GetField( DATASHEET_FIELD )->GetText(); + // Description + if( m_resolveTextVars ) + description = aSymbol->GetField( DESCRIPTION_FIELD )->GetShownText( aSheet, false ); + else + description = aSymbol->GetField( DESCRIPTION_FIELD )->GetText(); + for( int ii = MANDATORY_FIELDS; ii < aSymbol->GetFieldCount(); ++ii ) { const SCH_FIELD& f = aSymbol->GetFields()[ ii ]; @@ -198,11 +219,26 @@ void NETLIST_EXPORTER_XML::addSymbolFields( XNODE* aNode, SCH_SYMBOL* aSymbol, if( datasheet.size() ) aNode->AddChild( node( wxT( "datasheet" ), UnescapeString( datasheet ) ) ); + if( datasheet.size() ) + aNode->AddChild( node( wxT( "description" ), UnescapeString( description ) ) ); + if( userFields.size() ) { XNODE* xfields; aNode->AddChild( xfields = node( wxT( "fields" ) ) ); + XNODE* datasheetField = node( wxT( "field" ), UnescapeString( datasheet ) ); + datasheetField->AddAttribute( + wxT( "name" ), + UnescapeString( TEMPLATE_FIELDNAME::GetDefaultFieldName( DATASHEET_FIELD ) ) ); + xfields->AddChild( datasheetField ); + + XNODE* descriptionField = node( wxT( "field" ), UnescapeString( description ) ); + descriptionField->AddAttribute( + wxT( "name" ), + UnescapeString( TEMPLATE_FIELDNAME::GetDefaultFieldName( DESCRIPTION_FIELD ) ) ); + xfields->AddChild( descriptionField ); + // non MANDATORY fields are output alphabetically for( const std::pair& f : userFields ) { diff --git a/eeschema/tools/backannotate.cpp b/eeschema/tools/backannotate.cpp index 7f52e68979..fc97685e5a 100644 --- a/eeschema/tools/backannotate.cpp +++ b/eeschema/tools/backannotate.cpp @@ -44,7 +44,8 @@ BACK_ANNOTATE::BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, REPORTER& aReporter, bool aRelinkFootprints, bool aProcessFootprints, bool aProcessValues, bool aProcessReferences, bool aProcessNetNames, - bool aProcessAttributes, bool aDryRun ) : + bool aProcessAttributes, bool aProcessOtherFields, + bool aDryRun ) : m_reporter( aReporter ), m_matchByReference( aRelinkFootprints ), m_processFootprints( aProcessFootprints ), @@ -52,6 +53,7 @@ BACK_ANNOTATE::BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, REPORTER& aReporter, bool m_processReferences( aProcessReferences ), m_processNetNames( aProcessNetNames ), m_processAttributes( aProcessAttributes ), + m_processOtherFields( aProcessOtherFields ), m_dryRun( aDryRun ), m_frame( aFrame ), m_changesCount( 0 ) @@ -150,7 +152,7 @@ void BACK_ANNOTATE::getPcbModulesFromString( const std::string& aPayload ) { wxString path, value, footprint; bool dnp = false, exBOM = false; - std::map pinNetMap; + std::map pinNetMap, fieldsMap; wxASSERT( item.first == "ref" ); wxString ref = getStr( item.second ); @@ -171,6 +173,29 @@ void BACK_ANNOTATE::getPcbModulesFromString( const std::string& aPayload ) footprint = getStr( item.second.get_child( "fpid" ) ); value = getStr( item.second.get_child( "value" ) ); + // Get child PTREE of fields + boost::optional fields = item.second.get_child_optional( "fields" ); + + // Parse each field out of the fields string + if( fields ) + { + for( const std::pair& field : fields.get() ) + { + if( field.first != "field" ) + continue; + + // Fields are of the format "(field (name "name") "12345") + auto fieldName = field.second.get_child_optional( "name" ); + auto fieldValue = field.second.back().first; + + if( !fieldName ) + continue; + + fieldsMap[getStr( fieldName.get() )] = fieldValue; + } + } + + // Get DNP and Exclude from BOM out of the properties if they exist for( const auto& child : item.second ) { @@ -226,7 +251,7 @@ void BACK_ANNOTATE::getPcbModulesFromString( const std::string& aPayload ) { // Add footprint to the map auto data = std::make_shared( ref, footprint, value, dnp, exBOM, - pinNetMap ); + pinNetMap, fieldsMap ); m_pcbFootprints.insert( nearestItem, std::make_pair( path, data ) ); } } @@ -465,6 +490,81 @@ void BACK_ANNOTATE::applyChangelist() } } + if( m_processOtherFields ) + { + // Need to handle three cases: existing field, new field, deleted field + for( const std::pair& field : fpData.m_fieldsMap ) + { + const wxString& fpFieldName = field.first; + const wxString& fpFieldValue = field.second; + SCH_FIELD* symField = symbol->FindField( fpFieldName ); + + // 1. Existing fields has changed value + // PCB Field value is checked against the shown text because this is the value + // with all the variables resolved. The footprints field value gets the symbol's + // resolved value when the PCB is updated from the schematic. + if( symField + && symField->GetShownText( &ref.GetSheetPath(), false ) != fpFieldValue ) + { + m_changesCount++; + msg.Printf( _( "Change field '%s' value to '%s'." ), + symField->GetCanonicalName(), fpFieldValue ); + + if( !m_dryRun ) + { + commit.Modify( symbol, screen ); + symField->SetText( fpFieldValue ); + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + } + + // 2. New field has been added to footprint and needs to be added to symbol + if( symField == nullptr ) + { + m_changesCount++; + msg.Printf( _( "Add field '%s' with value '%s'." ), fpFieldName, fpFieldValue ); + + if( !m_dryRun ) + { + commit.Modify( symbol, screen ); + + SCH_FIELD newField( VECTOR2I( 0, 0 ), symbol->GetFieldCount(), symbol, + fpFieldName ); + newField.SetText( fpFieldValue ); + symbol->AddField( newField ); + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + } + } + + // 3. Existing field has been deleted from footprint and needs to be deleted from symbol + // Check all symbol fields for existence in the footprint field map + for( SCH_FIELD& field : symbol->GetFields() ) + { + // Never delete mandatory fields + if( field.GetId() < MANDATORY_FIELDS ) + continue; + + if( fpData.m_fieldsMap.find( field.GetCanonicalName() ) + == fpData.m_fieldsMap.end() ) + { + // Field not found in footprint field map, delete it + m_changesCount++; + msg.Printf( _( "Delete field '%s.'" ), field.GetCanonicalName() ); + + if( !m_dryRun ) + { + commit.Modify( symbol, screen ); + symbol->RemoveField( &field ); + } + + m_reporter.ReportHead( msg, RPT_SEVERITY_ACTION ); + } + } + } + // TODO: back-annotate netclass changes? } diff --git a/eeschema/tools/backannotate.h b/eeschema/tools/backannotate.h index ee7a0140a8..07087035e7 100644 --- a/eeschema/tools/backannotate.h +++ b/eeschema/tools/backannotate.h @@ -62,13 +62,15 @@ public: { PCB_FP_DATA( const wxString& aRef, const wxString& aFootprint, const wxString& aValue, bool aDNP, bool aExcludeFromBOM, - const std::map& aPinMap ) : + const std::map& aPinMap, + const std::map& aFieldsMap ) : m_ref( aRef ), m_footprint( aFootprint ), m_value( aValue ), m_DNP( aDNP ), m_excludeFromBOM( aExcludeFromBOM ), - m_pinMap( aPinMap ) + m_pinMap( aPinMap ), + m_fieldsMap( aFieldsMap ) {} wxString m_ref; @@ -77,6 +79,7 @@ public: bool m_DNP; bool m_excludeFromBOM; std::map m_pinMap; + std::map m_fieldsMap; }; ///< Map to hold NETLIST footprints data @@ -86,7 +89,8 @@ public: BACK_ANNOTATE( SCH_EDIT_FRAME* aFrame, REPORTER& aReporter, bool aRelinkFootprints, bool aProcessFootprints, bool aProcessValues, bool aProcessReferences, - bool aProcessNetNames, bool aProcessAttributes, bool aDryRun ); + bool aProcessNetNames, bool aProcessAttributes, bool aProcessOtherFields, + bool aDryRun ); ~BACK_ANNOTATE(); /** @@ -143,6 +147,7 @@ private: bool m_processReferences; bool m_processNetNames; bool m_processAttributes; + bool m_processOtherFields; bool m_dryRun; PCB_FOOTPRINTS_MAP m_pcbFootprints; diff --git a/pcbnew/cross-probing.cpp b/pcbnew/cross-probing.cpp index 48e2607486..b856524c0b 100644 --- a/pcbnew/cross-probing.cpp +++ b/pcbnew/cross-probing.cpp @@ -563,6 +563,12 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) } } + std::map fields; + for( PCB_FIELD* field : footprint->Fields() ) + fields[field->GetCanonicalName()] = field->GetText(); + + component->SetFields( fields ); + // Add DNP and Exclude from BOM properties std::map properties; diff --git a/pcbnew/netlist_reader/board_netlist_updater.cpp b/pcbnew/netlist_reader/board_netlist_updater.cpp index 9d0d8507b0..e03d9e6d31 100644 --- a/pcbnew/netlist_reader/board_netlist_updater.cpp +++ b/pcbnew/netlist_reader/board_netlist_updater.cpp @@ -360,6 +360,7 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint, changed = true; + // Add or change field value for( auto pair : aNetlistComponent->GetFields() ) { if( aPcbFootprint->HasFieldByName( pair.first ) ) @@ -386,6 +387,16 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint, } } } + + // Remove fields that aren't present in the symbol + for( PCB_FIELD* field : aPcbFootprint->GetFields() ) + { + if( field->IsMandatoryField() ) + continue; + + if( aNetlistComponent->GetFields().count( field->GetName() ) == 0 ) + aPcbFootprint->RemoveField( field->GetCanonicalName() ); + } } m_reporter->Report( msg, RPT_SEVERITY_ACTION ); diff --git a/pcbnew/netlist_reader/pcb_netlist.cpp b/pcbnew/netlist_reader/pcb_netlist.cpp index d95eef52bc..f3d84e3659 100644 --- a/pcbnew/netlist_reader/pcb_netlist.cpp +++ b/pcbnew/netlist_reader/pcb_netlist.cpp @@ -93,6 +93,15 @@ void COMPONENT::Format( OUTPUTFORMATTER* aOut, int aNestLevel, int aCtl ) aOut->Print( nl+1, "(timestamp %s)\n", aOut->Quotew( path ).c_str() ); + // Add all fields as a (field) under a (fields) node + aOut->Print( nl + 1, "(fields" ); + + for( std::pair field : m_fields ) + aOut->Print( nl + 2, "\n(field (name %s) %s)", aOut->Quotew( field.first ).c_str(), + aOut->Quotew( field.second ).c_str() ); + + aOut->Print( 0, ")\n" ); + // Add DNP and Exclude from BOM properties if we have them if( m_properties.count( "dnp" ) ) aOut->Print( nl + 1, "(property (name \"dnp\"))\n" ); diff --git a/pcbnew/tools/board_editor_control.cpp b/pcbnew/tools/board_editor_control.cpp index dd6d17aef5..c9f53c4423 100644 --- a/pcbnew/tools/board_editor_control.cpp +++ b/pcbnew/tools/board_editor_control.cpp @@ -473,6 +473,12 @@ int BOARD_EDITOR_CONTROL::ExportNetlist( const TOOL_EVENT& aEvent ) } } + std::map fields; + for( PCB_FIELD* field : footprint->Fields() ) + fields[field->GetCanonicalName()] = field->GetText(); + + component->SetFields( fields ); + netlist.AddComponent( component ); }