ADDED: Implement footprint link checking in ERC.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/16842
This commit is contained in:
Jeff Young 2024-02-01 17:29:16 +00:00
parent 6dc60598da
commit e760317af6
9 changed files with 116 additions and 11 deletions

View File

@ -27,6 +27,7 @@
#include <numeric>
#include "connection_graph.h"
#include "kiface_ids.h"
#include <advanced_config.h>
#include <common.h> // for ExpandEnvVarSubstitutions
#include <erc.h>
@ -958,7 +959,7 @@ int ERC_TESTER::TestLibSymbolIssues()
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LIB_SYMBOL_ISSUES );
ercItem->SetItems( symbol );
msg.Printf( _( "The current configuration does not include the library '%s'" ),
msg.Printf( _( "The current configuration does not include the symbol library '%s'" ),
UnescapeString( libName ) );
ercItem->SetErrorMessage( msg );
@ -1020,6 +1021,86 @@ int ERC_TESTER::TestLibSymbolIssues()
}
int ERC_TESTER::TestFootprintLinkIssues( KIFACE* aCvPcb, PROJECT* aProject )
{
wxCHECK( m_schematic, 0 );
wxString msg;
int err_count = 0;
typedef int (*TESTER_FN_PTR)( const wxString&, PROJECT* );
TESTER_FN_PTR linkTester = (TESTER_FN_PTR) aCvPcb->IfaceOrAddress( KIFACE_TEST_FOOTPRINT_LINK );
for( SCH_SHEET_PATH& sheet : m_schematic->GetSheets() )
{
std::vector<SCH_MARKER*> markers;
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
{
SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
wxString footprint = symbol->GetFootprintFieldText( true, &sheet, false );
if( footprint.IsEmpty() )
continue;
LIB_ID fpID;
if( fpID.Parse( footprint, true ) >= 0 )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_FOOTPRINT_LINK_ISSUES );
msg.Printf( _( "'%s' is not a valid footprint identifier." ), footprint );
ercItem->SetErrorMessage( msg );
ercItem->SetItems( symbol );
markers.emplace_back( new SCH_MARKER( ercItem, symbol->GetPosition() ) );
continue;
}
wxString libName = fpID.GetLibNickname();
wxString fpName = fpID.GetLibItemName();
int ret = (linkTester)( footprint, aProject );
if( ret == KIFACE_TEST_FOOTPRINT_LINK_NO_LIBRARY )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_FOOTPRINT_LINK_ISSUES );
msg.Printf( _( "The current configuration does not include the footprint library '%s'." ),
libName );
ercItem->SetErrorMessage( msg );
ercItem->SetItems( symbol );
markers.emplace_back( new SCH_MARKER( ercItem, symbol->GetPosition() ) );
}
else if( ret == KIFACE_TEST_FOOTPRINT_LINK_LIBRARY_NOT_ENABLED )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_FOOTPRINT_LINK_ISSUES );
msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration." ),
libName );
ercItem->SetErrorMessage( msg );
ercItem->SetItems( symbol );
markers.emplace_back( new SCH_MARKER( ercItem, symbol->GetPosition() ) );
}
else if( ret == KIFACE_TEST_FOOTPRINT_LINK_NO_FOOTPRINT )
{
std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_FOOTPRINT_LINK_ISSUES );
msg.Printf( _( "Footprint '%s' not found in library '%s'." ),
fpName,
libName );
ercItem->SetErrorMessage( msg );
ercItem->SetItems( symbol );
markers.emplace_back( new SCH_MARKER( ercItem, 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;
@ -1250,6 +1331,14 @@ void ERC_TESTER::RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aE
TestLibSymbolIssues();
}
if( settings.IsTestEnabled( ERCE_FOOTPRINT_LINK_ISSUES ) && aCvPcb )
{
if( aProgressReporter )
aProgressReporter->AdvancePhase( _( "Checking for footprint link issues..." ) );
TestFootprintLinkIssues( aCvPcb, aProject );
}
if( settings.IsTestEnabled( ERCE_ENDPOINT_OFF_GRID ) )
{
if( aProgressReporter )

View File

@ -113,6 +113,12 @@ public:
*/
int TestLibSymbolIssues();
/**
* Test footprint links against the current footprint libraries.
* @return the number of issues found
*/
int TestFootprintLinkIssues( KIFACE* aCvPcb, PROJECT* aProject );
/**
* Test pins and wire ends for being off grid.
* @return the error count

View File

@ -151,6 +151,10 @@ ERC_ITEM ERC_ITEM::libSymbolIssues( ERCE_LIB_SYMBOL_ISSUES,
_( "Library symbol issue" ),
wxT( "lib_symbol_issues" ) );
ERC_ITEM ERC_ITEM::footprintLinkIssues( ERCE_FOOTPRINT_LINK_ISSUES,
_( "Footprint link issue" ),
wxT( "footprint_link_issues" ) );
ERC_ITEM ERC_ITEM::unannotated( ERCE_UNANNOTATED,
_( "Symbol is not annotated" ),
wxT( "unannotated" ) );
@ -224,6 +228,7 @@ std::vector<std::reference_wrapper<RC_ITEM>> ERC_ITEM::allItemTypes( {
// TODO: Add bus label syntax checking
// ERC_ITEM::busLabelSyntax,
ERC_ITEM::libSymbolIssues,
ERC_ITEM::footprintLinkIssues,
ERC_ITEM::extraUnits,
ERC_ITEM::missingUnits,
ERC_ITEM::missingInputPin,
@ -264,6 +269,7 @@ std::shared_ptr<ERC_ITEM> ERC_ITEM::Create( int aErrorCode )
case ERCE_SIMULATION_MODEL: return std::make_shared<ERC_ITEM>( simulationModelIssues );
case ERCE_WIRE_DANGLING: return std::make_shared<ERC_ITEM>( wireDangling );
case ERCE_LIB_SYMBOL_ISSUES: return std::make_shared<ERC_ITEM>( libSymbolIssues );
case ERCE_FOOTPRINT_LINK_ISSUES: return std::make_shared<ERC_ITEM>( footprintLinkIssues );
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 );

View File

@ -210,6 +210,7 @@ private:
static ERC_ITEM simulationModelIssues;
static ERC_ITEM wireDangling;
static ERC_ITEM libSymbolIssues;
static ERC_ITEM footprintLinkIssues;
static ERC_ITEM unannotated;
static ERC_ITEM extraUnits;
static ERC_ITEM missingUnits;

View File

@ -101,6 +101,7 @@ ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
m_ERCSeverities[ERCE_DRIVER_CONFLICT] = RPT_SEVERITY_WARNING;
m_ERCSeverities[ERCE_BUS_ENTRY_CONFLICT] = RPT_SEVERITY_WARNING;
m_ERCSeverities[ERCE_LIB_SYMBOL_ISSUES] = RPT_SEVERITY_WARNING;
m_ERCSeverities[ERCE_FOOTPRINT_LINK_ISSUES] = RPT_SEVERITY_WARNING;
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;

View File

@ -74,6 +74,8 @@ enum ERCE_T
ERCE_WIRE_DANGLING, ///< Some wires are not connected to anything else.
ERCE_LIB_SYMBOL_ISSUES, ///< Library symbol changed from current symbol in schematic or
///< the library symbol link no longer valid.
ERCE_FOOTPRINT_LINK_ISSUES, ///< The footprint link is invalid, or points to a missing
///< (or inactive) footprint or library.
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.

View File

@ -1406,9 +1406,9 @@ void SYMBOL_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
if( !libTableRow )
{
msg.Printf( _( "The current configuration does not include the library '%s'.\n"
"Use Manage Symbol Libraries to edit the configuration." ),
msg.Printf( _( "The current configuration does not include the symbol library '%s'." ),
libFileName );
msg += wxS( "\n" ) + _( "Use Manage Symbol Libraries to edit the configuration." );
DisplayErrorMessage( this, _( "Library not found in symbol library table." ), msg );
break;
}
@ -1417,9 +1417,9 @@ void SYMBOL_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
if( !libTable->HasLibrary( libNickname, true ) )
{
msg.Printf( _( "The library '%s' is not enabled in the current configuration.\n"
"Use Manage Symbol Libraries to edit the configuration." ),
msg.Printf( _( "The symbol library '%s' is not enabled in the current configuration." ),
UnescapeString( libNickname ) );
msg += wxS( "\n" ) + _( "Use Manage Symbol Libraries to edit the configuration." );
DisplayErrorMessage( this, _( "Symbol library not enabled." ), msg );
break;
}

View File

@ -840,7 +840,7 @@ bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
msg.Printf( _( "The current configuration does not include the library '%s'." ),
msg.Printf( _( "The current configuration does not include the footprint library '%s'." ),
libName );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );
@ -854,7 +854,7 @@ bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
{
std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
msg.Printf( _( "The library '%s' is not enabled in the current configuration." ),
msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration." ),
libName );
drcItem->SetErrorMessage( msg );
drcItem->SetItems( footprint );

View File

@ -323,9 +323,9 @@ void FOOTPRINT_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
if( !libTableRow )
{
msg.Printf( _( "The current configuration does not include a library named '%s'.\n"
"Use Manage Footprint Libraries to edit the configuration." ),
msg.Printf( _( "The current configuration does not include the footprint library '%s'." ),
fpFileName.GetPath() );
msg += wxS( "\n" ) + _( "Use Manage Footprint Libraries to edit the configuration." );
DisplayErrorMessage( this, _( "Library not found in footprint library table." ),
msg );
break;
@ -335,9 +335,9 @@ void FOOTPRINT_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
if( !libTable->HasLibrary( libNickname, true ) )
{
msg.Printf( _( "The library '%s' is not enabled in the current configuration.\n"
"Use Manage Footprint Libraries to edit the configuration." ),
msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration." ),
libNickname );
msg += wxS( "\n" ) + _( "Use Manage Footprint Libraries to edit the configuration." );
DisplayErrorMessage( this, _( "Footprint library not enabled." ), msg );
break;
}