From b94e29e3b1124d850416300c0c4c5b456e9a7f4e Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Fri, 3 Jul 2020 17:08:17 -0400 Subject: [PATCH] Persist ERC pin table in project settings Fixes https://gitlab.com/kicad/code/kicad/-/issues/2066 Also a partial fix for https://gitlab.com/kicad/code/kicad/-/issues/4577 --- eeschema/dialogs/dialog_erc.cpp | 13 +- eeschema/dialogs/panel_setup_pinmap.cpp | 45 +++---- eeschema/dialogs/panel_setup_pinmap.h | 4 +- eeschema/erc.cpp | 117 +++++------------- eeschema/erc.h | 157 +++++++++--------------- eeschema/erc_item.cpp | 12 +- eeschema/erc_item.h | 3 +- eeschema/erc_settings.cpp | 115 ++++++++++++++++- eeschema/erc_settings.h | 93 +++++++++++++- eeschema/netlist_generator.cpp | 9 +- eeschema/tools/sch_editor_control.cpp | 4 +- 11 files changed, 344 insertions(+), 228 deletions(-) diff --git a/eeschema/dialogs/dialog_erc.cpp b/eeschema/dialogs/dialog_erc.cpp index dff0d437e2..2eba6814b6 100644 --- a/eeschema/dialogs/dialog_erc.cpp +++ b/eeschema/dialogs/dialog_erc.cpp @@ -196,19 +196,20 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter ) SCH_SCREENS screens( sch->Root() ); ERC_SETTINGS& settings = sch->ErcSettings(); + ERC_TESTER tester( sch ); // Test duplicate sheet names inside a given sheet. While one can have multiple references // to the same file, each must have a unique name. if( settings.IsTestEnabled( ERCE_DUPLICATE_SHEET_NAME ) ) { aReporter.ReportTail( _( "Checking sheet names...\n" ), RPT_SEVERITY_INFO ); - TestDuplicateSheetNames( sch, true ); + tester.TestDuplicateSheetNames( true ); } if( settings.IsTestEnabled( ERCE_BUS_ALIAS_CONFLICT ) ) { aReporter.ReportTail( _( "Checking bus conflicts...\n" ), RPT_SEVERITY_INFO ); - TestConflictingBusAliases( sch ); + tester.TestConflictingBusAliases(); } // The connection graph has a whole set of ERC checks it can run @@ -220,8 +221,8 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter ) if( settings.IsTestEnabled( ERCE_DIFFERENT_UNIT_FP ) ) { aReporter.ReportTail( _( "Checking footprints...\n" ), RPT_SEVERITY_INFO ); - SCH_SHEET_LIST sheets = sch->GetSheets(); - TestMultiunitFootprints( sheets ); + + tester.TestMultiunitFootprints(); } std::unique_ptr objectsConnectedList( m_parent->BuildNetListBase() ); @@ -304,7 +305,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter ) } // Look for ERC problems between pins: - TestOthersItems( objectsConnectedList.get(), itemIdx, nextItemIdx, &MinConn ); + tester.TestOthersItems( objectsConnectedList.get(), itemIdx, nextItemIdx, &MinConn ); break; } default: @@ -323,7 +324,7 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter ) } if( settings.IsTestEnabled( ERCE_UNRESOLVED_VARIABLE ) ) - TestTextVars( sch, m_parent->GetCanvas()->GetView()->GetWorksheet() ); + tester.TestTextVars( m_parent->GetCanvas()->GetView()->GetWorksheet() ); // Display diags: m_markerTreeModel->SetProvider( m_markerProvider ); diff --git a/eeschema/dialogs/panel_setup_pinmap.cpp b/eeschema/dialogs/panel_setup_pinmap.cpp index 666033760f..2eb4b034b4 100644 --- a/eeschema/dialogs/panel_setup_pinmap.cpp +++ b/eeschema/dialogs/panel_setup_pinmap.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,11 +42,6 @@ #include #include -extern int PinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; -extern int DefaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; - - -bool PANEL_SETUP_PINMAP::m_diagErcTableInit = false; // saved only for the current session // Control identifiers for events #define ID_MATRIX_0 1800 @@ -63,7 +59,8 @@ PANEL_SETUP_PINMAP::PANEL_SETUP_PINMAP( wxWindow* aWindow, SCH_EDIT_FRAME* paren m_buttonList(), m_initialized( false ) { - m_parent = parent; + m_parent = parent; + m_schematic = &parent->Schematic(); wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); infoFont.SetSymbolicSize( wxFONTSIZE_SMALL ); @@ -74,7 +71,7 @@ PANEL_SETUP_PINMAP::PANEL_SETUP_PINMAP( wxWindow* aWindow, SCH_EDIT_FRAME* paren void PANEL_SETUP_PINMAP::OnResetMatrixClick( wxCommandEvent& aEvent ) { - memcpy( PinMap, DefaultPinMap, sizeof( PinMap ) ); + m_schematic->ErcSettings().ResetPinMap(); ReBuildMatrixPanel(); } @@ -86,12 +83,6 @@ void PANEL_SETUP_PINMAP::ReBuildMatrixPanel() wxSize bitmap_size = dummy->GetSize(); delete dummy; - if( !m_diagErcTableInit ) - { - memcpy( PinMap, DefaultPinMap, sizeof(DefaultPinMap) ); - m_diagErcTableInit = true; - } - wxPoint pos; // Get the current text size using a dummy text. wxStaticText* text = new wxStaticText( m_matrixPanel, -1, CommentERC_V[0], pos ); @@ -140,16 +131,16 @@ void PANEL_SETUP_PINMAP::ReBuildMatrixPanel() for( int jj = 0; jj <= ii; jj++ ) { // Add column labels (only once) - int diag = PinMap[ii][jj]; - int x = pos.x + ( jj * ( bitmap_size.x + 4 ) ); + PIN_ERROR diag = m_schematic->ErcSettings().GetPinMapValue( ii, jj ); - if( (ii == jj) && !m_initialized ) + int x = pos.x + ( jj * ( bitmap_size.x + 4 ) ); + + if( ( ii == jj ) && !m_initialized ) { wxPoint txtpos; - txtpos.x = x + (bitmap_size.x / 2); + txtpos.x = x + ( bitmap_size.x / 2 ); txtpos.y = y - text_height; - new WX_ANGLE_TEXT( m_matrixPanel, wxID_ANY, CommentERC_V[ii], - txtpos, 450 ); + new WX_ANGLE_TEXT( m_matrixPanel, wxID_ANY, CommentERC_V[ii], txtpos, 450 ); } int event_id = ID_MATRIX_0 + ii + ( jj * ELECTRICAL_PINTYPES_TOTAL ); @@ -189,24 +180,24 @@ bool PANEL_SETUP_PINMAP::Show( bool show ) } -void PANEL_SETUP_PINMAP::setDRCMatrixButtonState( wxBitmapButton *aButton, int aState ) +void PANEL_SETUP_PINMAP::setDRCMatrixButtonState( wxBitmapButton *aButton, PIN_ERROR aState ) { BITMAP_DEF bitmap_butt = nullptr; wxString tooltip; switch( aState ) { - case OK: + case PIN_ERROR::OK: bitmap_butt = erc_green_xpm; tooltip = _( "No error or warning" ); break; - case WAR: + case PIN_ERROR::WARNING: bitmap_butt = ercwarn_xpm; tooltip = _( "Generate warning" ); break; - case ERR: + case PIN_ERROR::ERROR: bitmap_butt = ercerr_xpm; tooltip = _( "Generate error" ); break; @@ -231,11 +222,13 @@ void PANEL_SETUP_PINMAP::ChangeErrorLevel( wxCommandEvent& event ) int y = ii % ELECTRICAL_PINTYPES_TOTAL; wxBitmapButton* butt = (wxBitmapButton*) event.GetEventObject(); - int level = ( PinMap[y][x] + 1 ) % 3; + int level = static_cast( m_schematic->ErcSettings().GetPinMapValue( y, x ) ); + level = ( level + 1 ) % 3; - setDRCMatrixButtonState( butt, level ); + setDRCMatrixButtonState( butt, static_cast( level ) ); - PinMap[y][x] = PinMap[x][y] = level; + m_schematic->ErcSettings().SetPinMapValue( y, x, static_cast( level ) ); + m_schematic->ErcSettings().SetPinMapValue( x, y, static_cast( level ) ); } diff --git a/eeschema/dialogs/panel_setup_pinmap.h b/eeschema/dialogs/panel_setup_pinmap.h index 7e54f32e7a..5fa828ca74 100644 --- a/eeschema/dialogs/panel_setup_pinmap.h +++ b/eeschema/dialogs/panel_setup_pinmap.h @@ -32,6 +32,7 @@ class SCH_EDIT_FRAME; +class SCHEMATIC; class PANEL_SETUP_PINMAP : public PANEL_SETUP_PINMAP_BASE @@ -40,6 +41,7 @@ class PANEL_SETUP_PINMAP : public PANEL_SETUP_PINMAP_BASE private: SCH_EDIT_FRAME* m_parent; + SCHEMATIC* m_schematic; wxBitmapButton* m_buttonList[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; bool m_initialized; static bool m_diagErcTableInit; // go to true after DiagErc init @@ -54,7 +56,7 @@ private: void ChangeErrorLevel( wxCommandEvent& event ); void ReBuildMatrixPanel(); - void setDRCMatrixButtonState( wxBitmapButton *aButton, int aState ); + void setDRCMatrixButtonState( wxBitmapButton *aButton, PIN_ERROR aState ); }; diff --git a/eeschema/erc.cpp b/eeschema/erc.cpp index 6f929c8c82..61d131f6a2 100644 --- a/eeschema/erc.cpp +++ b/eeschema/erc.cpp @@ -98,72 +98,14 @@ const wxString CommentERC_V[] = }; -/* Look up table which gives the diag for a pair of connected pins - * Can be modified by ERC options. - * at start up: must be loaded by DefaultDiagErc - * Can be modified in dialog ERC - */ -int PinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; - -/** - * Default Look up table which gives the ERC error level for a pair of connected pins - * Same as DiagErc, but cannot be modified. - * Used to init or reset DiagErc - * note also, to avoid inconsistancy: - * DefaultDiagErc[i][j] = DefaultDiagErc[j][i] - */ -int DefaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL] = -{ -/* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */ -/* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR }, -/* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR }, -/* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR }, -/* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR }, -/*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR }, -/*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR }, -/*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR }, -/*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR }, -/* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR }, -/* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR }, -/* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR } -}; - - -/** - * Look up table which gives the minimal drive for a pair of connected pins on - * a net. - *

