diff --git a/eeschema/erc/erc.cpp b/eeschema/erc/erc.cpp index 8ec742c6dd..e6dc8fd573 100644 --- a/eeschema/erc/erc.cpp +++ b/eeschema/erc/erc.cpp @@ -1444,6 +1444,69 @@ int ERC_TESTER::TestFootprintLinkIssues( KIFACE* aCvPcb, PROJECT* aProject ) } +int ERC_TESTER::TestFootprintFilters() +{ + wxCHECK( m_schematic, 0 ); + + wxString msg; + int err_count = 0; + + for( SCH_SHEET_PATH& sheet : m_sheetList ) + { + std::vector<SCH_MARKER*> markers; + + for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) ) + { + SCH_SYMBOL* sch_symbol = static_cast<SCH_SYMBOL*>( item ); + std::unique_ptr<LIB_SYMBOL>& lib_symbol = sch_symbol->GetLibSymbolRef(); + + if( !lib_symbol ) + continue; + + wxArrayString filters = lib_symbol->GetFPFilters(); + + if( filters.empty() ) + continue; + + LIB_ID footprint; + + if( footprint.Parse( sch_symbol->GetFootprintFieldText( true, &sheet, false ) ) > 0 ) + continue; + + wxString footprintName = footprint.GetUniStringLibItemName(); + bool found = false; + + for( const wxString& filter : filters ) + { + found |= footprintName.Matches( filter ); + + if( found ) + break; + } + + if( !found ) + { + std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_FOOTPRINT_LINK_ISSUES ); + msg.Printf( _( "Assigned footprint (%s) doesn't match footprint filters (%s)." ), + footprintName, + wxJoin( filters, ' ' ) ); + ercItem->SetErrorMessage( msg ); + ercItem->SetItems( sch_symbol ); + markers.emplace_back( new SCH_MARKER( ercItem, sch_symbol->GetPosition() ) ); + } + } + + for( SCH_MARKER* marker : markers ) + { + sheet.LastScreen()->Append( marker ); + err_count += 1; + } + } + + return err_count; +} + + int ERC_TESTER::TestOffGridEndpoints() { const int gridSize = m_schematic->Settings().m_ConnectionGridSize; @@ -1687,6 +1750,14 @@ void ERC_TESTER::RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aE TestFootprintLinkIssues( aCvPcb, aProject ); } + if( m_settings.IsTestEnabled( ERCE_FOOTPRINT_FILTERS ) ) + { + if( aProgressReporter ) + aProgressReporter->AdvancePhase( _( "Checking footprint assignments against footprint filters..." ) ); + + TestFootprintFilters(); + } + if( m_settings.IsTestEnabled( ERCE_ENDPOINT_OFF_GRID ) ) { if( aProgressReporter ) diff --git a/eeschema/erc/erc.h b/eeschema/erc/erc.h index 18c9733a60..1f96d85bc5 100644 --- a/eeschema/erc/erc.h +++ b/eeschema/erc/erc.h @@ -146,6 +146,12 @@ public: */ int TestFootprintLinkIssues( KIFACE* aCvPcb, PROJECT* aProject ); + /** + * Test symbols to ensure that assigned footprint passes any given footprint filters. + * @return the number of issues found + */ + int TestFootprintFilters(); + /** * Test pins and wire ends for being off grid. * @return the error count diff --git a/eeschema/erc/erc_item.cpp b/eeschema/erc/erc_item.cpp index faeaec2995..419bd81be9 100644 --- a/eeschema/erc/erc_item.cpp +++ b/eeschema/erc/erc_item.cpp @@ -188,6 +188,10 @@ ERC_ITEM ERC_ITEM::footprintLinkIssues( ERCE_FOOTPRINT_LINK_ISSUES, _( "Footprint link issue" ), wxT( "footprint_link_issues" ) ); +ERC_ITEM ERC_ITEM::footprintFilters( ERCE_FOOTPRINT_FILTERS, + _( "Assigned footprint doesn't match footprint filters" ), + wxT( "footprint_filter" ) ); + ERC_ITEM ERC_ITEM::unannotated( ERCE_UNANNOTATED, _( "Symbol is not annotated" ), wxT( "unannotated" ) ); @@ -274,6 +278,7 @@ std::vector<std::reference_wrapper<RC_ITEM>> ERC_ITEM::allItemTypes( ERC_ITEM::libSymbolIssues, ERC_ITEM::libSymbolMismatch, ERC_ITEM::footprintLinkIssues, + ERC_ITEM::footprintFilters, ERC_ITEM::extraUnits, ERC_ITEM::missingUnits, ERC_ITEM::missingInputPin, @@ -330,6 +335,7 @@ std::shared_ptr<ERC_ITEM> ERC_ITEM::Create( int aErrorCode ) case ERCE_LIB_SYMBOL_ISSUES: return std::make_shared<ERC_ITEM>( libSymbolIssues ); case ERCE_LIB_SYMBOL_MISMATCH: return std::make_shared<ERC_ITEM>( libSymbolMismatch ); case ERCE_FOOTPRINT_LINK_ISSUES: return std::make_shared<ERC_ITEM>( footprintLinkIssues ); + case ERCE_FOOTPRINT_FILTERS: return std::make_shared<ERC_ITEM>( footprintFilters ); case ERCE_UNANNOTATED: return std::make_shared<ERC_ITEM>( unannotated ); case ERCE_EXTRA_UNITS: return std::make_shared<ERC_ITEM>( extraUnits ); case ERCE_DIFFERENT_UNIT_VALUE: return std::make_shared<ERC_ITEM>( differentUnitValue ); diff --git a/eeschema/erc/erc_item.h b/eeschema/erc/erc_item.h index 97d4e9aa78..3949b65360 100644 --- a/eeschema/erc/erc_item.h +++ b/eeschema/erc/erc_item.h @@ -233,6 +233,7 @@ private: static ERC_ITEM libSymbolIssues; static ERC_ITEM libSymbolMismatch; static ERC_ITEM footprintLinkIssues; + static ERC_ITEM footprintFilters; static ERC_ITEM unannotated; static ERC_ITEM extraUnits; static ERC_ITEM missingUnits; diff --git a/eeschema/erc/erc_report.cpp b/eeschema/erc/erc_report.cpp index 2873b2818d..ab7a36ea61 100644 --- a/eeschema/erc/erc_report.cpp +++ b/eeschema/erc/erc_report.cpp @@ -121,9 +121,6 @@ bool ERC_REPORT::WriteJsonReport( const wxString& aFullFileName ) reportHead.kicad_version = GetMajorMinorPatchVersion(); reportHead.coordinate_units = EDA_UNIT_UTILS::GetLabel( m_reportUnits ); - int err_count = 0; - int warn_count = 0; - int total_count = 0; SCH_SHEET_LIST sheetList = m_sch->BuildSheetListSortedByPageNumbers(); sheetList.FillItemMap( itemMap ); @@ -144,15 +141,6 @@ bool ERC_REPORT::WriteJsonReport( const wxString& aFullFileName ) if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC ) continue; - total_count++; - - switch( severity ) - { - case RPT_SEVERITY_ERROR: err_count++; break; - case RPT_SEVERITY_WARNING: warn_count++; break; - default: break; - } - RC_JSON::VIOLATION violation; marker->GetRCItem()->GetJsonViolation( violation, &unitsProvider, severity, itemMap ); @@ -162,7 +150,6 @@ bool ERC_REPORT::WriteJsonReport( const wxString& aFullFileName ) reportHead.sheets.push_back( jsonSheet ); } - nlohmann::json saveJson = nlohmann::json( reportHead ); jsonFileStream << std::setw( 4 ) << saveJson << std::endl; jsonFileStream.flush(); diff --git a/eeschema/erc/erc_settings.cpp b/eeschema/erc/erc_settings.cpp index 19f5a4830a..9449ddcab1 100644 --- a/eeschema/erc/erc_settings.cpp +++ b/eeschema/erc/erc_settings.cpp @@ -107,6 +107,7 @@ ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) : m_ERCSeverities[ERCE_LIB_SYMBOL_ISSUES] = RPT_SEVERITY_WARNING; m_ERCSeverities[ERCE_LIB_SYMBOL_MISMATCH] = RPT_SEVERITY_WARNING; m_ERCSeverities[ERCE_FOOTPRINT_LINK_ISSUES] = RPT_SEVERITY_WARNING; + m_ERCSeverities[ERCE_FOOTPRINT_FILTERS] = RPT_SEVERITY_IGNORE; m_ERCSeverities[ERCE_NOCONNECT_CONNECTED] = RPT_SEVERITY_WARNING; m_ERCSeverities[ERCE_NOCONNECT_NOT_CONNECTED] = RPT_SEVERITY_WARNING; m_ERCSeverities[ERCE_MISSING_UNIT] = RPT_SEVERITY_WARNING; diff --git a/eeschema/erc/erc_settings.h b/eeschema/erc/erc_settings.h index 1ebcc850d2..b0fd68eb0d 100644 --- a/eeschema/erc/erc_settings.h +++ b/eeschema/erc/erc_settings.h @@ -78,6 +78,7 @@ enum ERCE_T ERCE_LIB_SYMBOL_MISMATCH, ///< Symbol doesn't match copy in library. ERCE_FOOTPRINT_LINK_ISSUES, ///< The footprint link is invalid, or points to a missing ///< (or inactive) footprint or library. + ERCE_FOOTPRINT_FILTERS, ///< The assigned footprint doesn't match the footprint filters ERCE_UNANNOTATED, ///< Symbol has not been annotated. ERCE_EXTRA_UNITS, ///< Symbol has more units than are defined. ERCE_DIFFERENT_UNIT_VALUE, ///< Units of same symbol have different values. diff --git a/pcbnew/board_design_settings.cpp b/pcbnew/board_design_settings.cpp index cdb848cc4a..f6df75113d 100644 --- a/pcbnew/board_design_settings.cpp +++ b/pcbnew/board_design_settings.cpp @@ -179,7 +179,8 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS( JSON_SETTINGS* aParent, const std: m_DRCSeverities[ DRCE_DUPLICATE_FOOTPRINT ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_EXTRA_FOOTPRINT ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_NET_CONFLICT ] = RPT_SEVERITY_WARNING; - m_DRCSeverities[ DRCE_SCHEMATIC_PARITY_ISSUES ] = RPT_SEVERITY_WARNING; + m_DRCSeverities[ DRCE_SCHEMATIC_PARITY ] = RPT_SEVERITY_WARNING; + m_DRCSeverities[ DRCE_FOOTPRINT_FILTERS ] = RPT_SEVERITY_IGNORE; m_DRCSeverities[ DRCE_OVERLAPPING_SILK ] = RPT_SEVERITY_WARNING; m_DRCSeverities[ DRCE_SILK_CLEARANCE ] = RPT_SEVERITY_WARNING; diff --git a/pcbnew/dialogs/dialog_drc.cpp b/pcbnew/dialogs/dialog_drc.cpp index 5f17bf5c7c..5fa142a3c6 100644 --- a/pcbnew/dialogs/dialog_drc.cpp +++ b/pcbnew/dialogs/dialog_drc.cpp @@ -1309,7 +1309,8 @@ void DIALOG_DRC::updateDisplayedCounts() || ii == DRCE_DUPLICATE_FOOTPRINT || ii == DRCE_EXTRA_FOOTPRINT || ii == DRCE_NET_CONFLICT - || ii == DRCE_SCHEMATIC_PARITY_ISSUES ) + || ii == DRCE_SCHEMATIC_PARITY + || ii == DRCE_FOOTPRINT_FILTERS ) { if( showWarnings && bds.GetSeverity( ii ) == RPT_SEVERITY_WARNING ) footprintsOverflowed = true; diff --git a/pcbnew/drc/drc_item.cpp b/pcbnew/drc/drc_item.cpp index e03fa6cc38..0604cce4ca 100644 --- a/pcbnew/drc/drc_item.cpp +++ b/pcbnew/drc/drc_item.cpp @@ -186,10 +186,14 @@ DRC_ITEM DRC_ITEM::netConflict( DRCE_NET_CONFLICT, _( "Pad net doesn't match schematic" ), wxT( "net_conflict" ) ); -DRC_ITEM DRC_ITEM::schematicParityIssues( DRCE_SCHEMATIC_PARITY_ISSUES, +DRC_ITEM DRC_ITEM::schematicParity( DRCE_SCHEMATIC_PARITY, _( "Footprint attributes don't match symbol" ), wxT( "footprint_symbol_mismatch" ) ); +DRC_ITEM DRC_ITEM::footprintFilters( DRCE_FOOTPRINT_FILTERS, + _( "Footprint doesn't match symbol's footprint filters" ), + wxT( "footprint_filters_mismatch" ) ); + DRC_ITEM DRC_ITEM::libFootprintIssues( DRCE_LIB_FOOTPRINT_ISSUES, _( "Footprint not found in libraries" ), wxT( "lib_footprint_issues" ) ); @@ -307,7 +311,8 @@ std::vector<std::reference_wrapper<RC_ITEM>> DRC_ITEM::allItemTypes( DRC_ITEM::duplicateFootprints, DRC_ITEM::missingFootprint, DRC_ITEM::extraFootprint, - DRC_ITEM::schematicParityIssues, + DRC_ITEM::schematicParity, + DRC_ITEM::footprintFilters, DRC_ITEM::netConflict, DRC_ITEM::unconnectedItems, @@ -387,7 +392,8 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode ) case DRCE_DUPLICATE_FOOTPRINT: return std::make_shared<DRC_ITEM>( duplicateFootprints ); case DRCE_NET_CONFLICT: return std::make_shared<DRC_ITEM>( netConflict ); case DRCE_EXTRA_FOOTPRINT: return std::make_shared<DRC_ITEM>( extraFootprint ); - case DRCE_SCHEMATIC_PARITY_ISSUES: return std::make_shared<DRC_ITEM>( schematicParityIssues ); + case DRCE_SCHEMATIC_PARITY: return std::make_shared<DRC_ITEM>( schematicParity ); + case DRCE_FOOTPRINT_FILTERS: return std::make_shared<DRC_ITEM>( footprintFilters ); case DRCE_LIB_FOOTPRINT_ISSUES: return std::make_shared<DRC_ITEM>( libFootprintIssues ); case DRCE_LIB_FOOTPRINT_MISMATCH: return std::make_shared<DRC_ITEM>( libFootprintMismatch ); case DRCE_UNRESOLVED_VARIABLE: return std::make_shared<DRC_ITEM>( unresolvedVariable ); diff --git a/pcbnew/drc/drc_item.h b/pcbnew/drc/drc_item.h index 4c99af6bb5..4efe624a26 100644 --- a/pcbnew/drc/drc_item.h +++ b/pcbnew/drc/drc_item.h @@ -72,7 +72,8 @@ enum PCB_DRC_CODE { DRCE_DUPLICATE_FOOTPRINT, // more than one footprints found for netlist item DRCE_EXTRA_FOOTPRINT, // netlist item not found for footprint DRCE_NET_CONFLICT, // pad net doesn't match netlist - DRCE_SCHEMATIC_PARITY_ISSUES, // footprint attributes don't match symbol attributes + DRCE_SCHEMATIC_PARITY, // footprint attributes don't match symbol attributes + DRCE_FOOTPRINT_FILTERS, // footprint doesn't match symbol's footprint filters DRCE_FOOTPRINT_TYPE_MISMATCH, // footprint attribute does not match actual pads DRCE_LIB_FOOTPRINT_ISSUES, // footprint not found in active libraries @@ -206,7 +207,8 @@ private: static DRC_ITEM missingFootprint; static DRC_ITEM extraFootprint; static DRC_ITEM netConflict; - static DRC_ITEM schematicParityIssues; + static DRC_ITEM schematicParity; + static DRC_ITEM footprintFilters; static DRC_ITEM libFootprintIssues; static DRC_ITEM libFootprintMismatch; static DRC_ITEM unresolvedVariable; diff --git a/pcbnew/drc/drc_test_provider_schematic_parity.cpp b/pcbnew/drc/drc_test_provider_schematic_parity.cpp index 4fe37b4a8a..4ea336f376 100644 --- a/pcbnew/drc/drc_test_provider_schematic_parity.cpp +++ b/pcbnew/drc/drc_test_provider_schematic_parity.cpp @@ -38,7 +38,8 @@ - DRCE_MISSING_FOOTPRINT - DRCE_DUPLICATE_FOOTPRINT - DRCE_EXTRA_FOOTPRINT - - DRCE_SCHEMATIC_PARITY_ISSUES + - DRCE_SCHEMATIC_PARITY + - DRCE_FOOTPRINT_FILTERS TODO: - cross-check PCB netlist against SCH netlist @@ -126,43 +127,64 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist ) else { if( component->GetValue() != footprint->GetValue() - && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY_ISSUES ) ) + && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY ) ) { wxString msg; - msg.Printf( _( "Footprint %s value (%s) doesn't match symbol value (%s)." ), + msg.Printf( _( "Value (%s) doesn't match symbol value (%s)." ), footprint->GetReference(), footprint->GetValue(), component->GetValue() ); - std::shared_ptr<DRC_ITEM> drcItem = - DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY_ISSUES ); + std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY ); drcItem->SetErrorMessage( msg ); drcItem->SetItems( footprint ); reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); } if( component->GetFPID().GetUniStringLibId() != footprint->GetFPID().GetUniStringLibId() - && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY_ISSUES ) ) + && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY ) ) { wxString msg; - msg.Printf( _( "%s footprint (%s) doesn't match that given by symbol (%s)." ), - footprint->GetReference(), footprint->GetFPID().GetUniStringLibId(), + msg.Printf( _( "%s doesn't match footprint given by symbol (%s)." ), + footprint->GetFPID().GetUniStringLibId(), component->GetFPID().GetUniStringLibId() ); - std::shared_ptr<DRC_ITEM> drcItem = - DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY_ISSUES ); + std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY ); drcItem->SetErrorMessage( msg ); drcItem->SetItems( footprint ); reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); } + if( !m_drcEngine->IsErrorLimitExceeded( DRCE_FOOTPRINT_FILTERS ) ) + { + wxString fpName = footprint->GetFPID().GetUniStringLibItemName(); + size_t filtercount = component->GetFootprintFilters().GetCount(); + bool found = ( 0 == filtercount ); // if no entries, do not filter + + for( size_t jj = 0; jj < filtercount && !found; jj++ ) + found = fpName.Matches( component->GetFootprintFilters()[jj] ); + + if( !found ) + { + wxString msg; + msg.Printf( _( "%s doesn't match symbol's footprint filters (%s)." ), + fpName, + wxJoin( component->GetFootprintFilters(), ' ' ) ); + + std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_FOOTPRINT_FILTERS ); + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( footprint ); + reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); + } + } + if( ( component->GetProperties().count( "dnp" ) > 0 ) != ( ( footprint->GetAttributes() & FP_DNP ) > 0 ) - && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY_ISSUES ) ) + && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY ) ) { wxString msg; msg.Printf( _( "'%s' settings differ." ), _( "Do not populate" ) ); - std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY_ISSUES ); + std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY ); drcItem->SetErrorMessage( drcItem->GetErrorMessage() + wxS( ": " ) + msg ); drcItem->SetItems( footprint ); reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); @@ -170,12 +192,12 @@ void DRC_TEST_PROVIDER_SCHEMATIC_PARITY::testNetlist( NETLIST& aNetlist ) if( ( component->GetProperties().count( "exclude_from_bom" ) > 0 ) != ( (footprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) > 0 ) - && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY_ISSUES ) ) + && !m_drcEngine->IsErrorLimitExceeded( DRCE_SCHEMATIC_PARITY ) ) { wxString msg; msg.Printf( _( "'%s' settings differ." ), _( "Exclude from bill of materials" ) ); - std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY_ISSUES ); + std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_SCHEMATIC_PARITY ); drcItem->SetErrorMessage( drcItem->GetErrorMessage() + wxS( ": " ) + msg ); drcItem->SetItems( footprint ); reportViolation( drcItem, footprint->GetPosition(), UNDEFINED_LAYER ); diff --git a/pcbnew/pcb_marker.cpp b/pcbnew/pcb_marker.cpp index 032548843b..b7636fef6e 100644 --- a/pcbnew/pcb_marker.cpp +++ b/pcbnew/pcb_marker.cpp @@ -68,7 +68,8 @@ PCB_MARKER::PCB_MARKER( std::shared_ptr<RC_ITEM> aItem, const VECTOR2I& aPositio case DRCE_DUPLICATE_FOOTPRINT: case DRCE_EXTRA_FOOTPRINT: case DRCE_NET_CONFLICT: - case DRCE_SCHEMATIC_PARITY_ISSUES: + case DRCE_SCHEMATIC_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 904447a85f..221f7a307f 100644 --- a/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp +++ b/pcbnew/python/scripting/pcbnew_scripting_helpers.cpp @@ -597,7 +597,8 @@ bool WriteDRCReport( BOARD* aBoard, const wxString& aFileName, EDA_UNITS aUnits, || aItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT || aItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT || aItem->GetErrorCode() == DRCE_NET_CONFLICT - || aItem->GetErrorCode() == DRCE_SCHEMATIC_PARITY_ISSUES ) + || aItem->GetErrorCode() == DRCE_SCHEMATIC_PARITY + || aItem->GetErrorCode() == DRCE_FOOTPRINT_FILTERS ) { footprints.push_back( aItem ); }