diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index 55cb438093..148d7c1406 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -187,6 +187,7 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std: m_DRCSeverities[ DRCE_NET_CONFLICT ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_SCHEMATIC_PARITY ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_FOOTPRINT_FILTERS ] = RPT_SEVERITY_IGNORE; + m_DRCSeverities[ DRCE_SCHEMATIC_FIELDS_PARITY ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_SILK_MASK_CLEARANCE ] = RPT_SEVERITY_WARNING; diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 3e1cd2db07..47e0d1d253 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -1372,7 +1372,8 @@ void DIALOG_DRC::updateDisplayedCounts() || ii == DRCE_EXTRA_FOOTPRINT || ii == DRCE_NET_CONFLICT || ii == DRCE_SCHEMATIC_PARITY - || ii == DRCE_FOOTPRINT_FILTERS ) + || ii == DRCE_FOOTPRINT_FILTERS + || ii == DRCE_SCHEMATIC_FIELDS_PARITY ) { if( m_showWarnings->GetValue() && severity == RPT_SEVERITY_WARNING ) footprintsOverflowed = true; diff --git a/pcbnew/drc/drc_item.cpp b/pcbnew/drc/drc_item.cpp index f42f9435d2..faba144528 100644 --- a/pcbnew/drc/drc_item.cpp +++ b/pcbnew/drc/drc_item.cpp @@ -205,6 +205,10 @@ DRC_ITEM DRC_ITEM::footprintFilters( DRCE_FOOTPRINT_FILTERS, _HKI( "Footprint doesn't match symbol's footprint filters" ), wxT( "footprint_filters_mismatch" ) ); +DRC_ITEM DRC_ITEM::schematicFieldsParity( DRCE_SCHEMATIC_FIELDS_PARITY, + _HKI( "Footprint field does not match symbol field" ), + wxT( "footprint_symbol_field_mismatch" ) ); + DRC_ITEM DRC_ITEM::libFootprintIssues( DRCE_LIB_FOOTPRINT_ISSUES, _HKI( "Footprint not found in libraries" ), wxT( "lib_footprint_issues" ) ); @@ -346,6 +350,7 @@ std::vector> DRC_ITEM::allItemTypes( { DRC_ITEM::missingFootprint, DRC_ITEM::extraFootprint, DRC_ITEM::schematicParity, + DRC_ITEM::schematicFieldsParity, DRC_ITEM::footprintFilters, DRC_ITEM::netConflict, DRC_ITEM::unconnectedItems, @@ -434,6 +439,7 @@ std::shared_ptr DRC_ITEM::Create( int aErrorCode ) case DRCE_NET_CONFLICT: return std::make_shared( netConflict ); case DRCE_EXTRA_FOOTPRINT: return std::make_shared( extraFootprint ); case DRCE_SCHEMATIC_PARITY: return std::make_shared( schematicParity ); + case DRCE_SCHEMATIC_FIELDS_PARITY: return std::make_shared( schematicFieldsParity ); case DRCE_FOOTPRINT_FILTERS: return std::make_shared( footprintFilters ); case DRCE_LIB_FOOTPRINT_ISSUES: return std::make_shared( libFootprintIssues ); case DRCE_LIB_FOOTPRINT_MISMATCH: return std::make_shared( libFootprintMismatch ); diff --git a/pcbnew/drc/drc_item.h b/pcbnew/drc/drc_item.h index b5c8323b03..3377294535 100644 --- a/pcbnew/drc/drc_item.h +++ b/pcbnew/drc/drc_item.h @@ -115,7 +115,9 @@ enum PCB_DRC_CODE DRCE_TRACK_ON_POST_MACHINED_LAYER, // Track connected to pad/via on post-machined/backdrilled layer - DRCE_LAST = DRCE_TRACK_ON_POST_MACHINED_LAYER + DRCE_SCHEMATIC_FIELDS_PARITY, // Mismatch with schematic fields + + DRCE_LAST = DRCE_SCHEMATIC_FIELDS_PARITY }; @@ -251,6 +253,7 @@ private: static DRC_ITEM missingTuningProfile; static DRC_ITEM tuningProfileImplicitRules; static DRC_ITEM trackOnPostMachinedLayer; + static DRC_ITEM schematicFieldsParity; private: DRC_RULE* m_violatingRule = nullptr; diff --git a/pcbnew/drc/drc_test_provider_schematic_parity.cpp b/pcbnew/drc/drc_test_provider_schematic_parity.cpp index 1b932fc2f4..17aff91b36 100644 --- a/pcbnew/drc/drc_test_provider_schematic_parity.cpp +++ b/pcbnew/drc/drc_test_provider_schematic_parity.cpp @@ -201,6 +201,59 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist ) reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); } + // Compare custom fields between schematic component and PCB footprint + if( !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_FIELDS_PARITY ) ) + { + std::unordered_map fpFieldsAsMap; + + for( PCB_FIELD* field : footprint->GetFields() ) + { + if( field->IsReference() || field->IsValue() || field->IsComponentClass() ) + continue; + + fpFieldsAsMap[field->GetName()] = field->GetText(); + } + + // Remove the extra component fields we don't want to evaluate here + nlohmann::ordered_map compFields = component->GetFields(); + compFields.erase( GetCanonicalFieldName( FIELD_T::REFERENCE ) ); + compFields.erase( GetCanonicalFieldName( FIELD_T::VALUE ) ); + compFields.erase( GetCanonicalFieldName( FIELD_T::FOOTPRINT ) ); + compFields.erase( wxT( "Component Class" ) ); + + bool fieldsMatch = true; + wxString mismatchDetail; + + for( const auto& [name, value] : compFields ) + { + auto it = fpFieldsAsMap.find( name ); + + if( it == fpFieldsAsMap.end() ) + { + fieldsMatch = false; + mismatchDetail = wxString::Format( _( "Missing symbol field '%s' in footprint" ), name ); + break; + } + + if( it->second != value ) + { + fieldsMatch = false; + mismatchDetail = wxString::Format( _( "Field '%s' differs (PCB: '%s', Schematic: '%s')" ), + name, it->second, value ); + break; + } + } + + if( !fieldsMatch && !mismatchDetail.IsEmpty() ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_FIELDS_PARITY ); + + drcItem->SetErrorMessage( mismatchDetail ); + drcItem->SetItems( footprint ); + reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); + } + } + for( PAD* pad : footprint->Pads() ) { if( m_drcEngine->IsErrorLimitExceeded( DRCE_NET_CONFLICT ) ) diff --git a/pcbnew/pcb_marker.cpp b/pcbnew/pcb_marker.cpp index 457e35631b..4a75c32a01 100644 --- a/pcbnew/pcb_marker.cpp +++ b/pcbnew/pcb_marker.cpp @@ -71,6 +71,7 @@ PCB_MARKER::PCB_MARKER( std::shared_ptr aItem, const VECTOR2I& aPositio case DRCE_EXTRA_FOOTPRINT: case DRCE_NET_CONFLICT: case DRCE_SCHEMATIC_PARITY: + case DRCE_SCHEMATIC_FIELDS_PARITY: case DRCE_FOOTPRINT_FILTERS: SetMarkerType( MARKER_BASE::MARKER_PARITY ); break; diff --git a/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp b/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp index cf54e5f0db..29507f5f02 100644 --- a/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp +++ b/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp @@ -595,6 +595,7 @@ bool WriteDRCReport( BOARD* aBoard, const wxString& aFileName, EDA_UNITS aUnits, || aItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT || aItem->GetErrorCode() == DRCE_NET_CONFLICT || aItem->GetErrorCode() == DRCE_SCHEMATIC_PARITY + || aItem->GetErrorCode() == DRCE_SCHEMATIC_FIELDS_PARITY || aItem->GetErrorCode() == DRCE_FOOTPRINT_FILTERS ) { footprints.push_back( aItem ); diff --git a/pcbnew/tools/drc_tool.cpp b/pcbnew/tools/drc_tool.cpp index 818f804a5a..f8346839c4 100644 --- a/pcbnew/tools/drc_tool.cpp +++ b/pcbnew/tools/drc_tool.cpp @@ -300,6 +300,7 @@ wxString DRC_TOOL::FixDRCErrorMenuText( const std::shared_ptr& aDRCItem return frame()->GetRunMenuCommandDescription( PCB_ACTIONS::changeFootprint ); } else if( aDRCItem->GetErrorCode() == DRCE_SCHEMATIC_PARITY + || aDRCItem->GetErrorCode() == DRCE_SCHEMATIC_FIELDS_PARITY || aDRCItem->GetErrorCode() == DRCE_MISSING_FOOTPRINT || aDRCItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT || aDRCItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT ) @@ -359,6 +360,7 @@ void DRC_TOOL::FixDRCError( const std::shared_ptr& aDRCItem ) } } else if( aDRCItem->GetErrorCode() == DRCE_SCHEMATIC_PARITY + || aDRCItem->GetErrorCode() == DRCE_SCHEMATIC_FIELDS_PARITY || aDRCItem->GetErrorCode() == DRCE_MISSING_FOOTPRINT || aDRCItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT || aDRCItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT )