ADDED assertion constraints for user-defined DRC checks.
This commit is contained in:
parent
f7721dd274
commit
b7e196b710
|
@ -1,4 +1,5 @@
|
|||
annular_width
|
||||
assertion
|
||||
board_edge
|
||||
buried_via
|
||||
clearance
|
||||
|
|
|
@ -292,6 +292,7 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
|
|||
else if( sexprs.top() == "constraint" )
|
||||
{
|
||||
tokens = "annular_width|"
|
||||
"assertion|"
|
||||
"clearance|"
|
||||
"courtyard_clearance|"
|
||||
"diff_pair_gap|"
|
||||
|
@ -330,13 +331,11 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
|
|||
}
|
||||
else if( sexprs.top() == "zone_connection" )
|
||||
{
|
||||
tokens = "solid "
|
||||
"thermal_relief "
|
||||
"none";
|
||||
tokens = "none|solid|thermal_relief";
|
||||
}
|
||||
else if( sexprs.top() == "min_resolved_spokes" )
|
||||
{
|
||||
tokens = "0 1 2 3 4";
|
||||
tokens = "0|1|2|3|4";
|
||||
}
|
||||
else if( sexprs.top() == "layer" )
|
||||
{
|
||||
|
@ -346,15 +345,14 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
|
|||
{
|
||||
tokens = "warning|error|ignore|exclusion";
|
||||
}
|
||||
else if( sexprs.top() == "severity" )
|
||||
{
|
||||
tokens = "error "
|
||||
"exclusion "
|
||||
"ignore "
|
||||
"warning";
|
||||
}
|
||||
}
|
||||
else if( context == STRING && !sexprs.empty() && sexprs.top() == "condition" )
|
||||
else if( context == SEXPR_STRING && !sexprs.empty()
|
||||
&& ( sexprs.top() == "condition" || sexprs.top() == "assertion" ) )
|
||||
{
|
||||
m_textEditor->AddText( "\"" );
|
||||
}
|
||||
else if( context == STRING && !sexprs.empty()
|
||||
&& ( sexprs.top() == "condition" || sexprs.top() == "assertion" ) )
|
||||
{
|
||||
if( expr_context == STRUCT_REF )
|
||||
{
|
||||
|
|
|
@ -194,25 +194,25 @@ For the latter use a `(layer "layer_name")` clause in the rule.
|
|||
|
||||
(rule "Distance between Vias of Different Nets"
|
||||
(constraint hole_to_hole (min 0.254mm))
|
||||
(condition "A.Type =='Via' && B.Type =='Via' && A.Net != B.Net"))
|
||||
(condition "A.Type == 'Via' && B.Type == 'Via' && A.Net != B.Net"))
|
||||
|
||||
(rule "Clearance between Pads of Different Nets"
|
||||
(constraint clearance (min 3.0mm))
|
||||
(condition "A.Type =='Pad' && B.Type =='Pad' && A.Net != B.Net"))
|
||||
(condition "A.Type == 'Pad' && B.Type == 'Pad' && A.Net != B.Net"))
|
||||
|
||||
|
||||
(rule "Via Hole to Track Clearance"
|
||||
(constraint hole_clearance (min 0.254mm))
|
||||
(condition "A.Type =='Via' && B.Type =='Track'"))
|
||||
(condition "A.Type == 'Via' && B.Type == 'Track'"))
|
||||
|
||||
(rule "Pad to Track Clearance"
|
||||
(constraint clearance (min 0.2mm))
|
||||
(condition "A.Type =='Pad' && B.Type =='Track'"))
|
||||
(condition "A.Type == 'Pad' && B.Type == 'Track'"))
|
||||
|
||||
|
||||
(rule "clearance-to-1mm-cutout"
|
||||
(constraint clearance (min 0.8mm))
|
||||
(condition "A.Layer=='Edge.Cuts' && A.Thickness == 1.0mm"))
|
||||
(condition "A.Layer == 'Edge.Cuts' && A.Thickness == 1.0mm"))
|
||||
|
||||
|
||||
(rule "Max Drill Hole Size Mechanical"
|
||||
|
@ -247,4 +247,10 @@ For the latter use a `(layer "layer_name")` clause in the rule.
|
|||
# Prevent solder wicking from SMD pads
|
||||
(rule holes_in_pads
|
||||
(constraint mechanical_hole_clearance (min 0.2mm))
|
||||
(condition "B.Pad_Type == 'SMD'"))
|
||||
(condition "B.Pad_Type == 'SMD'"))
|
||||
|
||||
|
||||
# Disallow solder mask margin overrides
|
||||
(rule "disallow solder mask margin overrides"
|
||||
(constraint assertion "A.Soldermask_Margin_Override == 0mm")
|
||||
(condition "A.Type == 'Pad'"))
|
|
@ -871,6 +871,18 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
}
|
||||
}
|
||||
|
||||
auto testAssertion =
|
||||
[&]( const DRC_ENGINE_CONSTRAINT* c )
|
||||
{
|
||||
REPORT( wxString::Format( _( "Checking assertion \"%s\"." ),
|
||||
EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
|
||||
|
||||
if( c->constraint.m_Test->EvaluateFor( a, b, aLayer, aReporter ) )
|
||||
REPORT( _( "Assertion passed." ) )
|
||||
else
|
||||
REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
|
||||
};
|
||||
|
||||
auto processConstraint =
|
||||
[&]( const DRC_ENGINE_CONSTRAINT* c ) -> bool
|
||||
{
|
||||
|
@ -1027,8 +1039,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
}
|
||||
else if( c->parentRule )
|
||||
{
|
||||
REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule "
|
||||
"ignored." ),
|
||||
REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
|
||||
EscapeHTML( c->parentRule->m_LayerSource ) ) )
|
||||
}
|
||||
else
|
||||
|
@ -1061,8 +1072,22 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
|
||||
if( !c->condition || c->condition->GetExpression().IsEmpty() )
|
||||
{
|
||||
REPORT( implicit ? _( "Unconditional constraint applied." )
|
||||
: _( "Unconditional rule applied." ) );
|
||||
if( aReporter )
|
||||
{
|
||||
if( implicit )
|
||||
{
|
||||
REPORT( _( "Unconditional constraint applied." ) )
|
||||
}
|
||||
else if( constraint.m_Type == ASSERTION_CONSTRAINT )
|
||||
{
|
||||
REPORT( _( "Unconditional rule applied." ) )
|
||||
testAssertion( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT( _( "Unconditional rule applied; overrides previous constraints." ) )
|
||||
}
|
||||
}
|
||||
|
||||
constraint = c->constraint;
|
||||
return true;
|
||||
|
@ -1081,8 +1106,22 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
|
||||
if( c->condition->EvaluateFor( a, b, aLayer, aReporter ) )
|
||||
{
|
||||
REPORT( implicit ? _( "Constraint applied." )
|
||||
: _( "Rule applied; overrides previous constraints." ) )
|
||||
if( aReporter )
|
||||
{
|
||||
if( implicit )
|
||||
{
|
||||
REPORT( _( "Constraint applied." ) )
|
||||
}
|
||||
else if( constraint.m_Type == ASSERTION_CONSTRAINT )
|
||||
{
|
||||
REPORT( _( "Rule applied." ) )
|
||||
testAssertion( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT( _( "Rule applied; overrides previous constraints." ) )
|
||||
}
|
||||
}
|
||||
|
||||
if( c->constraint.m_Value.HasMin() )
|
||||
constraint.m_Value.SetMin( c->constraint.m_Value.Min() );
|
||||
|
@ -1239,6 +1278,78 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
|
|||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
|
||||
void DRC_ENGINE::ProcessAssertions( const BOARD_ITEM* a,
|
||||
std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
|
||||
REPORTER* aReporter )
|
||||
{
|
||||
/*
|
||||
* NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
|
||||
* kills performance when running bulk DRC tests (where aReporter is nullptr).
|
||||
*/
|
||||
|
||||
auto testAssertion =
|
||||
[&]( const DRC_ENGINE_CONSTRAINT* c )
|
||||
{
|
||||
REPORT( wxString::Format( _( "Checking rule assertion \"%s\"." ),
|
||||
EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
|
||||
|
||||
if( c->constraint.m_Test->EvaluateFor( a, nullptr, a->GetLayer(), aReporter ) )
|
||||
{
|
||||
REPORT( _( "Assertion passed." ) )
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
|
||||
aFailureHandler( &c->constraint );
|
||||
}
|
||||
};
|
||||
|
||||
auto processConstraint =
|
||||
[&]( const DRC_ENGINE_CONSTRAINT* c )
|
||||
{
|
||||
REPORT( "" )
|
||||
REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
|
||||
|
||||
if( !( a->GetLayerSet() & c->layerTest ).any() )
|
||||
{
|
||||
REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
|
||||
EscapeHTML( c->parentRule->m_LayerSource ) ) )
|
||||
}
|
||||
|
||||
if( !c->condition || c->condition->GetExpression().IsEmpty() )
|
||||
{
|
||||
REPORT( _( "Unconditional rule applied." ) )
|
||||
testAssertion( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
|
||||
EscapeHTML( c->condition->GetExpression() ) ) )
|
||||
|
||||
if( c->condition->EvaluateFor( a, nullptr, a->GetLayer(), aReporter ) )
|
||||
{
|
||||
REPORT( _( "Rule applied." ) )
|
||||
testAssertion( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT( _( "Condition not satisfied; rule ignored." ) )
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if( m_constraintMap.count( ASSERTION_CONSTRAINT ) )
|
||||
{
|
||||
std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ ASSERTION_CONSTRAINT ];
|
||||
|
||||
for( int ii = 0; ii < (int) ruleset->size(); ++ii )
|
||||
processConstraint( ruleset->at( ii ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef REPORT
|
||||
#undef UNITS
|
||||
#undef REPORT_VALUE
|
||||
|
|
|
@ -152,6 +152,10 @@ public:
|
|||
DRC_CONSTRAINT EvalZoneConnection( const BOARD_ITEM* a, const BOARD_ITEM* b,
|
||||
PCB_LAYER_ID aLayer, REPORTER* aReporter = nullptr );
|
||||
|
||||
void ProcessAssertions( const BOARD_ITEM* a,
|
||||
std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
|
||||
REPORTER* aReporter = nullptr );
|
||||
|
||||
bool HasRulesForConstraintType( DRC_CONSTRAINT_T constraintID );
|
||||
|
||||
EDA_UNITS UserUnits() const { return m_userUnits; }
|
||||
|
|
|
@ -183,6 +183,10 @@ DRC_ITEM DRC_ITEM::unresolvedVariable( DRCE_UNRESOLVED_VARIABLE,
|
|||
_( "Unresolved text variable" ),
|
||||
wxT( "unresolved_variable" ) );
|
||||
|
||||
DRC_ITEM DRC_ITEM::assertionFailure( DRCE_ASSERTION_FAILURE,
|
||||
_( "Assertion failure" ),
|
||||
wxT( "assertion_failure" ) );
|
||||
|
||||
DRC_ITEM DRC_ITEM::copperSliver( DRCE_COPPER_SLIVER,
|
||||
_( "Copper sliver" ),
|
||||
wxT( "copper_sliver" ) );
|
||||
|
@ -334,6 +338,7 @@ std::shared_ptr<DRC_ITEM> DRC_ITEM::Create( int aErrorCode )
|
|||
case DRCE_EXTRA_FOOTPRINT: return std::make_shared<DRC_ITEM>( extraFootprint );
|
||||
case DRCE_LIB_FOOTPRINT_ISSUES: return std::make_shared<DRC_ITEM>( libFootprintIssues );
|
||||
case DRCE_UNRESOLVED_VARIABLE: return std::make_shared<DRC_ITEM>( unresolvedVariable );
|
||||
case DRCE_ASSERTION_FAILURE: return std::make_shared<DRC_ITEM>( assertionFailure );
|
||||
case DRCE_COPPER_SLIVER: return std::make_shared<DRC_ITEM>( copperSliver );
|
||||
case DRCE_OVERLAPPING_SILK: return std::make_shared<DRC_ITEM>( silkOverlaps );
|
||||
case DRCE_SILK_CLEARANCE: return std::make_shared<DRC_ITEM>( silkClearance );
|
||||
|
|
|
@ -73,6 +73,7 @@ enum PCB_DRC_CODE {
|
|||
DRCE_PAD_TH_WITH_NO_HOLE, // footprint has Plated Through-Hole with no hole
|
||||
|
||||
DRCE_UNRESOLVED_VARIABLE,
|
||||
DRCE_ASSERTION_FAILURE, // user-defined (custom rule) assertion
|
||||
|
||||
DRCE_COPPER_SLIVER,
|
||||
DRCE_SOLDERMASK_BRIDGE, // failure to maintain min soldermask web thickness
|
||||
|
@ -177,6 +178,7 @@ private:
|
|||
static DRC_ITEM netConflict;
|
||||
static DRC_ITEM libFootprintIssues;
|
||||
static DRC_ITEM unresolvedVariable;
|
||||
static DRC_ITEM assertionFailure;
|
||||
static DRC_ITEM copperSliver;
|
||||
static DRC_ITEM silkClearance;
|
||||
static DRC_ITEM solderMaskBridge;
|
||||
|
|
|
@ -67,7 +67,8 @@ enum DRC_CONSTRAINT_T
|
|||
DIFF_PAIR_INTRA_SKEW_CONSTRAINT,
|
||||
VIA_COUNT_CONSTRAINT,
|
||||
MECHANICAL_CLEARANCE_CONSTRAINT,
|
||||
MECHANICAL_HOLE_CLEARANCE_CONSTRAINT
|
||||
MECHANICAL_HOLE_CLEARANCE_CONSTRAINT,
|
||||
ASSERTION_CONSTRAINT
|
||||
};
|
||||
|
||||
|
||||
|
@ -123,6 +124,7 @@ class DRC_CONSTRAINT
|
|||
m_Value(),
|
||||
m_DisallowFlags( 0 ),
|
||||
m_ZoneConnection( ZONE_CONNECTION::INHERITED ),
|
||||
m_Test( nullptr ),
|
||||
m_name( aName ),
|
||||
m_parentRule( nullptr )
|
||||
{
|
||||
|
@ -163,14 +165,15 @@ class DRC_CONSTRAINT
|
|||
}
|
||||
|
||||
public:
|
||||
DRC_CONSTRAINT_T m_Type;
|
||||
MINOPTMAX<int> m_Value;
|
||||
int m_DisallowFlags;
|
||||
ZONE_CONNECTION m_ZoneConnection;
|
||||
DRC_CONSTRAINT_T m_Type;
|
||||
MINOPTMAX<int> m_Value;
|
||||
int m_DisallowFlags;
|
||||
ZONE_CONNECTION m_ZoneConnection;
|
||||
DRC_RULE_CONDITION* m_Test;
|
||||
|
||||
private:
|
||||
wxString m_name; // For just-in-time constraints
|
||||
DRC_RULE* m_parentRule; // For constraints found in rules
|
||||
wxString m_name; // For just-in-time constraints
|
||||
DRC_RULE* m_parentRule; // For constraints found in rules
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
|||
if( (int) token == DSN_RIGHT || token == T_EOF )
|
||||
{
|
||||
msg.Printf( _( "Missing constraint type.| Expected %s." ),
|
||||
"clearance, hole_clearance, edge_clearance, mechanical_clearance, "
|
||||
"assertion, clearance, hole_clearance, edge_clearance, mechanical_clearance, "
|
||||
"mechanical_hole_clearance, courtyard_clearance, silk_clearance, hole_size, "
|
||||
"hole_to_hole, track_width, annular_width, via_diameter, disallow, "
|
||||
"zone_connection, thermal_relief_gap, thermal_spoke_width, min_resolved_spokes, "
|
||||
|
@ -271,6 +271,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
|||
|
||||
switch( token )
|
||||
{
|
||||
case T_assertion: c.m_Type = ASSERTION_CONSTRAINT; break;
|
||||
case T_clearance: c.m_Type = CLEARANCE_CONSTRAINT; break;
|
||||
case T_hole_clearance: c.m_Type = HOLE_CLEARANCE_CONSTRAINT; break;
|
||||
case T_edge_clearance: c.m_Type = EDGE_CLEARANCE_CONSTRAINT; break;
|
||||
|
@ -298,7 +299,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
|||
case T_mechanical_hole_clearance: c.m_Type = MECHANICAL_HOLE_CLEARANCE_CONSTRAINT; break;
|
||||
default:
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
|
||||
"clearance, hole_clearance, edge_clearance, mechanical_clearance, "
|
||||
"assertion, clearance, hole_clearance, edge_clearance, mechanical_clearance, "
|
||||
"mechanical_hole_clearance, courtyard_clearance, silk_clearance, hole_size, "
|
||||
"hole_to_hole, track_width, annular_width, disallow, zone_connection, "
|
||||
"thermal_relief_gap, thermal_spoke_width, min_resolved_spokes, length, skew, "
|
||||
|
@ -412,6 +413,33 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
|
|||
aRule->AddConstraint( c );
|
||||
return;
|
||||
}
|
||||
else if( c.m_Type == ASSERTION_CONSTRAINT )
|
||||
{
|
||||
token = NextTok();
|
||||
|
||||
if( (int) token == DSN_RIGHT )
|
||||
reportError( _( "Missing assertion expression." ) );
|
||||
|
||||
if( IsSymbol( token ) )
|
||||
{
|
||||
c.m_Test = new DRC_RULE_CONDITION( FromUTF8() );
|
||||
c.m_Test->Compile( m_reporter, CurLineNumber(), CurOffset() );
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ), FromUTF8() );
|
||||
reportError( msg );
|
||||
}
|
||||
|
||||
if( (int) NextTok() != DSN_RIGHT )
|
||||
{
|
||||
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
|
||||
parseUnknown();
|
||||
}
|
||||
|
||||
aRule->AddConstraint( c );
|
||||
return;
|
||||
}
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004-2020 KiCad Developers.
|
||||
* Copyright (C) 2004-2021 KiCad Developers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -25,6 +25,7 @@
|
|||
#include <drc/drc_engine.h>
|
||||
#include <drc/drc_item.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <drc/drc_rule_condition.h>
|
||||
#include <drc/drc_test_provider.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_track.h>
|
||||
|
@ -38,6 +39,7 @@
|
|||
- DRCE_DISABLED_LAYER_ITEM, ///< item on a disabled layer
|
||||
- DRCE_INVALID_OUTLINE, ///< invalid board outline
|
||||
- DRCE_UNRESOLVED_VARIABLE,
|
||||
- DRCE_ASSERTION_FAILURE ///< user-defined assertions
|
||||
*/
|
||||
|
||||
class DRC_TEST_PROVIDER_MISC : public DRC_TEST_PROVIDER
|
||||
|
@ -69,6 +71,7 @@ private:
|
|||
void testOutline();
|
||||
void testDisabledLayers();
|
||||
void testTextVars();
|
||||
void testAssertions();
|
||||
|
||||
BOARD* m_board;
|
||||
};
|
||||
|
@ -119,6 +122,19 @@ void DRC_TEST_PROVIDER_MISC::testOutline()
|
|||
|
||||
void DRC_TEST_PROVIDER_MISC::testDisabledLayers()
|
||||
{
|
||||
// This is the number of tests between 2 calls to the progress bar
|
||||
const int delta = 2000;
|
||||
|
||||
int ii = 0;
|
||||
int items = 0;
|
||||
|
||||
auto countItems =
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
++items;
|
||||
return true;
|
||||
};
|
||||
|
||||
LSET disabledLayers = m_board->GetEnabledLayers().flip();
|
||||
|
||||
// Perform the test only for copper layers
|
||||
|
@ -127,6 +143,12 @@ void DRC_TEST_PROVIDER_MISC::testDisabledLayers()
|
|||
auto checkDisabledLayers =
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_DISABLED_LAYER_ITEM ) )
|
||||
return false;
|
||||
|
||||
if( !reportProgress( ii++, items, delta ) )
|
||||
return false;
|
||||
|
||||
PCB_LAYER_ID badLayer = UNDEFINED_LAYER;
|
||||
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
|
@ -172,7 +194,7 @@ void DRC_TEST_PROVIDER_MISC::testDisabledLayers()
|
|||
|
||||
if( badLayer != UNDEFINED_LAYER )
|
||||
{
|
||||
std::shared_ptr<DRC_ITEM>drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM );
|
||||
auto drcItem = DRC_ITEM::Create( DRCE_DISABLED_LAYER_ITEM );
|
||||
|
||||
m_msg.Printf( _( "(layer %s)" ), LayerName( badLayer ) );
|
||||
|
||||
|
@ -185,18 +207,78 @@ void DRC_TEST_PROVIDER_MISC::testDisabledLayers()
|
|||
return true;
|
||||
};
|
||||
|
||||
forEachGeometryItem( s_allBasicItems, LSET::AllLayersMask(), countItems );
|
||||
forEachGeometryItem( s_allBasicItems, LSET::AllLayersMask(), checkDisabledLayers );
|
||||
}
|
||||
|
||||
|
||||
void DRC_TEST_PROVIDER_MISC::testAssertions()
|
||||
{
|
||||
// This is the number of tests between 2 calls to the progress bar
|
||||
const int delta = 2000;
|
||||
|
||||
int ii = 0;
|
||||
int items = 0;
|
||||
|
||||
auto countItems =
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
++items;
|
||||
return true;
|
||||
};
|
||||
|
||||
auto checkAssertions =
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_ASSERTION_FAILURE ) )
|
||||
return false;
|
||||
|
||||
if( !reportProgress( ii++, items, delta ) )
|
||||
return false;
|
||||
|
||||
m_drcEngine->ProcessAssertions( item,
|
||||
[&]( const DRC_CONSTRAINT* c )
|
||||
{
|
||||
auto drcItem = DRC_ITEM::Create( DRCE_ASSERTION_FAILURE );
|
||||
drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " (" )
|
||||
+ c->GetName() + wxS( ")" ) );
|
||||
drcItem->SetItems( item );
|
||||
|
||||
reportViolation( drcItem, item->GetPosition() );
|
||||
} );
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
forEachGeometryItem( {}, LSET::AllLayersMask(), countItems );
|
||||
forEachGeometryItem( {}, LSET::AllLayersMask(), checkAssertions );
|
||||
}
|
||||
|
||||
|
||||
void DRC_TEST_PROVIDER_MISC::testTextVars()
|
||||
{
|
||||
auto checkUnresolvedTextVar =
|
||||
// This is the number of tests between 2 calls to the progress bar
|
||||
const int delta = 2000;
|
||||
|
||||
int ii = 0;
|
||||
int items = 0;
|
||||
|
||||
auto countItems =
|
||||
[&]( BOARD_ITEM* item ) -> bool
|
||||
{
|
||||
++items;
|
||||
return true;
|
||||
};
|
||||
|
||||
auto checkTextVars =
|
||||
[&]( EDA_ITEM* item ) -> bool
|
||||
{
|
||||
if( m_drcEngine->IsErrorLimitExceeded( DRCE_UNRESOLVED_VARIABLE ) )
|
||||
return false;
|
||||
|
||||
if( !reportProgress( ii++, items, delta ) )
|
||||
return false;
|
||||
|
||||
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
|
||||
|
||||
if( text && text->GetShownText().Matches( wxT( "*${*}*" ) ) )
|
||||
|
@ -209,8 +291,8 @@ void DRC_TEST_PROVIDER_MISC::testTextVars()
|
|||
return true;
|
||||
};
|
||||
|
||||
forEachGeometryItem( { PCB_FP_TEXT_T, PCB_TEXT_T }, LSET::AllLayersMask(),
|
||||
checkUnresolvedTextVar );
|
||||
forEachGeometryItem( { PCB_FP_TEXT_T, PCB_TEXT_T }, LSET::AllLayersMask(), countItems );
|
||||
forEachGeometryItem( { PCB_FP_TEXT_T, PCB_TEXT_T }, LSET::AllLayersMask(), checkTextVars );
|
||||
|
||||
DS_PROXY_VIEW_ITEM* drawingSheet = m_drcEngine->GetDrawingSheet();
|
||||
DS_DRAW_ITEM_LIST drawItems;
|
||||
|
@ -273,6 +355,14 @@ bool DRC_TEST_PROVIDER_MISC::Run()
|
|||
testTextVars();
|
||||
}
|
||||
|
||||
if( !m_drcEngine->IsErrorLimitExceeded( DRCE_ASSERTION_FAILURE ) )
|
||||
{
|
||||
if( !reportPhase( _( "Checking assertions..." ) ) )
|
||||
return false; // DRC cancelled
|
||||
|
||||
testAssertions();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -840,6 +840,22 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
|||
|
||||
r->Flush();
|
||||
|
||||
r = m_inspectConstraintsDialog->AddPage( _( "Assertions" ) );
|
||||
reportHeader( _( "Assertions for:" ), item, r );
|
||||
|
||||
if( compileError )
|
||||
reportCompileError( r );
|
||||
|
||||
if( courtyardError )
|
||||
{
|
||||
r->Report( "" );
|
||||
r->Report( _( "Report may be incomplete: some footprint courtyards are malformed." )
|
||||
+ " <a href='drc'>" + _( "Run DRC for a full analysis." ) + "</a>" );
|
||||
}
|
||||
|
||||
drcEngine.ProcessAssertions( item, []( const DRC_CONSTRAINT* c ){}, r );
|
||||
r->Flush();
|
||||
|
||||
m_inspectConstraintsDialog->FinishInitialization();
|
||||
m_inspectConstraintsDialog->Raise();
|
||||
m_inspectConstraintsDialog->Show( true );
|
||||
|
|
Loading…
Reference in New Issue