From adbd94553da7ccee6785d329a8c324da7835f414 Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Tue, 25 Aug 2020 19:42:52 +0200 Subject: [PATCH] drc_proto: all tests now supported in drc_proto. Not tested yet! --- qa/drc_proto/CMakeLists.txt | 8 + qa/drc_proto/drc_engine.cpp | 51 ++-- qa/drc_proto/drc_engine.h | 37 ++- qa/drc_proto/drc_item.cpp | 10 +- qa/drc_proto/drc_item.h | 2 +- qa/drc_proto/drc_proto_test.cpp | 3 + qa/drc_proto/drc_rtree.h | 20 +- qa/drc_proto/drc_rule.h | 7 +- qa/drc_proto/drc_test_provider.cpp | 153 ++++++++---- qa/drc_proto/drc_test_provider.h | 8 +- qa/drc_proto/drc_test_provider_annulus.cpp | 160 ++++++++++++ .../drc_test_provider_connectivity.cpp | 177 ++++++++++++++ .../drc_test_provider_copper_clearance.cpp | 3 + .../drc_test_provider_courtyard_clearance.cpp | 229 ++++++++++++++++++ qa/drc_proto/drc_test_provider_disallow.cpp | 130 ++++++++++ .../drc_test_provider_edge_clearance.cpp | 31 ++- qa/drc_proto/drc_test_provider_lvs.cpp | 214 ++++++++++++++++ qa/drc_proto/drc_test_provider_misc.cpp | 216 +++++++++++++++++ .../drc_test_provider_silk_to_pad.cpp | 168 +++++++++++++ .../drc_test_provider_track_width.cpp | 194 ++++++--------- .../drc_test_provider_via_diameter.cpp | 154 ++++++++++++ 21 files changed, 1752 insertions(+), 223 deletions(-) create mode 100644 qa/drc_proto/drc_test_provider_annulus.cpp create mode 100644 qa/drc_proto/drc_test_provider_connectivity.cpp create mode 100644 qa/drc_proto/drc_test_provider_courtyard_clearance.cpp create mode 100644 qa/drc_proto/drc_test_provider_disallow.cpp create mode 100644 qa/drc_proto/drc_test_provider_lvs.cpp create mode 100644 qa/drc_proto/drc_test_provider_misc.cpp create mode 100644 qa/drc_proto/drc_test_provider_silk_to_pad.cpp create mode 100644 qa/drc_proto/drc_test_provider_via_diameter.cpp diff --git a/qa/drc_proto/CMakeLists.txt b/qa/drc_proto/CMakeLists.txt index 2b4f851c4e..93b841cf91 100644 --- a/qa/drc_proto/CMakeLists.txt +++ b/qa/drc_proto/CMakeLists.txt @@ -44,6 +44,14 @@ add_executable( drc_proto drc_test_provider_hole_clearance.cpp drc_test_provider_edge_clearance.cpp drc_test_provider_hole_size.cpp + drc_test_provider_disallow.cpp + drc_test_provider_track_width.cpp + drc_test_provider_annulus.cpp + drc_test_provider_connectivity.cpp + drc_test_provider_courtyard_clearance.cpp + drc_test_provider_via_diameter.cpp + drc_test_provider_lvs.cpp + drc_test_provider_misc.cpp drc_engine.cpp drc_item.cpp ../qa_utils/mocks.cpp diff --git a/qa/drc_proto/drc_engine.cpp b/qa/drc_proto/drc_engine.cpp index e318c7ac7d..b989b89bb2 100644 --- a/qa/drc_proto/drc_engine.cpp +++ b/qa/drc_proto/drc_engine.cpp @@ -43,6 +43,10 @@ void drcPrintDebugMessage( int level, wxString msg, const char *function, int li if( wxGetEnv( "DRC_DEBUG", &valueStr ) ) { int setLevel = wxAtoi( valueStr ); + if( level <= setLevel ) + { + printf("%-30s:%d | %s\n", function, line, (const char *) msg.c_str() ); + } } } @@ -50,6 +54,8 @@ void drcPrintDebugMessage( int level, wxString msg, const char *function, int li test::DRC_ENGINE::DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS *aSettings ) : m_board( aBoard ), m_designSettings ( aSettings ), + m_worksheet( nullptr ), + m_schematicNetlist( nullptr ), m_reporter( nullptr ), m_progressReporter( nullptr ) { @@ -64,11 +70,6 @@ test::DRC_ENGINE::~DRC_ENGINE() test::DRC_REPORT::~DRC_REPORT() { - for( auto item : m_entries ) - { - if ( item.m_marker ) - delete item.m_marker; - } } @@ -139,11 +140,11 @@ bool test::DRC_ENGINE::CompileRules() for( auto provider : m_testProviders ) { ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) ); - drc_dbg(11, "do prov %s", provider->GetName() ); + drc_dbg(7, "do prov %s", provider->GetName() ); for ( auto id : provider->GetMatchingConstraintIds() ) { - drc_dbg(11, "do id %d", id); + drc_dbg(7, "do id %d", id); if( m_constraintMap.find(id) == m_constraintMap.end() ) m_constraintMap[id] = new CONSTRAINT_SET; @@ -151,14 +152,14 @@ bool test::DRC_ENGINE::CompileRules() for( auto rule : m_rules ) { - drc_dbg(11, "Scan provider %s, rule %s", provider->GetName(), rule->GetName() ); + drc_dbg(7, "Scan provider %s, rule %s", provider->GetName(), rule->GetName() ); if( ! rule->IsEnabled() ) continue; for( auto& constraint : rule->Constraints() ) { - drc_dbg(11, "scan constraint id %d\n", constraint.GetType() ); + drc_dbg(7, "scan constraint id %d\n", constraint.GetType() ); if( constraint.GetType() != id ) continue; @@ -191,8 +192,6 @@ bool test::DRC_ENGINE::CompileRules() void test::DRC_ENGINE::RunTests( ) { - //m_largestClearance = m_designSettings->GetBiggestClearanceValue(); - m_drcReport.reset( new test::DRC_REPORT ); m_testProviders = DRC_TEST_PROVIDER_REGISTRY::Instance().GetTestProviders(); @@ -209,14 +208,18 @@ void test::DRC_ENGINE::RunTests( ) for( auto provider : m_testProviders ) { bool skipProvider = false; + auto matchingConstraints = provider->GetMatchingConstraintIds(); - for( auto ruleID : provider->GetMatchingConstraintIds() ) + if( matchingConstraints.size() ) { - if( !HasCorrectRulesForId( ruleID ) ) + for( auto ruleID : matchingConstraints ) { - ReportAux( wxString::Format( "DRC provider '%s' has no rules provided. Skipping run.", provider->GetName() ) ); - skipProvider = true; - break; + if( !HasCorrectRulesForId( ruleID ) ) + { + ReportAux( wxString::Format( "DRC provider '%s' has no rules provided. Skipping run.", provider->GetName() ) ); + skipProvider = true; + break; + } } } @@ -271,12 +274,18 @@ void test::DRC_ENGINE::Report( std::shared_ptr aItem, ::MARKER_PCB *aM if( m_reporter ) { - m_reporter->Report ( wxString::Format( "Test '%s': violation of rule '%s' : %s (code %d)", - aItem->GetViolatingTest()->GetName(), - aItem->GetViolatingRule()->GetName(), - aItem->GetErrorMessage(), - aItem->GetErrorCode() ), RPT_SEVERITY_ERROR /* fixme */ ); + wxString msg = wxString::Format( "Test '%s': %s (code %d)", + aItem->GetViolatingTest()->GetName(), + aItem->GetErrorMessage(), + aItem->GetErrorCode() ); + auto rule = aItem->GetViolatingRule(); + + if( rule ) + msg += wxString::Format( ", violating rule: '%s'", rule->GetName() ); + + m_reporter->Report ( msg, RPT_SEVERITY_ERROR /* fixme */ ); + wxString violatingItemsStr = "Violating items: "; if( aMarker ) diff --git a/qa/drc_proto/drc_engine.h b/qa/drc_proto/drc_engine.h index 873ed5bafa..2a1422d22f 100644 --- a/qa/drc_proto/drc_engine.h +++ b/qa/drc_proto/drc_engine.h @@ -53,12 +53,20 @@ class NETLIST; class PROGRESS_REPORTER; class REPORTER; +namespace KIGFX +{ + class WS_PROXY_VIEW_ITEM; +}; void drcPrintDebugMessage( int level, wxString msg, const char *function, int line ); #define drc_dbg(level, fmt, ...) \ drcPrintDebugMessage(level, wxString::Format( fmt, __VA_ARGS__ ), __FUNCTION__, __LINE__ ); + +//#define drc_dbg(level, fmt, ...) \ + // wxLogTrace("DUPA", fmt, __VA_ARGS__); + namespace test { @@ -88,10 +96,10 @@ enum PCB_DRC_CODE DRCE_ZONE_HAS_EMPTY_NET, ///< copper area has a net but no pads in nets, which is suspicious DRCE_DANGLING_VIA, ///< via which isn't connected to anything DRCE_DANGLING_TRACK, ///< track with at least one end not connected to anything - DRCE_HOLE_CLEARANCE, ///< overlapping drilled holes break drill bits + DRCE_HOLE_CLEARANCE, ///< overlapping drilled holes break drill bits DRCE_TRACK_WIDTH, ///< Track width is too small or too large DRCE_TOO_SMALL_VIA, ///< Too small via size - DRCE_VIA_ANNULUS, ///< Via size and drill leave annulus too small or too large + DRCE_ANNULUS, ///< Via size and drill leave annulus too small or too large DRCE_TOO_SMALL_DRILL, ///< Too small via or pad drill DRCE_VIA_HOLE_BIGGER, ///< via's hole is bigger than its diameter DRCE_PADSTACK, ///< something is wrong with a pad or via stackup @@ -111,6 +119,7 @@ enum PCB_DRC_CODE DRCE_EXTRA_FOOTPRINT, ///< netlist item not found for footprint DRCE_UNRESOLVED_VARIABLE, + DRCE_VIA_DIAMETER, ///< Via diameter checks (min/max) DRCE_LAST = DRCE_UNRESOLVED_VARIABLE }; @@ -158,6 +167,26 @@ public: DRC_ENGINE( BOARD* aBoard, BOARD_DESIGN_SETTINGS* aSettings ); ~DRC_ENGINE(); + void SetSchematicNetlist( NETLIST* aNetlist ) + { + m_schematicNetlist = aNetlist; + } + + NETLIST* GetSchematicNetlist() const + { + return m_schematicNetlist; + } + + void SetWorksheet( KIGFX::WS_PROXY_VIEW_ITEM* aWorksheet ) + { + m_worksheet = aWorksheet; + } + + KIGFX::WS_PROXY_VIEW_ITEM* GetWorksheet() const + { + return m_worksheet; + } + void SetProgressReporter( PROGRESS_REPORTER* aProgRep ) { m_progressReporter = aProgRep; @@ -183,6 +212,8 @@ public: return m_board; } + + const DRC_CONSTRAINT& EvalRulesForItems( DRC_CONSTRAINT_TYPE_T ruleID, BOARD_ITEM* a, BOARD_ITEM* b = nullptr, PCB_LAYER_ID aLayer = UNDEFINED_LAYER ); @@ -233,6 +264,8 @@ private: BOARD_DESIGN_SETTINGS* m_designSettings; BOARD* m_board; + KIGFX::WS_PROXY_VIEW_ITEM* m_worksheet; + NETLIST* m_schematicNetlist; std::shared_ptr m_drcReport; diff --git a/qa/drc_proto/drc_item.cpp b/qa/drc_proto/drc_item.cpp index 1c50eca9e7..0c89763098 100644 --- a/qa/drc_proto/drc_item.cpp +++ b/qa/drc_proto/drc_item.cpp @@ -88,9 +88,9 @@ test::DRC_ITEM test::DRC_ITEM::viaTooSmall( DRCE_TOO_SMALL_VIA, _( "Via size too small" ), wxT( "via_too_small" ) ); -test::DRC_ITEM test::DRC_ITEM::viaAnnulus( DRCE_VIA_ANNULUS, - _( "Via annulus" ), - wxT( "via_annulus" ) ); +test::DRC_ITEM test::DRC_ITEM::annulus( DRCE_ANNULUS, + _( "annulus" ), + wxT( "annulus" ) ); test::DRC_ITEM test::DRC_ITEM::drillTooSmall( DRCE_TOO_SMALL_DRILL, _( "Drill too small" ), @@ -175,7 +175,7 @@ std::vector> test::DRC_ITEM::allItemTypes( { DRC_ITEM::holeClearance, DRC_ITEM::trackWidth, DRC_ITEM::viaTooSmall, - DRC_ITEM::viaAnnulus, + DRC_ITEM::annulus, DRC_ITEM::drillTooSmall, DRC_ITEM::viaHoleLargerThanPad, DRC_ITEM::padstack, @@ -215,7 +215,7 @@ std::shared_ptr test::DRC_ITEM::Create( int aErrorCode ) case DRCE_HOLE_CLEARANCE: item = new DRC_ITEM( holeClearance ); break; case DRCE_TRACK_WIDTH: item = new DRC_ITEM( trackWidth ); break; case DRCE_TOO_SMALL_VIA: item = new DRC_ITEM( viaTooSmall ); break; - case DRCE_VIA_ANNULUS: item = new DRC_ITEM( viaAnnulus ); break; + case DRCE_ANNULUS: item = new DRC_ITEM( annulus ); break; case DRCE_TOO_SMALL_DRILL: item = new DRC_ITEM( drillTooSmall ); break; case DRCE_VIA_HOLE_BIGGER: item = new DRC_ITEM( viaHoleLargerThanPad ); break; case DRCE_PADSTACK: item = new DRC_ITEM( padstack ); break; diff --git a/qa/drc_proto/drc_item.h b/qa/drc_proto/drc_item.h index 0e485e2229..018a56d4cb 100644 --- a/qa/drc_proto/drc_item.h +++ b/qa/drc_proto/drc_item.h @@ -98,7 +98,7 @@ private: static DRC_ITEM holeClearance; static DRC_ITEM trackWidth; static DRC_ITEM viaTooSmall; - static DRC_ITEM viaAnnulus; + static DRC_ITEM annulus; static DRC_ITEM drillTooSmall; static DRC_ITEM viaHoleLargerThanPad; static DRC_ITEM padstack; diff --git a/qa/drc_proto/drc_proto_test.cpp b/qa/drc_proto/drc_proto_test.cpp index 0d081b5023..9949b3c2f7 100644 --- a/qa/drc_proto/drc_proto_test.cpp +++ b/qa/drc_proto/drc_proto_test.cpp @@ -36,6 +36,9 @@ int main( int argc, char *argv[] ) { + + wxLogTrace("DUPA", "Debug Test!\n"); + PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); propMgr.Rebuild(); diff --git a/qa/drc_proto/drc_rtree.h b/qa/drc_proto/drc_rtree.h index 85d66d51a8..5e81ddbc32 100644 --- a/qa/drc_proto/drc_rtree.h +++ b/qa/drc_proto/drc_rtree.h @@ -26,7 +26,7 @@ #define DRC_RTREE_H_ #include -#include +#include #include #include @@ -46,7 +46,7 @@ private: public: DRC_RTREE() { - for( int layer : LSET::AllCuMask().Seq() ) + for( int layer : LSET::AllLayersMask().Seq() ) m_tree[layer] = new drc_rtree(); m_count = 0; @@ -92,14 +92,14 @@ public: } } else - { - const EDA_RECT& bbox = aItem->GetBoundingBox(); - const int mmin[2] = { bbox.GetX(), bbox.GetY() }; - const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() }; + { + const EDA_RECT& bbox = aItem->GetBoundingBox(); + const int mmin[2] = { bbox.GetX(), bbox.GetY() }; + const int mmax[2] = { bbox.GetRight(), bbox.GetBottom() }; - for( int layer : aItem->GetLayerSet().Seq() ) + for( int layer : aItem->GetLayerSet().Seq() ) { - m_tree[layer]->Insert( mmin, mmax, aItem ); + m_tree[layer]->Insert( mmin, mmax, aItem ); } } @@ -130,8 +130,8 @@ public: const int mmin2[2] = { INT_MIN, INT_MIN }; const int mmax2[2] = { INT_MAX, INT_MAX }; - // If we are not successful ( true == not found ), then we expand - // the search to the full tree + // If we are not successful ( true == not found ), then we expand + // the search to the full tree while( !m_tree[int( layer )]->Remove( mmin2, mmax2, aItem ) ) ; diff --git a/qa/drc_proto/drc_rule.h b/qa/drc_proto/drc_rule.h index a6a3d070b8..8311b02c80 100644 --- a/qa/drc_proto/drc_rule.h +++ b/qa/drc_proto/drc_rule.h @@ -57,7 +57,8 @@ enum DRC_CONSTRAINT_TYPE_T DRC_CONSTRAINT_TYPE_SILK_TO_SILK, DRC_CONSTRAINT_TYPE_TRACK_WIDTH, DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH, - DRC_CONSTRAINT_TYPE_DISALLOW + DRC_CONSTRAINT_TYPE_DISALLOW, + DRC_CONSTRAINT_TYPE_VIA_DIAMETER }; enum DRC_DISALLOW_T @@ -93,7 +94,7 @@ public: bool HasMax() const { return m_hasMax; } bool HasOpt() const { return m_hasOpt; } - void SetMin( T v ) { m_min = v; m_hasMin = true; } +void SetMin( T v ) { m_min = v; m_hasMin = true; } void SetMax( T v ) { m_max = v; m_hasMax = true; } void SetOpt( T v ) { m_opt = v; m_hasOpt = true; } @@ -127,6 +128,8 @@ class DRC_CONSTRAINT DRC_CONSTRAINT_TYPE_T GetType() const { return m_Type; } + const LSET& GetAllowedLayers() const { return m_LayerCondition; } + public: DRC_CONSTRAINT_TYPE_T m_Type; int m_DisallowFlags; diff --git a/qa/drc_proto/drc_test_provider.cpp b/qa/drc_proto/drc_test_provider.cpp index b770436bea..cebe377724 100644 --- a/qa/drc_proto/drc_test_provider.cpp +++ b/qa/drc_proto/drc_test_provider.cpp @@ -99,7 +99,7 @@ void test::DRC_TEST_PROVIDER::reportRuleStatistics() } } -int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector aTypes, const LSET aLayers, std::function aFunc ) +int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector aTypes, const LSET aLayers, std::function aFunc ) { BOARD *brd = m_drcEngine->GetBoard(); std::bitset typeMask; @@ -125,20 +125,23 @@ int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector aTy case PCB_ARC_T:*/ for ( auto item : brd->Tracks() ) { - if( typeMask[ PCB_TRACE_T ] && item->Type() == PCB_TRACE_T ) + if( (item->GetLayerSet() & aLayers).any() ) { - aFunc( item ); - n++; - } - else if( typeMask[ PCB_VIA_T ] && item->Type() == PCB_VIA_T ) - { - aFunc( item ); - n++; - } - else if( typeMask[ PCB_ARC_T ] && item->Type() == PCB_ARC_T ) - { - aFunc( item ); - n++; + if( typeMask[ PCB_TRACE_T ] && item->Type() == PCB_TRACE_T ) + { + aFunc( item ); + n++; + } + else if( typeMask[ PCB_VIA_T ] && item->Type() == PCB_VIA_T ) + { + aFunc( item ); + n++; + } + else if( typeMask[ PCB_ARC_T ] && item->Type() == PCB_ARC_T ) + { + aFunc( item ); + n++; + } } } @@ -149,34 +152,50 @@ int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector aTy */ for( auto item : brd->Drawings() ) { - if( typeMask[ PCB_DIMENSION_T ] && item->Type() == PCB_DIMENSION_T ) + if( (item->GetLayerSet() & aLayers).any() ) { - aFunc( item ); - n++; - } - else if( typeMask[ PCB_LINE_T ] && item->Type() == PCB_LINE_T ) - { - aFunc( item ); - n++; - } - else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T ) - { - aFunc( item ); - n++; - } - else if( typeMask[ PCB_TARGET_T ] && item->Type() == PCB_TARGET_T ) - { - aFunc( item ); - n++; + if( typeMask[ PCB_DIMENSION_T ] && item->Type() == PCB_DIMENSION_T ) + { + if( !aFunc( item ) ) + return n; + + n++; + } + else if( typeMask[ PCB_LINE_T ] && item->Type() == PCB_LINE_T ) + { + if( !aFunc( item ) ) + return n; + + n++; + } + else if( typeMask[ PCB_TEXT_T ] && item->Type() == PCB_TEXT_T ) + { + if( !aFunc( item ) ) + return n; + + n++; + } + else if( typeMask[ PCB_TARGET_T ] && item->Type() == PCB_TARGET_T ) + { + if( !aFunc( item ) ) + return n; + + n++; + } } } for( auto item : brd->Zones() ) { - if( typeMask[ PCB_ZONE_AREA_T ] && item->Type() == PCB_ZONE_AREA_T ) + if( (item->GetLayerSet() & aLayers).any() ) { - aFunc( item ); - n++; + if( typeMask[ PCB_ZONE_AREA_T ] && item->Type() == PCB_ZONE_AREA_T ) + { + if( !aFunc( item ) ) + return n; + + n++; + } } } @@ -184,41 +203,69 @@ int test::DRC_TEST_PROVIDER::forEachGeometryItem( const std::vector aTy { if( typeMask[ PCB_MODULE_TEXT_T ] ) { - aFunc( &mod->Reference() ); - n++; - aFunc( &mod->Value() ); - n++; + if( (mod->Reference().GetLayerSet() & aLayers).any() ) + { + if( !aFunc( &mod->Reference() ) ) + return n; + + n++; + } + + if( (mod->Value().GetLayerSet() & aLayers).any() ) + { + if( !aFunc( &mod->Value() ) ) + return n; + + n++; + } } for( auto pad : mod->Pads() ) { - if( typeMask[ PCB_PAD_T ] && pad->Type() == PCB_PAD_T ) + if( (pad->GetLayerSet() & aLayers).any() ) { - aFunc( pad ); - n++; + if( typeMask[ PCB_PAD_T ] && pad->Type() == PCB_PAD_T ) + { + if( !aFunc( pad ) ) + return n; + + n++; + } } } for( auto dwg : mod->GraphicalItems() ) { - if( typeMask[ PCB_MODULE_TEXT_T ] && dwg->Type() == PCB_MODULE_TEXT_T ) + if( (dwg->GetLayerSet() & aLayers).any() ) { - aFunc( dwg ); - n++; - } - else if( typeMask[ PCB_MODULE_EDGE_T ] && dwg->Type() == PCB_MODULE_EDGE_T ) - { - aFunc( dwg ); - n++; + if( typeMask[ PCB_MODULE_TEXT_T ] && dwg->Type() == PCB_MODULE_TEXT_T ) + { + if( !aFunc( dwg ) ) + return n; + + n++; + } + else if( typeMask[ PCB_MODULE_EDGE_T ] && dwg->Type() == PCB_MODULE_EDGE_T ) + { + if( !aFunc( dwg ) ) + return n; + + n++; + } } } for( auto zone : mod->Zones() ) { - if( typeMask[ PCB_MODULE_ZONE_AREA_T ] && zone->Type() == PCB_MODULE_ZONE_AREA_T ) + if( (zone->GetLayerSet() & aLayers).any() ) { - aFunc( zone ); - n++; + if( typeMask[ PCB_MODULE_ZONE_AREA_T ] && zone->Type() == PCB_MODULE_ZONE_AREA_T ) + { + if( ! aFunc( zone ) ) + return n; + + n++; + } } } } diff --git a/qa/drc_proto/drc_test_provider.h b/qa/drc_proto/drc_test_provider.h index 57aa08cc2b..081565597b 100644 --- a/qa/drc_proto/drc_test_provider.h +++ b/qa/drc_proto/drc_test_provider.h @@ -106,9 +106,14 @@ public: virtual std::set GetMatchingConstraintIds() const = 0; + virtual bool IsRuleDriven() const + { + return m_isRuleDriven; + } + protected: - int forEachGeometryItem( const std::vector aTypes, const LSET aLayers, std::function aFunc ); + int forEachGeometryItem( const std::vector aTypes, const LSET aLayers, std::function aFunc ); virtual void reportRuleStatistics(); virtual void accountCheck( const test::DRC_RULE* ruleToTest ); @@ -119,6 +124,7 @@ protected: DRC_ENGINE *m_drcEngine; std::unordered_map m_stats; bool m_enable; + bool m_isRuleDriven = true; }; diff --git a/qa/drc_proto/drc_test_provider_annulus.cpp b/qa/drc_proto/drc_test_provider_annulus.cpp new file mode 100644 index 0000000000..d8b67eec89 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_annulus.cpp @@ -0,0 +1,160 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + + +/* + Via/pad annular ring width test. Checks if there's sufficient copper ring around PTH/NPTH holes (vias/pads) + Errors generated: + - DRCE_ANNULUS + + Todo: + - check pad holes too. + - pad stack support (different IAR/OAR values depending on layer) +*/ + +namespace test +{ + +class DRC_TEST_PROVIDER_ANNULUS : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_ANNULUS() + { + } + + virtual ~DRC_TEST_PROVIDER_ANNULUS() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "annulus"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests pad/via annular rings"; + } + + virtual std::set GetMatchingConstraintIds() const override; +}; + +}; // namespace test + + +bool test::DRC_TEST_PROVIDER_ANNULUS::Run() +{ + if( !m_drcEngine->HasCorrectRulesForId( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH ) ) + { + ReportAux( "No annulus constraints found. Skipping check." ); + return false; + } + + ReportStage( ( "Testing via annular rings" ), 0, 2 ); + + auto checkAnnulus = [&]( BOARD_ITEM* item ) -> bool + { + bool fail_min = false, fail_max = false; + int v_min, v_max; + auto via = dyn_cast( item ); + + // fixme: check minimum IAR/OAR ring for THT pads too + if( !via ) + return true; + + test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH, via ); + + int annulus = ( via->GetWidth() - via->GetDrillValue() ) / 2; + + if( constraint.Value().HasMin() ) + { + v_min = constraint.Value().Min(); + fail_min = annulus < v_min; + } + + if( constraint.Value().HasMax() ) + { + v_max = constraint.Value().Max(); + fail_max = annulus > v_max; + } + + if( fail_min || fail_max ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ANNULUS ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s; actual annulus %s, constraint %s %s)" ), + constraint.GetParentRule()->GetName(), + MessageTextFromValue( userUnits(), annulus, true ), + fail_min ? _( "minimum" ) : _( "maximum" ), + MessageTextFromValue( userUnits(), fail_min ? v_min : v_max, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( item ); + drcItem->SetViolatingRule( constraint.GetParentRule() ); + + ReportWithMarker( drcItem, via->GetPosition() ); + + if( isErrorLimitExceeded( DRCE_ANNULUS ) ) + return false; + + } + + return true; + }; + + forEachGeometryItem( { PCB_VIA_T }, LSET::AllCuMask(), checkAnnulus ); + + reportRuleStatistics(); + + return true; +} + + +std::set +test::DRC_TEST_PROVIDER_ANNULUS::GetMatchingConstraintIds() const +{ + return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH }; +} + + +namespace detail +{ +static test::DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file diff --git a/qa/drc_proto/drc_test_provider_connectivity.cpp b/qa/drc_proto/drc_test_provider_connectivity.cpp new file mode 100644 index 0000000000..7f8a83246d --- /dev/null +++ b/qa/drc_proto/drc_test_provider_connectivity.cpp @@ -0,0 +1,177 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +/* + Connectivity test provider. Not rule-driven. + Errors generated: + - DRCE_DANGLING_TRACK + - DRCE_DANGLING_VIA + - DRCE_ZONE_HAS_EMPTY_NET +*/ + +namespace test +{ + +class DRC_TEST_PROVIDER_CONNECTIVITY : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_CONNECTIVITY() + { + } + + virtual ~DRC_TEST_PROVIDER_CONNECTIVITY() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "connectivity"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests board connectivity"; + } + + virtual std::set GetMatchingConstraintIds() const override; +}; + +}; // namespace test + + +bool test::DRC_TEST_PROVIDER_CONNECTIVITY::Run() +{ + ReportStage( ( "Testing dangling pads/vias" ), 0, 2 ); + + BOARD* board = m_drcEngine->GetBoard(); + + std::shared_ptr connectivity = board->GetConnectivity(); + connectivity->Clear(); + connectivity->Build( board ); // just in case. This really needs to be reliable. + + + for( auto track : board->Tracks() ) + { + bool exceedT = isErrorLimitExceeded( DRCE_DANGLING_TRACK ); + bool exceedV = isErrorLimitExceeded( DRCE_DANGLING_VIA ); + // Test for dangling items + int code = track->Type() == PCB_VIA_T ? DRCE_DANGLING_VIA : DRCE_DANGLING_TRACK; + wxPoint pos; + + if( track->Type() == PCB_VIA_T && exceedV ) + continue; + else if( track->Type() == PCB_TRACE_T && exceedT ) + continue; + + if( connectivity->TestTrackEndpointDangling( track, &pos ) ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( code ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() ); + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( track ); + ReportWithMarker( drcItem, pos ); + } + + if( exceedV && exceedT ) + break; + } + + ReportStage( ( "Testing starved zones" ), 0, 2 ); + + /* test starved zones */ + for( auto zone : board->Zones() ) + { + if( !zone->IsOnCopperLayer() ) + continue; + + int netcode = zone->GetNetCode(); + // a netcode < 0 or > 0 and no pad in net is a error or strange + // perhaps a "dead" net, which happens when all pads in this net were removed + // Remark: a netcode < 0 should not happen (this is more a bug somewhere) + int pads_in_net = ( netcode > 0 ) ? connectivity->GetPadCount( netcode ) : 1; + + if( ( netcode < 0 ) || pads_in_net == 0 ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ZONE_HAS_EMPTY_NET ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() ); + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( zone ); + ReportWithMarker( drcItem, zone->GetPosition() ); + + if( isErrorLimitExceeded( DRCE_ZONE_HAS_EMPTY_NET ) ) + break; + } + } + + ReportStage( ( "Testing unconnected ratlines" ), 0, 2 ); + + connectivity->RecalculateRatsnest(); + std::vector edges; + connectivity->GetUnconnectedEdges( edges ); + + for( const CN_EDGE& edge : edges ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNCONNECTED_ITEMS ); + + drcItem->SetItems( edge.GetSourceNode()->Parent(), edge.GetTargetNode()->Parent() ); + ReportWithMarker( drcItem, edge.GetSourceNode()->Pos() ); + + if( isErrorLimitExceeded( DRCE_UNCONNECTED_ITEMS ) ) + break; + } + + reportRuleStatistics(); + + return true; +} + + +std::set +test::DRC_TEST_PROVIDER_CONNECTIVITY::GetMatchingConstraintIds() const +{ + return {}; +} + + +namespace detail +{ +static test::DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file diff --git a/qa/drc_proto/drc_test_provider_copper_clearance.cpp b/qa/drc_proto/drc_test_provider_copper_clearance.cpp index d8f95337cd..31dddd1ef1 100644 --- a/qa/drc_proto/drc_test_provider_copper_clearance.cpp +++ b/qa/drc_proto/drc_test_provider_copper_clearance.cpp @@ -46,6 +46,7 @@ - DRCE_CLEARANCE - DRCE_TRACKS_CROSSING - DRCE_ZONES_INTERSECT + - DRCE_SHORTING_ITEMS TODO: improve zone clearance check (super slow) */ @@ -121,6 +122,8 @@ bool test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::Run() ReportStage( ("Testing copper zone clearances"), 1, 2 ); testZones(); + reportRuleStatistics(); + return true; } diff --git a/qa/drc_proto/drc_test_provider_courtyard_clearance.cpp b/qa/drc_proto/drc_test_provider_courtyard_clearance.cpp new file mode 100644 index 0000000000..fb2fa481a7 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_courtyard_clearance.cpp @@ -0,0 +1,229 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + Couartyard clearance. Tests for malformed component courtyards and overlapping footprints. + Generated errors: + - DRCE_OVERLAPPING_FOOTPRINTS + - DRCE_MISSING_COURTYARD + - DRCE_MALFORMED_COURTYARD + + TODO: do an actual clearance check instead of polygon intersection. Treat closed outlines + as filled and allow open curves in the courtyard. +*/ + +namespace test { + +class DRC_TEST_PROVIDER_COURTYARD_CLEARANCE : public DRC_TEST_PROVIDER_CLEARANCE_BASE +{ +public: + DRC_TEST_PROVIDER_COURTYARD_CLEARANCE () + { + m_isRuleDriven = false; + } + + virtual ~DRC_TEST_PROVIDER_COURTYARD_CLEARANCE () + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "courtyard_clearance"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests components' courtyard clearance"; + } + + virtual std::set GetMatchingConstraintIds() const override; + +private: + + void testFootprintCourtyardDefinitions(); + void testOverlappingComponentCourtyards(); + +}; + +}; + + +void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testFootprintCourtyardDefinitions() +{ + ReportStage( _("Testing component courtyard definitions"), 0, 2 ); + + for( MODULE* footprint : m_board->Modules() ) + { + if( footprint->BuildPolyCourtyard() ) + { + if( footprint->GetPolyCourtyardFront().OutlineCount() == 0 + && footprint->GetPolyCourtyardBack().OutlineCount() == 0 ) + { + if( isErrorLimitExceeded( DRCE_MISSING_COURTYARD ) ) + continue; + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_MISSING_COURTYARD ); + wxString msg; + + msg.Printf( drcItem->GetErrorText( )); + + drcItem->SetItems( footprint ); + ReportWithMarker( drcItem, footprint->GetPosition() ); + } + else + { + footprint->GetPolyCourtyardFront().BuildBBoxCaches(); + footprint->GetPolyCourtyardBack().BuildBBoxCaches(); + } + } + else + { + if( !isErrorLimitExceeded( DRCE_MALFORMED_COURTYARD) ) + { + wxString msg; + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD ); + + msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( footprint ); + ReportWithMarker( drcItem, footprint->GetPosition() ); + } + } + } +} + + +void test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::testOverlappingComponentCourtyards() +{ + ReportStage( _("Testing component courtyard overlap"), 0, 2 ); + + for( auto it1 = m_board->Modules().begin(); it1 != m_board->Modules().end(); it1++ ) + { + MODULE* footprint = *it1; + SHAPE_POLY_SET& footprintFront = footprint->GetPolyCourtyardFront(); + SHAPE_POLY_SET& footprintBack = footprint->GetPolyCourtyardBack(); + + if( footprintFront.OutlineCount() == 0 && footprintBack.OutlineCount() == 0 ) + continue; // No courtyards defined + + for( auto it2 = it1 + 1; it2 != m_board->Modules().end(); it2++ ) + { + MODULE* test = *it2; + SHAPE_POLY_SET& testFront = test->GetPolyCourtyardFront(); + SHAPE_POLY_SET& testBack = test->GetPolyCourtyardBack(); + SHAPE_POLY_SET intersection; + bool overlap = false; + wxPoint pos; + + if( footprintFront.OutlineCount() > 0 && testFront.OutlineCount() > 0 + && footprintFront.BBoxFromCaches().Intersects( testFront.BBoxFromCaches() ) ) + { + intersection.RemoveAllContours(); + intersection.Append( footprintFront ); + + // Build the common area between footprint and the test: + intersection.BooleanIntersection( testFront, SHAPE_POLY_SET::PM_FAST ); + + // If the intersection exists then they overlap + if( intersection.OutlineCount() > 0 ) + { + overlap = true; + pos = (wxPoint) intersection.CVertex( 0, 0, -1 ); + } + } + + if( footprintBack.OutlineCount() > 0 && testBack.OutlineCount() > 0 + && footprintBack.BBoxFromCaches().Intersects( testBack.BBoxFromCaches() ) ) + { + intersection.RemoveAllContours(); + intersection.Append( footprintBack ); + + intersection.BooleanIntersection( testBack, SHAPE_POLY_SET::PM_FAST ); + + if( intersection.OutlineCount() > 0 ) + { + overlap = true; + pos = (wxPoint) intersection.CVertex( 0, 0, -1 ); + } + } + + if( overlap ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_OVERLAPPING_FOOTPRINTS ); + drcItem->SetItems( footprint, test ); + ReportWithMarker ( drcItem, pos ); + + if( isErrorLimitExceeded( DRCE_OVERLAPPING_FOOTPRINTS ) ) + return; + } + } + } +} + + +bool test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::Run() +{ + m_board = m_drcEngine->GetBoard(); + + // fixme: don't use polygon intersection but distance for clearance tests + //m_largestClearance = 0; + //ReportAux( "Worst courtyard clearance : %d nm", m_largestClearance ); + + testFootprintCourtyardDefinitions(); + testOverlappingComponentCourtyards(); + + return true; +} + + +std::set test::DRC_TEST_PROVIDER_COURTYARD_CLEARANCE::GetMatchingConstraintIds() const +{ + return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE }; +} + + +namespace detail +{ + static test::DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file diff --git a/qa/drc_proto/drc_test_provider_disallow.cpp b/qa/drc_proto/drc_test_provider_disallow.cpp new file mode 100644 index 0000000000..27b88d8e82 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_disallow.cpp @@ -0,0 +1,130 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include + +#include +#include +#include +#include + +/* + "Disallow" test. Goes through all items, matching types/conditions drop errors. + Errors generated: + - DRCE_ALLOWED_ITEMS +*/ + +namespace test +{ + +class DRC_TEST_PROVIDER_DISALLOW : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_DISALLOW() + { + } + + virtual ~DRC_TEST_PROVIDER_DISALLOW() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "disallow"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests for disallowed items (e.g. keepouts)"; + } + + virtual std::set GetMatchingConstraintIds() const override; + +private: +}; + +}; // namespace test + + +bool test::DRC_TEST_PROVIDER_DISALLOW::Run() +{ + if( !m_drcEngine->HasCorrectRulesForId( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW ) ) + { + ReportAux( "No disallow constraints found. Skipping check." ); + return false; + } + + ReportStage( ("Testing for disallow constraints"), 0, 2 ); + + auto checkItem = [&] ( BOARD_ITEM *item ) -> bool + { + test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW, item ); + + if( constraint.Allowed() ) + return true; + + if( ( constraint.GetAllowedLayers() & item->GetLayerSet() ).any() ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_ALLOWED_ITEMS ); + wxString msg; + + msg.Printf( + drcItem->GetErrorText() + _( " (%s)" ), constraint.GetParentRule()->GetName() ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( item ); + drcItem->SetViolatingRule( constraint.GetParentRule() ); + + ReportWithMarker( drcItem, item->GetPosition() ); + + if( isErrorLimitExceeded( DRCE_ALLOWED_ITEMS ) ) + return false; + } + return true; + }; + + forEachGeometryItem( {}, LSET::AllLayersMask(), checkItem ); + + reportRuleStatistics(); + + return true; +} + + +std::set +test::DRC_TEST_PROVIDER_DISALLOW::GetMatchingConstraintIds() const +{ + return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW }; +} + + +namespace detail +{ +static test::DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file diff --git a/qa/drc_proto/drc_test_provider_edge_clearance.cpp b/qa/drc_proto/drc_test_provider_edge_clearance.cpp index c65f863dc5..adcacde378 100644 --- a/qa/drc_proto/drc_test_provider_edge_clearance.cpp +++ b/qa/drc_proto/drc_test_provider_edge_clearance.cpp @@ -104,35 +104,37 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() std::vector boardOutline; std::vector boardItems; - auto queryBoardOutlineItems = [&] ( BOARD_ITEM *item ) -> int + auto queryBoardOutlineItems = [&] ( BOARD_ITEM *item ) -> bool { boardOutline.push_back( dyn_cast( item ) ); - return 0; + return true; }; - auto queryBoardGeometryItems = [&] ( BOARD_ITEM *item ) -> int + auto queryBoardGeometryItems = [&] ( BOARD_ITEM *item ) -> bool { boardItems.push_back( item ); - return 0; + return true; }; - - forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems ); forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems ); + wxString val; + wxGetEnv( "WXTRACE", &val); drc_dbg(2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() ); + bool stop = false; + for( auto outlineItem : boardOutline ) { - drc_dbg(12, "RefT %d %p\n", outlineItem->Type(), outlineItem ); auto refShape = outlineItem->GetEffectiveShape(); for( auto boardItem : boardItems ) { - drc_dbg(12, "BoardT %d %p\n", boardItem->Type(), boardItem ); - + drc_dbg(10, "RefT %d %p %s %d\n", outlineItem->Type(), outlineItem, outlineItem->GetClass(), outlineItem->GetLayer() ); + drc_dbg(10, "BoardT %d %p %s %d\n", boardItem->Type(), boardItem, boardItem->GetClass(), boardItem->GetLayer() ); + auto shape = boardItem->GetEffectiveShape(); test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, outlineItem, boardItem ); @@ -154,10 +156,21 @@ bool test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::Run() drcItem->SetViolatingRule( constraint.GetParentRule() ); ReportWithMarker( drcItem, refShape->Centre() ); + + if( isErrorLimitExceeded( DRCE_COPPER_EDGE_CLEARANCE ) ) + { + stop = true; + break; + } } } + + if( stop ) + break; } + reportRuleStatistics(); + return true; } diff --git a/qa/drc_proto/drc_test_provider_lvs.cpp b/qa/drc_proto/drc_test_provider_lvs.cpp new file mode 100644 index 0000000000..8397a95df2 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_lvs.cpp @@ -0,0 +1,214 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* + Layout-versus-schematic (LVS) test. + + Errors generated: + - DRCE_MISSING_FOOTPRINT + - DRCE_DUPLICATE_FOOTPRINT + - DRCE_EXTRA_FOOTPRINT + + TODO: + - cross-check PCB netlist against SCH netlist + - cross-check PCB fields against SCH fields +*/ + +namespace test +{ + +class DRC_TEST_PROVIDER_LVS : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_LVS() + { + m_isRuleDriven = false; + } + + virtual ~DRC_TEST_PROVIDER_LVS() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "LVS"; + }; + + virtual const wxString GetDescription() const override + { + return "Performs layout-vs-schematics integity check"; + } + + virtual std::set GetMatchingConstraintIds() const override; + +private: + + bool fetchNetlistFromSchematic( NETLIST& aNetlist ); + void testFootprints( NETLIST& aNetlist ); +}; + +}; // namespace test + + +void test::DRC_TEST_PROVIDER_LVS::testFootprints( NETLIST& aNetlist ) +{ + wxString msg; + BOARD* board = m_drcEngine->GetBoard(); + + auto comp = []( const MODULE* x, const MODULE* y ) { + return x->GetReference().CmpNoCase( y->GetReference() ) < 0; + }; + + auto mods = std::set( comp ); + + for( MODULE* mod : board->Modules() ) + { + auto ins = mods.insert( mod ); + + if( !ins.second ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_DUPLICATE_FOOTPRINT ); + drcItem->SetItems( mod, *ins.first ); + + ReportWithMarker( drcItem, mod->GetPosition() ); + + if( isErrorLimitExceeded( DRCE_DUPLICATE_FOOTPRINT ) ) + break; + } + } + + // Search for component footprints in the netlist but not on the board. + for( unsigned ii = 0; ii < aNetlist.GetCount(); ii++ ) + { + COMPONENT* component = aNetlist.GetComponent( ii ); + MODULE* module = board->FindModuleByReference( component->GetReference() ); + + if( module == nullptr ) + { + msg.Printf( _( "Missing footprint %s (%s)" ), component->GetReference(), + component->GetValue() ); + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_MISSING_FOOTPRINT ); + + drcItem->SetErrorMessage( msg ); + Report( drcItem ); + + if( isErrorLimitExceeded( DRCE_MISSING_FOOTPRINT ) ) + break; + } + } + + + for( auto module : mods ) + { + COMPONENT* component = aNetlist.GetComponentByReference( module->GetReference() ); + + if( component == NULL ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_EXTRA_FOOTPRINT ); + + drcItem->SetItems( module ); + ReportWithMarker( drcItem, module->GetPosition() ); + + if( isErrorLimitExceeded( DRCE_EXTRA_FOOTPRINT ) ) + break; + } + } +} + + +bool test::DRC_TEST_PROVIDER_LVS::fetchNetlistFromSchematic( NETLIST& aNetlist ) +{ + // fixme: make it work without dependency on EDIT_FRAME/kiway +#if 0 + std::string payload; + + Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_GET_NETLIST, payload, nullptr ); + + try + { + auto lineReader = new STRING_LINE_READER( payload, _( "Eeschema netlist" ) ); + KICAD_NETLIST_READER netlistReader( lineReader, &aNetlist ); + netlistReader.LoadNetlist(); + } + catch( const IO_ERROR& ) + { + assert( false ); // should never happen + return false; + } + +#endif + + return false; +} + +bool test::DRC_TEST_PROVIDER_LVS::Run() +{ + ReportStage( _( "Layout-vs-Schematic checks..." ), 0, 2 ); + +#if 0 + + if ( !Kiface().IsSingle() ) + { + NETLIST netlist; // fixme: fetch from schematic without referring directly to the FRAME + + if( ! fetchNetlistFromSchematic( netlist ) ) + { + ReportAux( _( "Unable to fetch the schematic netlist. Skipping LVS checks. ") ); + return true; + } + + testFootprints( netlist ); + } +#endif + + reportRuleStatistics(); + + return true; +} + + +std::set test::DRC_TEST_PROVIDER_LVS::GetMatchingConstraintIds() const +{ + return {}; +} + + +namespace detail +{ +static test::DRC_REGISTER_TEST_PROVIDER dummy; +} diff --git a/qa/drc_proto/drc_test_provider_misc.cpp b/qa/drc_proto/drc_test_provider_misc.cpp new file mode 100644 index 0000000000..5989ae19c2 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_misc.cpp @@ -0,0 +1,216 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* + Miscellaneous tests: + + - DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer + - DRCE_INVALID_OUTLINE, ///< invalid board outline + - DRCE_UNRESOLVED_VARIABLE, + + TODO: + - if grows too big, split into separate providers +*/ + +namespace test +{ + +class DRC_TEST_PROVIDER_MISC : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_MISC() + { + m_isRuleDriven = false; + } + + virtual ~DRC_TEST_PROVIDER_MISC() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "miscellanous"; + }; + + virtual const wxString GetDescription() const override + { + return "Misc checks (board outline, missing textvars)"; + } + + virtual std::set GetMatchingConstraintIds() const override; + +private: + void testOutline(); + void testDisabledLayers(); + void testTextVars(); + + BOARD* m_board; +}; + +}; // namespace test + + +void test::DRC_TEST_PROVIDER_MISC::testOutline() +{ + wxPoint error_loc( m_board->GetBoardEdgesBoundingBox().GetPosition() ); + + SHAPE_POLY_SET boardOutlines; + + if( m_board->GetBoardPolygonOutlines( boardOutlines, nullptr, &error_loc ) ) + return; + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_INVALID_OUTLINE ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (not a closed shape)" ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( m_board ); + + ReportWithMarker( drcItem, error_loc ); +} + + +void test::DRC_TEST_PROVIDER_MISC::testDisabledLayers() +{ + LSET disabledLayers = m_board->GetEnabledLayers().flip(); + + + // Perform the test only for copper layers + disabledLayers &= LSET::AllCuMask(); + + auto checkDisabledLayers = [&]( BOARD_ITEM* item ) -> bool { + if( ( disabledLayers & item->GetLayerSet() ).any() ) + { + wxString msg; + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM ); + + msg.Printf( drcItem->GetErrorText() + _( " (layer %s)" ), item->GetLayerName() ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( item ); + + ReportWithMarker( drcItem, item->GetPosition() ); + } + return true; + }; + + // fixme: what about graphical items? + forEachGeometryItem( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_ZONE_AREA_T, PCB_PAD_T }, + LSET::AllLayersMask(), checkDisabledLayers ); +} + +void test::DRC_TEST_PROVIDER_MISC::testTextVars() +{ + auto checkUnresolvedTextVar = [&]( EDA_ITEM* item ) -> bool { + EDA_TEXT* text = dynamic_cast( item ); + + assert( text ); + + + if( text->GetShownText().Matches( wxT( "*${*}*" ) ) ) + { + if( isErrorLimitExceeded( DRCE_UNRESOLVED_VARIABLE ) ) + return false; + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE ); + drcItem->SetItems( item ); + + ReportWithMarker( drcItem, item->GetPosition() ); + } + return true; + }; + + forEachGeometryItem( + { PCB_MODULE_TEXT_T, PCB_TEXT_T }, LSET::AllLayersMask(), checkUnresolvedTextVar ); + + WS_DRAW_ITEM_LIST wsItems; + + auto worksheet = m_drcEngine->GetWorksheet(); + + if( !worksheet ) + return; + + wsItems.SetMilsToIUfactor( IU_PER_MILS ); + wsItems.BuildWorkSheetGraphicList( worksheet->GetPageInfo(), worksheet->GetTitleBlock() ); + + for( WS_DRAW_ITEM_BASE* item = wsItems.GetFirst(); item; item = wsItems.GetNext() ) + { + if( WS_DRAW_ITEM_TEXT* text = dynamic_cast( item ) ) + { + if( isErrorLimitExceeded( DRCE_UNRESOLVED_VARIABLE ) ) + return; + + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_UNRESOLVED_VARIABLE ); + drcItem->SetItems( text ); + + ReportWithMarker( drcItem, text->GetPosition() ); + } + } +} + + +bool test::DRC_TEST_PROVIDER_MISC::Run() +{ + m_board = m_drcEngine->GetBoard(); + + ReportStage( _( "Test board outline" ), 0, 3 ); + testOutline(); + + ReportStage( _( "Test disabled layers" ), 1, 3 ); + testDisabledLayers(); + + ReportStage( _( "Test text variables" ), 2, 3 ); + testTextVars(); + + return true; +} + + +std::set test::DRC_TEST_PROVIDER_MISC::GetMatchingConstraintIds() const +{ + return {}; +} + + +namespace detail +{ +static test::DRC_REGISTER_TEST_PROVIDER dummy; +} diff --git a/qa/drc_proto/drc_test_provider_silk_to_pad.cpp b/qa/drc_proto/drc_test_provider_silk_to_pad.cpp new file mode 100644 index 0000000000..9bb5f069c4 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_silk_to_pad.cpp @@ -0,0 +1,168 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + Silk to pads clearance test. Check all pads against silkscreen (mask opening in the pad vs silkscreen) + Errors generated: + - DRCE_SILK_ON_PADS + + TODO: + - tester only looks for edge crossings. it doesn't check if items are inside/outside the board area. +*/ + +namespace test { + +class DRC_TEST_PROVIDER_SILK_TO_PAD : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_SILK_TO_PAD () + { + } + + virtual ~DRC_TEST_PROVIDER_SILK_TO_PAD() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "silk_to_pad"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests for silkscreen covering components pads"; + } + + virtual std::set GetMatchingConstraintIds() const override; + +private: +}; + +}; + + +bool test::DRC_TEST_PROVIDER_SILK_TO_PAD::Run() +{ + m_board = m_drcEngine->GetBoard(); + + DRC_CONSTRAINT worstClearanceConstraint; + m_largestClearance = 0; + + if( m_drcEngine->QueryWorstConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_SILK_TO_PAD, worstClearanceConstraint, DRCCQ_LARGEST_MINIMUM ) ) + { + m_largestClearance = worstClearanceConstraint.m_Value.Min(); + } + + ReportAux( "Worst clearance : %d nm", m_largestClearance ); + ReportStage( ("Testing pads vs silkscreen clearance"), 0, 2 ); + + + std::vector boardOutline; + std::vector boardItems; + + auto queryBoardOutlineItems = [&] ( BOARD_ITEM *item ) -> int + { + boardOutline.push_back( dyn_cast( item ) ); + }; + + auto queryBoardGeometryItems = [&] ( BOARD_ITEM *item ) -> int + { + boardItems.push_back( item ); + }; + + + + forEachGeometryItem( { PCB_LINE_T }, LSET( Edge_Cuts ), queryBoardOutlineItems ); + forEachGeometryItem( {}, LSET::AllTechMask() | LSET::AllCuMask(), queryBoardGeometryItems ); + + + drc_dbg(2,"outline: %d items, board: %d items\n", boardOutline.size(), boardItems.size() ); + + for( auto outlineItem : boardOutline ) + { + //printf("RefT %d\n", outlineItem->Type() ); + auto refShape = outlineItem->GetEffectiveShape(); + + for( auto boardItem : boardItems ) + { +// printf("BoardT %d\n", boardItem->Type() ); + + auto shape = boardItem->GetEffectiveShape(); + + test::DRC_RULE* rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, outlineItem, boardItem ); + int minClearance = rule->GetConstraint().GetValue().Min(); + int actual; + + if( refShape->Collide( shape.get(), minClearance, &actual ) ) + { + DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_COPPER_EDGE_CLEARANCE ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ), + rule->GetName(), + MessageTextFromValue( userUnits(), minClearance, true ), + MessageTextFromValue( userUnits(), actual, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( outlineItem, boardItem ); + drcItem->SetViolatingRule( rule ); + + ReportWithMarker( drcItem, refShape->Centre() ); + } + } + } + + return true; +} + + +std::set test::DRC_TEST_PROVIDER_EDGE_CLEARANCE::GetMatchingConstraintIds() const +{ + return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE }; +} + + +namespace detail +{ + static test::DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file diff --git a/qa/drc_proto/drc_test_provider_track_width.cpp b/qa/drc_proto/drc_test_provider_track_width.cpp index b0556d72c6..fe9c4de0be 100644 --- a/qa/drc_proto/drc_test_provider_track_width.cpp +++ b/qa/drc_proto/drc_test_provider_track_width.cpp @@ -22,44 +22,32 @@ */ #include -#include -#include +#include #include -#include -#include - -#include -#include -#include -#include - #include #include #include -#include +#include /* - Drilled hole size test. scans vias/through-hole pads and checks for min drill sizes + Track width test. As the name says, checks width of the tracks (including segments and arcs) Errors generated: - - DRCE_TOO_SMALL_DRILL - - DRCE_TOO_SMALL_MICROVIA_DRILL - - TODO: max drill size check + - DRCE_TRACK_WIDTH */ namespace test { -class DRC_TEST_PROVIDER_HOLE_SIZE : public DRC_TEST_PROVIDER +class DRC_TEST_PROVIDER_TRACK_WIDTH : public DRC_TEST_PROVIDER { public: - DRC_TEST_PROVIDER_HOLE_SIZE() + DRC_TEST_PROVIDER_TRACK_WIDTH() { } - virtual ~DRC_TEST_PROVIDER_HOLE_SIZE() + virtual ~DRC_TEST_PROVIDER_TRACK_WIDTH() { } @@ -67,57 +55,90 @@ public: virtual const wxString GetName() const override { - return "hole_size"; + return "width"; }; virtual const wxString GetDescription() const override { - return "Tests sizes of drilled holes (via/pad drills)"; + return "Tests track widths"; } virtual std::set GetMatchingConstraintIds() const override; - -private: - bool checkVia( VIA* via ); - bool checkPad( D_PAD* aPad ); - - BOARD* m_board; }; }; // namespace test -bool test::DRC_TEST_PROVIDER_HOLE_SIZE::Run() +bool test::DRC_TEST_PROVIDER_TRACK_WIDTH::Run() { - ReportStage( ( "Testing pad holes" ), 0, 2 ); - - for( auto module : m_board->Modules() ) + if( !m_drcEngine->HasCorrectRulesForId( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH ) ) { - for( auto pad : module->Pads() ) + ReportAux( "No track width constraints found. Skipping check." ); + return false; + } + + ReportStage( ( "Testing track widths" ), 0, 2 ); + + auto checkTrackWidth = [&]( BOARD_ITEM* item ) -> bool { + int width; + VECTOR2I p0; + + if( auto arc = dyn_cast( item ) ) { - if( checkPad( pad ) ) - break; + width = arc->GetWidth(); + p0 = arc->GetStart(); } - } - - ReportStage( ( "Testing via/microvia holes" ), 0, 2 ); - - std::vector vias; - - for( auto track : m_board->Tracks() ) - { - if( track->Type() == PCB_VIA_T ) + else if( auto trk = dyn_cast( item ) ) { - vias.push_back( static_cast( track ) ); + width = trk->GetWidth(); + p0 = ( trk->GetStart() + trk->GetEnd() ) / 2; } - } + test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH, item ); - for( auto via : vias ) - { - if( checkVia( via ) ) - break; - } + bool fail_min = false, fail_max = false; + int constraintWidth; + + if( constraint.Value().HasMin() && width < constraint.Value().Min() ) + { + fail_min = true; + constraintWidth = constraint.Value().Min(); + } + + if( constraint.Value().HasMax() && width > constraint.Value().Max() ) + { + fail_max = true; + constraintWidth = constraint.Value().Max(); + } + + if( fail_min || fail_max ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_TRACK_WIDTH ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s; width %s, constraint %s %s)" ), + constraint.GetParentRule()->GetName(), + MessageTextFromValue( userUnits(), width, true ), + fail_min ? _( "minimum" ) : _( "maximum" ), + MessageTextFromValue( userUnits(), constraintWidth, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( item ); + drcItem->SetViolatingRule( constraint.GetParentRule() ); + + ReportWithMarker( drcItem, p0 ); + + if( isErrorLimitExceeded( DRCE_TRACK_WIDTH ) ) + return false; + + } + + return true; + }; + + forEachGeometryItem( { PCB_TRACE_T, PCB_ARC_T }, LSET::AllCuMask(), checkTrackWidth ); reportRuleStatistics(); @@ -125,79 +146,14 @@ bool test::DRC_TEST_PROVIDER_HOLE_SIZE::Run() } -bool test::DRC_TEST_PROVIDER_HOLE_SIZE::checkPad( D_PAD* aPad ) +std::set +test::DRC_TEST_PROVIDER_TRACK_WIDTH::GetMatchingConstraintIds() const { - int holeSize = std::min( aPad->GetDrillSize().x, aPad->GetDrillSize().y ); - - if( holeSize == 0 ) - return true; - - auto rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE, aPad ); - auto minHole = rule->GetConstraint().GetValue().Min(); - - accountCheck( rule ); - - if( holeSize < minHole ) - { - wxString msg; - DRC_ITEM* drcItem = DRC_ITEM::Create( DRCE_TOO_SMALL_DRILL ); - - msg.Printf( drcItem->GetErrorText() + _( " (%s; actual %s)" ), - MessageTextFromValue( userUnits(), minHole, true ), - MessageTextFromValue( userUnits(), holeSize, true ) ); - - drcItem->SetViolatingRule( rule ); - drcItem->SetErrorMessage( msg ); - drcItem->SetItems( aPad ); - - ReportWithMarker( drcItem, aPad->GetPosition() ); - - return isErrorLimitExceeded( DRCE_TOO_SMALL_DRILL ); - } - - return false; -} - - -bool test::DRC_TEST_PROVIDER_HOLE_SIZE::checkVia( VIA* via ) -{ - auto rule = m_drcEngine->EvalRulesForItems( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE, via ); - auto minHole = rule->GetConstraint().GetValue().Min(); - - accountCheck( rule ); - - if( via->GetDrillValue() < minHole ) - { - wxString msg; - int errorCode = via->GetViaType() == VIATYPE::MICROVIA ? DRCE_TOO_SMALL_MICROVIA_DRILL : - DRCE_TOO_SMALL_DRILL; - - DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode ); - - msg.Printf( drcItem->GetErrorText() + _( " (%s; actual %s)" ), - MessageTextFromValue( userUnits(), minHole, true ), - MessageTextFromValue( userUnits(), via->GetDrillValue(), true ) ); - - drcItem->SetViolatingRule( rule ); - drcItem->SetErrorMessage( msg ); - drcItem->SetItems( via ); - - ReportWithMarker( drcItem, via->GetPosition() ); - - return isErrorLimitExceeded( errorCode ); - } - - return false; -} - - -std::set test::DRC_TEST_PROVIDER_HOLE_SIZE::GetMatchingConstraintIds() const -{ - return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE }; + return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH }; } namespace detail { -static test::DRC_REGISTER_TEST_PROVIDER dummy; +static test::DRC_REGISTER_TEST_PROVIDER dummy; } \ No newline at end of file diff --git a/qa/drc_proto/drc_test_provider_via_diameter.cpp b/qa/drc_proto/drc_test_provider_via_diameter.cpp new file mode 100644 index 0000000000..d3a1376bb4 --- /dev/null +++ b/qa/drc_proto/drc_test_provider_via_diameter.cpp @@ -0,0 +1,154 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2004-2020 KiCad Developers. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include +#include +#include +#include + + +/* + Via diameter test. + + Errors generated: + - DRCE_TOO_SMALL_VIA + - DRCE_TOO_SMALL_MICROVIA +*/ + +namespace test +{ + +class DRC_TEST_PROVIDER_VIA_DIAMETER : public DRC_TEST_PROVIDER +{ +public: + DRC_TEST_PROVIDER_VIA_DIAMETER() + { + } + + virtual ~DRC_TEST_PROVIDER_VIA_DIAMETER() + { + } + + virtual bool Run() override; + + virtual const wxString GetName() const override + { + return "diameter"; + }; + + virtual const wxString GetDescription() const override + { + return "Tests via diameters"; + } + + virtual std::set GetMatchingConstraintIds() const override; +}; + +}; // namespace test + + +bool test::DRC_TEST_PROVIDER_VIA_DIAMETER::Run() +{ + if( !m_drcEngine->HasCorrectRulesForId( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER ) ) + { + ReportAux( "No diameter constraints found. Skipping check." ); + return false; + } + + ReportStage( ( "Testing via diameters" ), 0, 2 ); + + auto checkViaDiameter = [&]( BOARD_ITEM* item ) -> bool { + auto via = dyn_cast( item ); + + // fixme: move to pad stack check? + if( !via ) + return true; + + test::DRC_CONSTRAINT constraint = m_drcEngine->EvalRulesForItems( + test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER, item ); + + bool fail_min = false, fail_max = false; + int constraintDiameter; + int diameter = via->GetWidth(); + + if( constraint.Value().HasMin() && diameter < constraint.Value().Min() ) + { + fail_min = true; + constraintDiameter = constraint.Value().Min(); + } + + if( constraint.Value().HasMax() && diameter > constraint.Value().Max() ) + { + fail_max = true; + constraintDiameter = constraint.Value().Max(); + } + + if( fail_min || fail_max ) + { + std::shared_ptr drcItem = DRC_ITEM::Create( DRCE_VIA_DIAMETER ); + wxString msg; + + msg.Printf( drcItem->GetErrorText() + _( " (%s; diameter %s, constraint %s %s)" ), + constraint.GetParentRule()->GetName(), + MessageTextFromValue( userUnits(), diameter, true ), + fail_min ? _( "minimum" ) : _( "maximum" ), + MessageTextFromValue( userUnits(), constraintDiameter, true ) ); + + drcItem->SetErrorMessage( msg ); + drcItem->SetItems( item ); + drcItem->SetViolatingRule( constraint.GetParentRule() ); + + ReportWithMarker( drcItem, via->GetPosition() ); + + if( isErrorLimitExceeded( DRCE_VIA_DIAMETER ) ) + return false; + + } + + return true; + }; + + forEachGeometryItem( { PCB_VIA_T }, LSET::AllCuMask(), checkViaDiameter ); + + reportRuleStatistics(); + + return true; +} + + +std::set +test::DRC_TEST_PROVIDER_VIA_DIAMETER::GetMatchingConstraintIds() const +{ + return { DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER }; +} + + +namespace detail +{ +static test::DRC_REGISTER_TEST_PROVIDER dummy; +} \ No newline at end of file