Apply a more sophisticated test for ignoring isInCoupledDiffPair.

The basic problem is that the DRC engine does length testing and skew
testing by collecting all the diff pair constituent parts and pairing them
itself.  Since each part is collected on its own, we need to ignore the
'B' unit when evaluating any conditional expressions.  However, doing this
in general means that when evaluating "OwnClearance()" we also ignore the
'B' unit and return the diff pair CLEARANCE_CONSTRAINT when we shouldn't.

This implements a more discerning test which know what the current requested
constraint is when evaluating expressions.

See also https://forum.kicad.info/t/solved-custom-differencing-rule-not-working-drc/34034/6

Fixes https://gitlab.com/kicad/code/kicad/issues/11314
This commit is contained in:
Jeff Young 2022-04-02 15:08:32 +01:00
parent b18e441a88
commit f7cdc7af75
7 changed files with 46 additions and 35 deletions

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2014 Dick Hollenbeck, dick@softplc.com
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -895,10 +895,15 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
REPORT( wxString::Format( _( "Checking assertion \"%s\"." ),
EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
if( c->constraint.m_Test->EvaluateFor( a, b, aLayer, aReporter ) )
if( c->constraint.m_Test->EvaluateFor( a, b, c->constraint.m_Type, aLayer,
aReporter ) )
{
REPORT( _( "Assertion passed." ) )
}
else
{
REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
}
};
auto processConstraint =
@ -1125,7 +1130,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
EscapeHTML( c->condition->GetExpression() ) ) )
}
if( c->condition->EvaluateFor( a, b, aLayer, aReporter ) )
if( c->condition->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
{
if( aReporter )
{
@ -1321,7 +1326,8 @@ void DRC_ENGINE::ProcessAssertions( const BOARD_ITEM* a,
REPORT( wxString::Format( _( "Checking rule assertion \"%s\"." ),
EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
if( c->constraint.m_Test->EvaluateFor( a, nullptr, a->GetLayer(), aReporter ) )
if( c->constraint.m_Test->EvaluateFor( a, nullptr, c->constraint.m_Type,
a->GetLayer(), aReporter ) )
{
REPORT( _( "Assertion passed." ) )
}
@ -1354,7 +1360,8 @@ void DRC_ENGINE::ProcessAssertions( const BOARD_ITEM* a,
REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
EscapeHTML( c->condition->GetExpression() ) ) )
if( c->condition->EvaluateFor( a, nullptr, a->GetLayer(), aReporter ) )
if( c->condition->EvaluateFor( a, nullptr, c->constraint.m_Type,
a->GetLayer(), aReporter ) )
{
REPORT( _( "Rule applied." ) )
testAssertion( c );

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2020-2022 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -41,7 +41,7 @@ DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB,
PCB_LAYER_ID aLayer, REPORTER* aReporter )
int aConstraint, PCB_LAYER_ID aLayer, REPORTER* aReporter )
{
if( GetExpression().IsEmpty() )
return true;
@ -54,7 +54,7 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM
return false;
}
PCB_EXPR_CONTEXT ctx( aLayer );
PCB_EXPR_CONTEXT ctx( aConstraint, aLayer );
if( aReporter )
{
@ -109,7 +109,7 @@ bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSou
m_ucode = std::make_unique<PCB_EXPR_UCODE>();
PCB_EXPR_CONTEXT preflightContext( F_Cu );
PCB_EXPR_CONTEXT preflightContext( 0, F_Cu );
bool ok = compiler.Compile( GetExpression().ToUTF8().data(), m_ucode.get(), &preflightContext );
return ok;

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2020-2022 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -38,8 +38,8 @@ public:
DRC_RULE_CONDITION( const wxString& aExpression = "" );
~DRC_RULE_CONDITION();
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, PCB_LAYER_ID aLayer,
REPORTER* aReporter = nullptr );
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB, int aConstraint,
PCB_LAYER_ID aLayer, REPORTER* aReporter = nullptr );
bool Compile( REPORTER* aReporter, int aSourceLine = 0, int aSourceOffset = 0 );

View File

@ -333,7 +333,7 @@ bool DRC_TEST_PROVIDER_MATCHED_LENGTH::runInternal( bool aDelayReportMode )
}
else
{
ent.from = ent.to = _("<unconstrained>");
ent.from = ent.to = _( "<unconstrained>" );
}
m_report.Add( ent );

View File

@ -784,20 +784,27 @@ static void isCoupledDiffPair( LIBEVAL::CONTEXT* aCtx, void* self )
aCtx->Push( result );
result->SetDeferredEval(
[a, b]() -> double
[a, b, context]() -> double
{
NETINFO_ITEM* netinfo = a ? a->GetNet() : nullptr;
wxString coupledNet;
wxString dummy;
if( netinfo
&& DRC_ENGINE::MatchDpSuffix( netinfo->GetNetname(), coupledNet, dummy )
&& ( !b || b->GetNetname() == coupledNet ) )
if( !netinfo )
return 0.0;
wxString coupledNet;
wxString dummy;
if( !DRC_ENGINE::MatchDpSuffix( netinfo->GetNetname(), coupledNet, dummy ) )
return 0.0;
if( context->GetConstraint() == DRC_CONSTRAINT_T::LENGTH_CONSTRAINT
|| context->GetConstraint() == DRC_CONSTRAINT_T::SKEW_CONSTRAINT )
{
// DRC engine evaluates these singly, so we won't have a B item
return 1.0;
}
return 0.0;
return b && b->GetNetname() == coupledNet;
} );
}
@ -1227,12 +1234,12 @@ PCB_EXPR_EVALUATOR::~PCB_EXPR_EVALUATOR()
bool PCB_EXPR_EVALUATOR::Evaluate( const wxString& aExpr )
{
PCB_EXPR_UCODE ucode;
PCB_EXPR_CONTEXT preflightContext( F_Cu );
PCB_EXPR_CONTEXT preflightContext( NULL_CONSTRAINT, F_Cu );
if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
return false;
PCB_EXPR_CONTEXT evaluationContext( F_Cu );
PCB_EXPR_CONTEXT evaluationContext( NULL_CONSTRAINT, F_Cu );
LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
if( result->GetType() == LIBEVAL::VT_NUMERIC )

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -52,7 +52,8 @@ public:
class PCB_EXPR_CONTEXT : public LIBEVAL::CONTEXT
{
public:
PCB_EXPR_CONTEXT( PCB_LAYER_ID aLayer = UNDEFINED_LAYER ) :
PCB_EXPR_CONTEXT( int aConstraint, PCB_LAYER_ID aLayer ) :
m_constraint( aConstraint ),
m_layer( aLayer )
{
m_items[0] = nullptr;
@ -67,17 +68,12 @@ public:
BOARD* GetBoard() const;
BOARD_ITEM* GetItem( int index ) const
{
return m_items[index];
}
PCB_LAYER_ID GetLayer() const
{
return m_layer;
}
int GetConstraint() const { return m_constraint; }
BOARD_ITEM* GetItem( int index ) const { return m_items[index]; }
PCB_LAYER_ID GetLayer() const { return m_layer; }
private:
int m_constraint;
BOARD_ITEM* m_items[2];
PCB_LAYER_ID m_layer;
};

View File

@ -27,7 +27,7 @@
#include <layer_ids.h>
#include <pcbnew/pcb_expr_evaluator.h>
#include <drc/drc_rule.h>
#include <pcbnew/board.h>
#include <pcbnew/pcb_track.h>
@ -91,7 +91,8 @@ static bool testEvalExpr( const wxString& expr, LIBEVAL::VALUE expectedResult,
{
PCB_EXPR_COMPILER compiler;
PCB_EXPR_UCODE ucode;
PCB_EXPR_CONTEXT context, preflightContext;
PCB_EXPR_CONTEXT context( NULL_CONSTRAINT, UNDEFINED_LAYER );
PCB_EXPR_CONTEXT preflightContext( NULL_CONSTRAINT, UNDEFINED_LAYER );
bool ok = true;
context.SetItems( itemA, itemB );