- * The initial state of a net is NOC (Net with No Connection). It can be updated to - * NPI (Pin Isolated), NET_NC (Net with a no connect symbol), NOD (Not Driven) or DRV - * (DRIven). It can be updated to NET_NC with no error only if there is only one pin - * in net. Nets are OK when their final state is NET_NC or DRV. Nets with the state - * NOD have no valid source signal. - */ -static int MinimalReq[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL] = -{ -/* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */ -/* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI }, -/* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI }, -/*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI }, -/* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, -/* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI } -}; - - -int TestDuplicateSheetNames( SCHEMATIC* aSchematic, bool aCreateMarker ) +int ERC_TESTER::TestDuplicateSheetNames( bool aCreateMarker ) { SCH_SCREEN* screen; int err_count = 0; - SCH_SCREENS screenList( aSchematic->Root() ); + SCH_SCREENS screenList( m_schematic->Root() ); - for( screen = screenList.GetFirst(); screen != NULL; screen = screenList.GetNext() ) + for( screen = screenList.GetFirst(); screen != nullptr; screen = screenList.GetNext() ) { std::vector list; @@ -202,7 +144,7 @@ int TestDuplicateSheetNames( SCHEMATIC* aSchematic, bool aCreateMarker ) } -void TestTextVars( SCHEMATIC* aSchematic, KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) +void ERC_TESTER::TestTextVars( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) { WS_DRAW_ITEM_LIST wsItems; @@ -212,7 +154,7 @@ void TestTextVars( SCHEMATIC* aSchematic, KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet wsItems.BuildWorkSheetGraphicList( aWorksheet->GetPageInfo(), aWorksheet->GetTitleBlock() ); } - SCH_SCREENS screens( aSchematic->Root() ); + SCH_SCREENS screens( m_schematic->Root() ); for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() ) { @@ -297,12 +239,12 @@ void TestTextVars( SCHEMATIC* aSchematic, KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet } -int TestConflictingBusAliases( SCHEMATIC* aSchematic ) +int ERC_TESTER::TestConflictingBusAliases() { wxString msg; int err_count = 0; - SCH_SCREENS screens( aSchematic->Root() ); + SCH_SCREENS screens( m_schematic->Root() ); std::vector< std::shared_ptr > aliases; for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() ) @@ -338,12 +280,14 @@ int TestConflictingBusAliases( SCHEMATIC* aSchematic ) } -int TestMultiunitFootprints( const SCH_SHEET_LIST& aSheetList ) +int ERC_TESTER::TestMultiunitFootprints() { + SCH_SHEET_LIST sheets = m_schematic->GetSheets(); + int errors = 0; std::map footprints; SCH_MULTI_UNIT_REFERENCE_MAP refMap; - aSheetList.GetMultiUnitComponents( refMap, true ); + sheets.GetMultiUnitComponents( refMap, true ); for( auto& component : refMap ) { @@ -402,9 +346,10 @@ int TestMultiunitFootprints( const SCH_SHEET_LIST& aSheetList ) } -void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, int aMinConn, int aDiag ) +void ERC_TESTER::diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, int aMinConn, + PIN_ERROR aDiag ) { - if( aDiag == OK || aMinConn < 1 || aNetItemRef->m_Type != NETLIST_ITEM::PIN ) + if( aDiag == PIN_ERROR::OK || aMinConn < 1 || aNetItemRef->m_Type != NETLIST_ITEM::PIN ) return; SCH_PIN* pin = static_cast( aNetItemRef->m_Comp ); @@ -424,8 +369,8 @@ void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, int aMi if( aNetItemTst && aNetItemTst->m_Type == NETLIST_ITEM::PIN ) /* Error between 2 pins */ { - ERC_ITEM* ercItem = ERC_ITEM::Create( aDiag == ERR ? ERCE_PIN_TO_PIN_ERROR - : ERCE_PIN_TO_PIN_WARNING ); + ERC_ITEM* ercItem = ERC_ITEM::Create( aDiag == PIN_ERROR::ERROR ? + ERCE_PIN_TO_PIN_ERROR : ERCE_PIN_TO_PIN_WARNING ); ercItem->SetItems( pin, static_cast( aNetItemTst->m_Comp ) ); SCH_MARKER* marker = new SCH_MARKER( ercItem, aNetItemRef->m_Start ); @@ -434,12 +379,14 @@ void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst, int aMi } -void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aNetStart, - int* aMinConnexion ) +void ERC_TESTER::TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, + unsigned aNetStart, int* aMinConnexion ) { + ERC_SETTINGS& settings = m_schematic->ErcSettings(); + unsigned netItemTst = aNetStart; ELECTRICAL_PINTYPE jj; - int erc = OK; + PIN_ERROR erc = PIN_ERROR::OK; /* Analysis of the table of connections. */ ELECTRICAL_PINTYPE ref_elect_type = aList->GetItem( aNetItemRef )->m_ElectricalPinType; @@ -457,11 +404,11 @@ void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned if( netItemTst < aList->size() ) { ELECTRICAL_PINTYPE test_elect_type = aList->GetItem( netItemTst )->m_ElectricalPinType; - erc = PinMap[static_cast( ref_elect_type )][static_cast(test_elect_type )]; + erc = settings.GetPinMapValue( ref_elect_type, test_elect_type ); } - if( erc != OK ) - Diagnose( aList->GetItem( aNetItemRef ), aList->GetItem( netItemTst ), 1, erc ); + if( erc != PIN_ERROR::OK ) + diagnose( aList->GetItem( aNetItemRef ), aList->GetItem( netItemTst ), 1, erc ); // We examine only a given net. We stop the search if the net changes if( ( netItemTst >= aList->size() ) // End of list @@ -518,7 +465,10 @@ void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned } if( seterr ) - Diagnose( aList->GetItem( aNetItemRef ), NULL, local_minconn, WAR ); + { + diagnose( aList->GetItem( aNetItemRef ), nullptr, local_minconn, + PIN_ERROR::WARNING ); + } *aMinConnexion = DRV; // inhibiting other messages of this // type for the net. @@ -549,18 +499,17 @@ void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned case NETLIST_ITEM::PIN: jj = aList->GetItem( netItemTst )->m_ElectricalPinType; - local_minconn = std::max( - MinimalReq[static_cast( ref_elect_type )][static_cast( jj )], - local_minconn ); + local_minconn = std::max( settings.GetPinMinDrive( ref_elect_type, jj ), + local_minconn ); if( netItemTst <= aNetItemRef ) break; - if( erc == OK ) + if( erc == PIN_ERROR::OK ) { - erc = PinMap[static_cast( ref_elect_type )][static_cast( jj )]; + erc = settings.GetPinMapValue( ref_elect_type, jj ); - if( erc != OK ) + if( erc != PIN_ERROR::OK ) { if( aList->GetConnectionType( netItemTst ) == NET_CONNECTION::UNCONNECTED ) { diff --git a/eeschema/erc.h b/eeschema/erc.h index 55ef881a91..6a7d2055fc 100644 --- a/eeschema/erc.h +++ b/eeschema/erc.h @@ -30,6 +30,8 @@ #ifndef _ERC_H #define _ERC_H +#include + class NETLIST_OBJECT; class NETLIST_OBJECT_LIST; @@ -41,110 +43,73 @@ namespace KIGFX class WS_PROXY_VIEW_ITEM; } -/* For ERC markers: error types (used in diags, and to set the color): -*/ -enum errortype -{ - OK = 0, - WAR, // Error: severity = warning - ERR, // Error: severity = error - UNC // Error: unconnected pin -}; extern const wxString CommentERC_H[]; extern const wxString CommentERC_V[]; -/// DRC error codes: -enum ERCE_T + +class ERC_TESTER { - ERCE_UNSPECIFIED = 0, - ERCE_FIRST, - ERCE_DUPLICATE_SHEET_NAME = ERCE_FIRST, // duplicate sheet names within a given sheet - ERCE_PIN_NOT_CONNECTED, // pin not connected and not no connect symbol - ERCE_PIN_NOT_DRIVEN, // pin connected to some others pins but no pin to drive it - ERCE_HIERACHICAL_LABEL, // mismatch between hierarchical labels and pins sheets - ERCE_NOCONNECT_CONNECTED, // a no connect symbol is connected to more than 1 pin - ERCE_NOCONNECT_NOT_CONNECTED, // a no connect symbol is not connected to anything - ERCE_LABEL_NOT_CONNECTED, // label not connected to anything - ERCE_SIMILAR_LABELS, // 2 labels are equal fir case insensitive comparisons - ERCE_DIFFERENT_UNIT_FP, // different units of the same component have different footprints assigned - ERCE_DIFFERENT_UNIT_NET, // a shared pin in a multi-unit component is connected to more than one net - ERCE_BUS_ALIAS_CONFLICT, // conflicting bus alias definitions across sheets - ERCE_DRIVER_CONFLICT, // conflicting drivers (labels, etc) on a subgraph - ERCE_BUS_ENTRY_CONFLICT, // a wire connected to a bus doesn't match the bus - ERCE_BUS_LABEL_ERROR, // a label attached to a bus isn't in bus format - ERCE_BUS_TO_BUS_CONFLICT, // a connection between bus objects doesn't share at least one net - ERCE_BUS_TO_NET_CONFLICT, // a bus wire is graphically connected to a net port/pin (or vice versa) - ERCE_GLOBLABEL, // a global label is unique - ERCE_UNRESOLVED_VARIABLE, - ERCE_LAST = ERCE_UNRESOLVED_VARIABLE, +public: - // Errors after this point will not automatically appear in the Severities Panel + ERC_TESTER( SCHEMATIC* aSchematic ) : + m_schematic( aSchematic ) + { + } - ERCE_PIN_TO_PIN_WARNING, // pin connected to an other pin: warning level - ERCE_PIN_TO_PIN_ERROR, // pin connected to an other pin: error level + /** + * Perform ERC testing for electrical conflicts between \a NetItemRef and other items + * (mainly pin) on the same net. + * @param aList = a reference to the list of connected objects + * @param aNetItemRef = index in list of the current object + * @param aNetStart = index in list of net objects of the first item + * @param aMinConnexion = a pointer to a variable to store the minimal connection + * found( NOD, DRV, NPI, NET_NC) + */ + void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aNetStart, + int* aMinConnexion ); + + /** + * inside a given sheet, one cannot have sheets with duplicate names (file + * names can be duplicated). + * @return the error count + * @param aCreateMarker: true = create error markers in schematic, + * false = calculate error count only + */ + int TestDuplicateSheetNames( bool aCreateMarker ); + + /** + * Checks for any unresolved text variable references. + */ + void TestTextVars( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ); + + /** + * Checks that there are not conflicting bus alias definitions in the schematic + * + * (for example, two hierarchical sub-sheets contain different definitions for + * the same bus alias) + * + * @return the error count + */ + int TestConflictingBusAliases(); + + /** + * Test if all units of each multiunit component have the same footprint assigned. + * @return The error count. + */ + int TestMultiunitFootprints(); + +private: + /** + * Performs ERC testing and creates an ERC marker to show the ERC problem for aNetItemRef + * or between aNetItemRef and aNetItemTst. + * if MinConn < 0: this is an error on labels + */ + void diagnose( NETLIST_OBJECT* NetItemRef, NETLIST_OBJECT* NetItemTst, int MinConnexion, + PIN_ERROR Diag ); + + SCHEMATIC* m_schematic; }; -/* Minimal connection table */ -#define NPI 4 // Net with Pin isolated, this pin has type Not Connected and must be left N.C. -#define DRV 3 // Net driven by a signal (a pin output for instance) -#define NET_NC 2 // Net "connected" to a "NoConnect symbol" -#define NOD 1 // Net not driven ( Such as 2 or more connected inputs ) -#define NOC 0 // initial state of a net: no connection - - -/** - * Performs ERC testing and creates an ERC marker to show the ERC problem for aNetItemRef - * or between aNetItemRef and aNetItemTst. - * if MinConn < 0: this is an error on labels - */ -void Diagnose( NETLIST_OBJECT* NetItemRef, NETLIST_OBJECT* NetItemTst, int MinConnexion, - int Diag ); - -/** - * Perform ERC testing for electrical conflicts between \a NetItemRef and other items - * (mainly pin) on the same net. - * @param aList = a reference to the list of connected objects - * @param aNetItemRef = index in list of the current object - * @param aNetStart = index in list of net objects of the first item - * @param aMinConnexion = a pointer to a variable to store the minimal connection - * found( NOD, DRV, NPI, NET_NC) - */ -void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aNetStart, - int* aMinConnexion ); - -/** - * Function TestDuplicateSheetNames( ) - * inside a given sheet, one cannot have sheets with duplicate names (file - * names can be duplicated). - * @return the error count - * @param aCreateMarker: true = create error markers in schematic, - * false = calculate error count only - */ -int TestDuplicateSheetNames( SCHEMATIC* aSchematic, bool aCreateMarker ); - -/** - * Function TestTextVars() - * Checks for any unresolved text variable references. - */ -void TestTextVars( SCHEMATIC* aSchematic, KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ); - -/** - * Checks that there are not conflicting bus alias definitions in the schematic - * - * (for example, two hierarchical sub-sheets contain different definitions for - * the same bus alias) - * - * @return the error count - */ -int TestConflictingBusAliases( SCHEMATIC* aSchematic ); - -/** - * Test if all units of each multiunit component have the same footprint assigned. - * @param aSheetList contains components to be validated. - * @return The error count. - */ -int TestMultiunitFootprints( const SCH_SHEET_LIST& aSheetList ); - #endif // _ERC_H diff --git a/eeschema/erc_item.cpp b/eeschema/erc_item.cpp index 2b363175ca..9c61086b92 100644 --- a/eeschema/erc_item.cpp +++ b/eeschema/erc_item.cpp @@ -49,7 +49,11 @@ ERC_ITEM ERC_ITEM::pinNotDriven( ERCE_PIN_NOT_DRIVEN, _( "Pin connected to other pins, but not driven by any pin" ), wxT( "pin_not_driven" ) ); -ERC_ITEM ERC_ITEM::pinTableConflict( ERCE_PIN_TO_PIN_ERROR, +ERC_ITEM ERC_ITEM::pinTableWarning( ERCE_PIN_TO_PIN_WARNING, + _( "Conflict problem between pins" ), + wxT( "pin_to_pin" ) ); + +ERC_ITEM ERC_ITEM::pinTableError( ERCE_PIN_TO_PIN_ERROR, _( "Conflict problem between pins" ), wxT( "pin_to_pin" ) ); @@ -117,7 +121,7 @@ std::vector> ERC_ITEM::allItemTypes( { ERC_ITEM::duplicateSheetName, ERC_ITEM::pinNotConnected, ERC_ITEM::pinNotDriven, - ERC_ITEM::pinTableConflict, + ERC_ITEM::pinTableWarning, ERC_ITEM::hierLabelMismatch, ERC_ITEM::noConnectConnected, ERC_ITEM::noConnectDangling, @@ -151,8 +155,10 @@ ERC_ITEM* ERC_ITEM::Create( int aErrorCode ) return new ERC_ITEM( pinNotDriven ); case ERCE_PIN_TO_PIN_WARNING: + return new ERC_ITEM( pinTableWarning ); + case ERCE_PIN_TO_PIN_ERROR: - return new ERC_ITEM( pinTableConflict ); + return new ERC_ITEM( pinTableError ); case ERCE_HIERACHICAL_LABEL: return new ERC_ITEM( hierLabelMismatch ); diff --git a/eeschema/erc_item.h b/eeschema/erc_item.h index f1c58996fe..04eef82305 100644 --- a/eeschema/erc_item.h +++ b/eeschema/erc_item.h @@ -55,7 +55,8 @@ private: static ERC_ITEM duplicateSheetName; static ERC_ITEM pinNotConnected; static ERC_ITEM pinNotDriven; - static ERC_ITEM pinTableConflict; + static ERC_ITEM pinTableWarning; + static ERC_ITEM pinTableError; static ERC_ITEM hierLabelMismatch; static ERC_ITEM noConnectConnected; static ERC_ITEM noConnectDangling; diff --git a/eeschema/erc_settings.cpp b/eeschema/erc_settings.cpp index 552ca0aa2f..a5bcd48403 100644 --- a/eeschema/erc_settings.cpp +++ b/eeschema/erc_settings.cpp @@ -29,13 +29,68 @@ const int ercSettingsSchemaVersion = 0; + +#define OK PIN_ERROR::OK +#define ERR PIN_ERROR::ERROR +#define WAR PIN_ERROR::WARNING + +/** + * Default Look up table which gives the ERC error level for a pair of connected pins + */ +PIN_ERROR ERC_SETTINGS::m_defaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL] = + { +/* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */ +/* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR }, +/* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR }, +/* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR }, +/* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR }, +/*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR }, +/*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR }, +/*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR }, +/*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR }, +/* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR }, +/* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR }, +/* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR } + }; + + +/** + * Look up table which gives the minimal drive for a pair of connected pins on + * a net. + *

+ * The initial state of a net is NOC (Net with No Connection). It can be updated to + * NPI (Pin Isolated), NET_NC (Net with a no connect symbol), NOD (Not Driven) or DRV + * (DRIven). It can be updated to NET_NC with no error only if there is only one pin + * in net. Nets are OK when their final state is NET_NC or DRV. Nets with the state + * NOD have no valid source signal. + */ +int ERC_SETTINGS::m_PinMinDrive[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL] = + { +/* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */ +/* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI }, +/* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI }, +/*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI }, +/* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI }, +/* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI } + }; + + ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) : NESTED_SETTINGS( "erc", ercSettingsSchemaVersion, aParent, aPath ) { + ResetPinMap(); + for( int i = ERCE_FIRST; i <= ERCE_LAST; ++i ) m_Severities[ i ] = RPT_SEVERITY_ERROR; - m_Severities[ ERCE_UNSPECIFIED ] = RPT_SEVERITY_UNDEFINED; + m_Severities[ERCE_UNSPECIFIED] = RPT_SEVERITY_UNDEFINED; + m_Severities[ERCE_PIN_TO_PIN_WARNING] = RPT_SEVERITY_WARNING; m_params.emplace_back( new PARAM_LAMBDA( "rule_severities", [&]() -> nlohmann::json @@ -74,6 +129,52 @@ ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) : } }, {} ) ); + + m_params.emplace_back( new PARAM_LAMBDA( "pin_map", + [&]() -> nlohmann::json + { + nlohmann::json ret = nlohmann::json::array(); + + for( int i = 0; i < ELECTRICAL_PINTYPES_TOTAL; i++ ) + { + nlohmann::json inner = nlohmann::json::array(); + + for( int j = 0; j < ELECTRICAL_PINTYPES_TOTAL; j++ ) + inner.push_back( static_cast( GetPinMapValue( i, j ) ) ); + + ret.push_back( inner ); + } + + return ret; + }, + [&]( const nlohmann::json& aJson ) + { + if( !aJson.is_array() || aJson.size() != ELECTRICAL_PINTYPES_TOTAL ) + return; + + for( size_t i = 0; i < ELECTRICAL_PINTYPES_TOTAL; i++ ) + { + if( i > aJson.size() - 1 ) + break; + + nlohmann::json inner = aJson[i]; + + if( !inner.is_array() || inner.size() != ELECTRICAL_PINTYPES_TOTAL ) + return; + + for( size_t j = 0; j < ELECTRICAL_PINTYPES_TOTAL; j++ ) + { + if( inner[j].is_number_integer() ) + { + int val = inner[j].get(); + + if( val >= 0 && val <= static_cast( PIN_ERROR::UNCONNECTED ) ) + SetPinMapValue( i, j, static_cast( val ) ); + } + } + } + }, + {} ) ); } @@ -89,9 +190,6 @@ ERC_SETTINGS::~ERC_SETTINGS() int ERC_SETTINGS::GetSeverity( int aErrorCode ) const { - wxCHECK_MSG( m_Severities.count( aErrorCode ), RPT_SEVERITY_IGNORE, - "Missing severity from map in ERC_SETTINGS!" ); - // Special-case pin-to-pin errors: // Ignore-or-not is controlled by ERCE_PIN_TO_PIN_WARNING (for both) // Warning-or-error is controlled by which errorCode it is @@ -114,6 +212,9 @@ int ERC_SETTINGS::GetSeverity( int aErrorCode ) const return RPT_SEVERITY_WARNING; } + wxCHECK_MSG( m_Severities.count( aErrorCode ), RPT_SEVERITY_IGNORE, + "Missing severity from map in ERC_SETTINGS!" ); + return m_Severities.at( aErrorCode ); } @@ -124,6 +225,12 @@ void ERC_SETTINGS::SetSeverity( int aErrorCode, int aSeverity ) } +void ERC_SETTINGS::ResetPinMap() +{ + memcpy( m_PinMap, m_defaultPinMap, sizeof( m_PinMap ) ); +} + + void SHEETLIST_ERC_ITEMS_PROVIDER::SetSeverities( int aSeverities ) { m_severities = aSeverities; diff --git a/eeschema/erc_settings.h b/eeschema/erc_settings.h index baf92e5fb5..3765355cd9 100644 --- a/eeschema/erc_settings.h +++ b/eeschema/erc_settings.h @@ -21,13 +21,62 @@ #ifndef _ERC_SETTINGS_H #define _ERC_SETTINGS_H -#include #include +#include #include #include class SCH_MARKER; +class SCHEMATIC; + + +/// ERC error codes +enum ERCE_T +{ + ERCE_UNSPECIFIED = 0, + ERCE_FIRST, + ERCE_DUPLICATE_SHEET_NAME = ERCE_FIRST, // duplicate sheet names within a given sheet + ERCE_PIN_NOT_CONNECTED, // pin not connected and not no connect symbol + ERCE_PIN_NOT_DRIVEN, // pin connected to some others pins but no pin to drive it + ERCE_HIERACHICAL_LABEL, // mismatch between hierarchical labels and pins sheets + ERCE_NOCONNECT_CONNECTED, // a no connect symbol is connected to more than 1 pin + ERCE_NOCONNECT_NOT_CONNECTED, // a no connect symbol is not connected to anything + ERCE_LABEL_NOT_CONNECTED, // label not connected to anything + ERCE_SIMILAR_LABELS, // 2 labels are equal fir case insensitive comparisons + ERCE_DIFFERENT_UNIT_FP, // different units of the same component have different footprints assigned + ERCE_DIFFERENT_UNIT_NET, // a shared pin in a multi-unit component is connected to more than one net + ERCE_BUS_ALIAS_CONFLICT, // conflicting bus alias definitions across sheets + ERCE_DRIVER_CONFLICT, // conflicting drivers (labels, etc) on a subgraph + ERCE_BUS_ENTRY_CONFLICT, // a wire connected to a bus doesn't match the bus + ERCE_BUS_LABEL_ERROR, // a label attached to a bus isn't in bus format + ERCE_BUS_TO_BUS_CONFLICT, // a connection between bus objects doesn't share at least one net + ERCE_BUS_TO_NET_CONFLICT, // a bus wire is graphically connected to a net port/pin (or vice versa) + ERCE_GLOBLABEL, // a global label is unique + ERCE_UNRESOLVED_VARIABLE, + ERCE_LAST = ERCE_UNRESOLVED_VARIABLE, + + // Errors after this point will not automatically appear in the Severities Panel + + ERCE_PIN_TO_PIN_WARNING, // pin connected to an other pin: warning level + ERCE_PIN_TO_PIN_ERROR, // pin connected to an other pin: error level +}; + +/// The values a pin-to-pin entry in the pin matrix can take on +enum class PIN_ERROR +{ + OK, + WARNING, + ERROR, + UNCONNECTED +}; + +/// Types of drive on a net (used for legacy ERC) +#define NPI 4 // Net with Pin isolated, this pin has type Not Connected and must be left N.C. +#define DRV 3 // Net driven by a signal (a pin output for instance) +#define NET_NC 2 // Net "connected" to a "NoConnect symbol" +#define NOD 1 // Net not driven ( Such as 2 or more connected inputs ) +#define NOC 0 // initial state of a net: no connection /** * Container for ERC settings @@ -71,7 +120,49 @@ public: void SetSeverity( int aErrorCode, int aSeverity ); + void ResetPinMap(); + + PIN_ERROR GetPinMapValue( int aFirstType, int aSecondType ) const + { + wxASSERT( aFirstType < ELECTRICAL_PINTYPES_TOTAL + && aSecondType < ELECTRICAL_PINTYPES_TOTAL ); + return m_PinMap[aFirstType][aSecondType]; + } + + PIN_ERROR GetPinMapValue( ELECTRICAL_PINTYPE aFirstType, ELECTRICAL_PINTYPE aSecondType ) const + { + return m_PinMap[static_cast( aFirstType )][static_cast( aSecondType )]; + } + + void SetPinMapValue( int aFirstType, int aSecondType, PIN_ERROR aValue ) + { + wxASSERT( aFirstType < ELECTRICAL_PINTYPES_TOTAL + && aSecondType < ELECTRICAL_PINTYPES_TOTAL ); + m_PinMap[aFirstType][aSecondType] = aValue; + } + + void SetPinMapValue( ELECTRICAL_PINTYPE aFirstType, ELECTRICAL_PINTYPE aSecondType, + PIN_ERROR aValue ) + { + m_PinMap[static_cast( aFirstType )][static_cast( aSecondType )] = aValue; + } + + int GetPinMinDrive( ELECTRICAL_PINTYPE aFirstType, ELECTRICAL_PINTYPE aSecondType ) const + { + return m_PinMinDrive[static_cast( aFirstType )][static_cast( aSecondType )]; + } + +public: + std::map m_Severities; + + PIN_ERROR m_PinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; + + static int m_PinMinDrive[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; + +private: + + static PIN_ERROR m_defaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL]; }; /** diff --git a/eeschema/netlist_generator.cpp b/eeschema/netlist_generator.cpp index 53160c4d03..689c0abc19 100644 --- a/eeschema/netlist_generator.cpp +++ b/eeschema/netlist_generator.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -158,10 +159,6 @@ bool SCH_EDIT_FRAME::WriteNetListFile( int aFormat, const wxString& aFullFileNam } -//Imported function: -int TestDuplicateSheetNames( SCHEMATIC* aSchematic, bool aCreateMarker ); - - bool SCH_EDIT_FRAME::ReadyToNetlist( bool aSilent, bool aSilentAnnotate ) { // Ensure all power symbols have a valid reference @@ -190,7 +187,9 @@ bool SCH_EDIT_FRAME::ReadyToNetlist( bool aSilent, bool aSilentAnnotate ) } // Test duplicate sheet names: - if( TestDuplicateSheetNames( &Schematic(), false ) > 0 ) + ERC_TESTER erc( &Schematic() ); + + if( erc.TestDuplicateSheetNames( false ) > 0 ) { if( aSilent || !IsOK( this, _( "Error: duplicate sheet names. Continue?" ) ) ) return false; diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp index 72b9296ec5..d0159eeb49 100644 --- a/eeschema/tools/sch_editor_control.cpp +++ b/eeschema/tools/sch_editor_control.cpp @@ -831,7 +831,9 @@ static bool highlightNet( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition ) if( aPosition != CLEAR ) { - if( TestDuplicateSheetNames( &editFrame->Schematic(), false ) > 0 ) + ERC_TESTER erc( &editFrame->Schematic() ); + + if( erc.TestDuplicateSheetNames( false ) > 0 ) { wxMessageBox( _( "Error: duplicate sub-sheet names found in current sheet." ) ); retVal = false;