Add ERC & DRC checks for unresolved variables.

This commit is contained in:
Jeff Young 2020-03-29 02:12:29 +01:00
parent 4990d1e7b2
commit 41b5872f12
21 changed files with 249 additions and 62 deletions

View File

@ -168,8 +168,8 @@ wxString EDA_TEXT::ShortenedShownText() const
tmp.Replace( wxT( "\r" ), wxT( " " ) );
tmp.Replace( wxT( "\t" ), wxT( " " ) );
if( tmp.Length() > 15 )
tmp = tmp.Left( 12 ) + wxT( "..." );
if( tmp.Length() > 36 )
tmp = tmp.Left( 34 ) + wxT( "..." );
return tmp;
}

View File

@ -322,12 +322,12 @@ bool DIALOG_LABEL_EDITOR::TransferDataFromWindow()
return false;
}
m_CurrentText->SetLabelSpinStyle( m_TextOrient->GetSelection() );
m_CurrentText->SetLabelSpinStyle( (LABEL_SPIN_STYLE::SPIN) m_TextOrient->GetSelection() );
m_CurrentText->SetTextSize( wxSize( m_textSize.GetValue(), m_textSize.GetValue() ) );
if( m_TextShape )
m_CurrentText->SetShape( static_cast<PINSHEETLABEL_SHAPE>( m_TextShape->GetSelection() ) );
m_CurrentText->SetShape( (PINSHEETLABEL_SHAPE) m_TextShape->GetSelection() );
int style = m_TextStyle->GetSelection();

View File

@ -316,6 +316,9 @@ void DIALOG_ERC::TestErc( REPORTER& aReporter )
objectsConnectedList->TestforSimilarLabels();
}
if( g_ErcSettings->IsTestEnabled( ERCE_UNRESOLVED_VARIABLE ) )
TestTextVars();
// Display diags:
m_markerTreeModel->SetProvider( m_markerProvider );

View File

@ -246,7 +246,7 @@ void DIALOG_GLOBAL_EDIT_TEXT_AND_GRAPHICS::processItem( const SCH_SHEET_PATH& aS
{
if( m_orientation->GetStringSelection() != INDETERMINATE )
{
sch_text->SetLabelSpinStyle( m_orientation->GetSelection() );
sch_text->SetLabelSpinStyle( (LABEL_SPIN_STYLE::SPIN) m_orientation->GetSelection() );
m_hasChange = true;
}
}

View File

@ -353,27 +353,27 @@ void PANEL_EESCHEMA_COLOR_SETTINGS::createPreviewItems()
addItem( e2 );
auto t1 = new SCH_TEXT( wxPoint( Mils2iu( 2850 ), Mils2iu( 2250 ) ), wxT( "PLAIN TEXT" ) );
t1->SetLabelSpinStyle( 0 );
t1->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::LEFT );
addItem( t1 );
auto t2 = new SCH_LABEL( wxPoint( Mils2iu( 1975 ), Mils2iu( 1500 ) ), wxT( "GLOBAL0" ) );
t2->SetLabelSpinStyle( 2 );
t2->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
t2->SetIsDangling( false );
addItem( t2 );
auto t3 = new SCH_LABEL( wxPoint( Mils2iu( 1975 ), Mils2iu( 2600 ) ), wxT( "GLOBAL1" ) );
t3->SetLabelSpinStyle( 2 );
t3->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
t3->SetIsDangling( false );
addItem( t3 );
auto t4 = new SCH_GLOBALLABEL(
wxPoint( Mils2iu( 1750 ), Mils2iu( 1400 ) ), wxT( "GLOBAL[3..0]" ) );
t4->SetLabelSpinStyle( 0 );
t4->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::LEFT );
t4->SetIsDangling( false );
addItem( t4 );
auto t5 = new SCH_HIERLABEL( wxPoint( Mils2iu( 3250 ), Mils2iu( 1600 ) ), wxT( "HIER_LABEL" ) );
t5->SetLabelSpinStyle( 2 );
t5->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
t5->SetIsDangling( false );
addItem( t5 );

View File

@ -198,6 +198,73 @@ int TestDuplicateSheetNames( bool aCreateMarker )
}
void TestTextVars()
{
SCH_SCREENS screens;
for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
{
for( SCH_ITEM* item : screen->Items().OfType( SCH_LOCATE_ANY_T ) )
{
if( item->Type() == SCH_COMPONENT_T )
{
SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
for( SCH_FIELD& field : component->GetFields() )
{
if( field.GetShownText().Matches( wxT( "*${*}*" ) ) )
{
wxPoint delta = field.GetPosition() - component->GetPosition();
delta = component->GetTransform().TransformCoordinate( delta );
SCH_MARKER* marker = new SCH_MARKER( MARKER_BASE::MARKER_ERC );
marker->SetData( EDA_UNITS::UNSCALED, ERCE_UNRESOLVED_VARIABLE,
component->GetPosition() + delta, &field );
screen->Append( marker );
}
}
}
else if( item->Type() == SCH_SHEET_T )
{
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
for( SCH_FIELD& field : sheet->GetFields() )
{
if( field.GetShownText().Matches( wxT( "*${*}*" ) ) )
{
SCH_MARKER* marker = new SCH_MARKER( MARKER_BASE::MARKER_ERC );
marker->SetData( EDA_UNITS::UNSCALED, ERCE_UNRESOLVED_VARIABLE,
field.GetPosition(), &field );
screen->Append( marker );
}
}
for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
{
if( pin->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
SCH_MARKER* marker = new SCH_MARKER( MARKER_BASE::MARKER_ERC );
marker->SetData( EDA_UNITS::UNSCALED, ERCE_UNRESOLVED_VARIABLE,
pin->GetPosition(), pin );
screen->Append( marker );
}
}
}
else if( SCH_TEXT* text = dynamic_cast<SCH_TEXT*>( item ) )
{
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
SCH_MARKER* marker = new SCH_MARKER( MARKER_BASE::MARKER_ERC );
marker->SetData( EDA_UNITS::UNSCALED, ERCE_UNRESOLVED_VARIABLE,
text->GetPosition(), text );
screen->Append( marker );
}
}
}
}
}
int TestConflictingBusAliases()
{
wxString msg;
@ -205,7 +272,7 @@ int TestConflictingBusAliases()
SCH_SCREENS screens;
std::vector< std::shared_ptr<BUS_ALIAS> > aliases;
for( auto screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
for( SCH_SCREEN* screen = screens.GetFirst(); screen != NULL; screen = screens.GetNext() )
{
std::unordered_set< std::shared_ptr<BUS_ALIAS> > screen_aliases = screen->GetBusAliases();

View File

@ -72,7 +72,8 @@ enum ERCE_T
ERCE_BUS_TO_BUS_CONFLICT, // a connection between bus objects doesn't share at least one net
ERCE_BUS_TO_NET_CONFLICT, // a bus wire is graphically connected to a net port/pin (or vice versa)
ERCE_GLOBLABEL, // a global label is unique
ERCE_LAST = ERCE_GLOBLABEL
ERCE_UNRESOLVED_VARIABLE,
ERCE_LAST = ERCE_UNRESOLVED_VARIABLE
};
/* Minimal connection table */
@ -113,6 +114,12 @@ void TestOthersItems( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned
*/
int TestDuplicateSheetNames( bool aCreateMarker );
/**
* Function TestTextVars()
* Checks for any unresolved text variable references.
*/
void TestTextVars();
/**
* Checks that there are not conflicting bus alias definitions in the schematic
*

View File

@ -74,6 +74,8 @@ wxString ERC_ITEM::GetErrorText() const
return wxString( _( "Invalid connection between bus and net items" ) );
case ERCE_GLOBLABEL:
return wxString( _( "Global label not connected anywhere else in the schematic" ) );
case ERCE_UNRESOLVED_VARIABLE:
return wxString( _( "Unresolved text variable" ) );
default:
wxFAIL_MSG( "Missing ERC error description" );
return wxString( wxT("Unknown.") );

View File

@ -429,7 +429,7 @@ void LIB_FIELD::SetName( const wxString& aName )
wxString LIB_FIELD::GetSelectMenuText( EDA_UNITS aUnits ) const
{
return wxString::Format( _( "Field %s \"%s\"" ),
return wxString::Format( _( "Field %s (%s)" ),
GetName(),
ShortenedShownText() );
}

View File

@ -343,7 +343,11 @@ void SCH_BASE_FRAME::FocusOnItem( SCH_ITEM* aItem )
if( aItem->GetParent() && aItem->GetParent()->Type() == SCH_COMPONENT_T )
{
SCH_COMPONENT* comp = static_cast<SCH_COMPONENT*>( aItem->GetParent() );
position += comp->GetPosition();
wxPoint delta;
position -= comp->GetPosition();
delta = comp->GetTransform().TransformCoordinate( position );
position = delta + comp->GetPosition();
}
FocusOnLocation( position );

View File

@ -1017,7 +1017,7 @@ SCH_TEXT* SCH_EAGLE_PLUGIN::loadLabel( wxXmlNode* aLabelNode, const wxString& aN
if( elabel.rot )
{
label->SetLabelSpinStyle( KiROUND( elabel.rot->degrees / 90 ) % 4 );
label->SetLabelSpinStyle( (LABEL_SPIN_STYLE::SPIN) ( KiROUND( elabel.rot->degrees / 90 ) % 4 ) );
if( elabel.rot->mirror )
{

View File

@ -1059,6 +1059,12 @@ void SCH_EDIT_FRAME::UpdateTitle()
}
int SCH_EDIT_FRAME::GetSeverity( int aErrorCode ) const
{
return ::GetSeverity( aErrorCode );
}
void SCH_EDIT_FRAME::RecalculateConnections( SCH_CLEANUP_FLAGS aCleanupFlags )
{
SCH_SHEET_LIST list( g_RootSheet );

View File

@ -549,6 +549,9 @@ public:
*/
int ModalAnnotate( const wxString& aMessage );
///> @copydoc EDA_BASE_FRAME::GetSeverity()
int GetSeverity( int aErrorCode ) const override;
// Functions used for hierarchy handling
SCH_SHEET_PATH& GetCurrentSheet();

View File

@ -501,7 +501,9 @@ void SCH_FIELD::Rotate( wxPoint aPosition )
wxString SCH_FIELD::GetSelectMenuText( EDA_UNITS aUnits ) const
{
return wxString::Format( _( "Field %s" ), GetName() );
return wxString::Format( _( "Field %s (%s)" ),
GetName(),
ShortenedShownText() );
}

View File

@ -1406,7 +1406,7 @@ SCH_TEXT* SCH_LEGACY_PLUGIN::loadText( LINE_READER& aReader )
spinStyle = 0;
}
text->SetLabelSpinStyle( spinStyle );
text->SetLabelSpinStyle( (LABEL_SPIN_STYLE::SPIN) spinStyle );
int size = Mils2Iu( parseInt( aReader, line, &line ) );

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2020 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
@ -40,7 +40,7 @@
#include <gal/stroke_font.h>
#include <bitmaps.h>
#include <math/util.h> // for KiROUND
#include <kiway.h>
#include <sch_text.h>
#include <netlist_object.h>
#include <settings/color_settings.h>
@ -446,6 +446,69 @@ const EDA_RECT SCH_TEXT::GetBoundingBox() const
}
wxString getElectricalTypeLabel( PINSHEETLABEL_SHAPE aType )
{
switch( aType )
{
case PINSHEETLABEL_SHAPE::PS_INPUT: return _( "Input" );
case PINSHEETLABEL_SHAPE::PS_OUTPUT: return _( "Output" );
case PINSHEETLABEL_SHAPE::PS_BIDI: return _( "Bidirectional" );
case PINSHEETLABEL_SHAPE::PS_TRISTATE: return _( "Tri-State" );
case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED: return _( "Passive" );
default: return wxT( "???" );
}
}
wxString SCH_TEXT::GetShownText() const
{
auto textResolver = [this]( wxString* token ) -> bool
{
if( ( Type() == SCH_GLOBAL_LABEL_T
|| Type() == SCH_HIER_LABEL_T
|| Type() == SCH_SHEET_PIN_T )
&& token->IsSameAs( wxT( "CONNECTION_TYPE" ) ) )
{
*token = getElectricalTypeLabel( GetShape() );
return true;
}
if( Type() == SCH_SHEET_PIN_T && m_Parent )
{
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( m_Parent );
std::vector<SCH_FIELD>& fields = sheet->GetFields();
for( int i = 0; i < SHEET_MANDATORY_FIELDS; ++i )
{
if( token->IsSameAs( fields[i].GetCanonicalName().Upper() ) )
{
*token = fields[i].GetShownText();
return true;
}
}
for( int i = SHEET_MANDATORY_FIELDS; i < fields.size(); ++i )
{
if( token->IsSameAs( fields[i].GetName() ) )
{
*token = fields[i].GetShownText();
return true;
}
}
}
return false;
};
PROJECT* project = nullptr;
if( g_RootSheet && g_RootSheet->GetScreen() )
project = &g_RootSheet->GetScreen()->Kiway().Prj();
return ExpandTextVars( GetText(), textResolver, project );
}
wxString SCH_TEXT::GetSelectMenuText( EDA_UNITS aUnits ) const
{
return wxString::Format( _( "Graphic Text \"%s\"" ), GetChars( ShortenedShownText() ) );
@ -597,16 +660,7 @@ void SCH_TEXT::GetMsgPanelInfo( EDA_UNITS aUnits, MSG_PANEL_ITEMS& aList )
// Display electrical type if it is relevant
if( Type() == SCH_GLOBAL_LABEL_T || Type() == SCH_HIER_LABEL_T || Type() == SCH_SHEET_PIN_T )
{
switch( GetShape() )
{
case PINSHEETLABEL_SHAPE::PS_INPUT: msg = _( "Input" ); break;
case PINSHEETLABEL_SHAPE::PS_OUTPUT: msg = _( "Output" ); break;
case PINSHEETLABEL_SHAPE::PS_BIDI: msg = _( "Bidirectional" ); break;
case PINSHEETLABEL_SHAPE::PS_TRISTATE: msg = _( "Tri-State" ); break;
case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED: msg = _( "Passive" ); break;
default: msg = wxT( "???" ); break;
}
msg = getElectricalTypeLabel( GetShape() );
aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg, BLUE ) );
}

View File

@ -55,31 +55,21 @@ public:
{
}
LABEL_SPIN_STYLE( int aSpin )
{
m_spin = static_cast<SPIN>( aSpin );
}
constexpr bool operator==( SPIN a ) const
{
return m_spin == a;
}
constexpr bool operator!=( SPIN a ) const
{
return m_spin != a;
}
operator int() const
{
return static_cast<int>( m_spin );
}
LABEL_SPIN_STYLE RotateCW()
{
SPIN newSpin = m_spin;
@ -96,7 +86,6 @@ public:
return LABEL_SPIN_STYLE( newSpin );
}
LABEL_SPIN_STYLE RotateCCW()
{
SPIN newSpin = m_spin;
@ -113,7 +102,6 @@ public:
return LABEL_SPIN_STYLE( newSpin );
}
/*
* Mirrors the label spin style across the X axis or simply swaps up and bottom
*/
@ -133,7 +121,6 @@ public:
return LABEL_SPIN_STYLE( newSpin );
}
/*
* Mirrors the label spin style across the Y axis or simply swaps left and right
*/
@ -220,6 +207,8 @@ public:
return wxT( "SCH_TEXT" );
}
wxString GetShownText() const override;
/**
* Increment the label text, if it ends with a number.
*

View File

@ -235,9 +235,6 @@ wxString SCH_NETNAME_VALIDATOR::IsValid( const wxString& str ) const
if( SCH_CONNECTION::IsBusGroupLabel( str ) )
return wxString();
if( str.Contains( '{' ) || str.Contains( '}' ) )
return _( "Signal name contains '{' or '}' but is not a valid group bus name" );
if( ( str.Contains( '[' ) || str.Contains( ']' ) ) &&
!SCH_CONNECTION::IsBusVectorLabel( str ) )
return _( "Signal name contains '[' or ']' but is not a valid vector bus name" );

View File

@ -484,6 +484,9 @@ void DRC::RunTests( wxTextCtrl* aMessages )
aMessages->Refresh();
}
if( !m_pcb->GetDesignSettings().Ignore( DRCE_UNRESOLVED_VARIABLE ) )
testTextVars();
m_drcRun = true;
// update the m_drcDialog listboxes
@ -1160,31 +1163,73 @@ void DRC::testDisabledLayers()
// Perform the test only for copper layers
disabledLayers &= LSET::AllCuMask();
auto createMarker = [&]( BOARD_ITEM* aItem ) {
addMarkerToPcb( new MARKER_PCB( userUnits(), DRCE_DISABLED_LAYER_ITEM,
aItem->GetPosition(), aItem ) );
};
for( auto track : board->Tracks() )
for( TRACK* track : board->Tracks() )
{
if( disabledLayers.test( track->GetLayer() ) )
createMarker( track );
{
addMarkerToPcb( new MARKER_PCB( userUnits(), DRCE_DISABLED_LAYER_ITEM,
track->GetPosition(), track ) );
}
}
for( auto module : board->Modules() )
for( MODULE* module : board->Modules() )
{
module->RunOnChildren(
[&]( BOARD_ITEM* aItem )
[&]( BOARD_ITEM* child )
{
if( disabledLayers.test( aItem->GetLayer() ) )
createMarker( aItem );
if( disabledLayers.test( child->GetLayer() ) )
{
addMarkerToPcb( new MARKER_PCB( userUnits(), DRCE_DISABLED_LAYER_ITEM,
child->GetPosition(), child ) );
}
} );
}
for( auto zone : board->Zones() )
for( ZONE_CONTAINER* zone : board->Zones() )
{
if( disabledLayers.test( zone->GetLayer() ) )
createMarker( zone );
{
addMarkerToPcb( new MARKER_PCB( userUnits(), DRCE_DISABLED_LAYER_ITEM,
zone->GetPosition(), zone ) );
}
}
}
void DRC::testTextVars()
{
BOARD* board = m_pcbEditorFrame->GetBoard();
for( MODULE* module : board->Modules() )
{
module->RunOnChildren(
[&]( BOARD_ITEM* child )
{
if( child->Type() == PCB_MODULE_TEXT_T )
{
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( child );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
addMarkerToPcb( new MARKER_PCB( userUnits(), DRCE_UNRESOLVED_VARIABLE,
text->GetPosition(), text ) );
}
}
} );
}
for( BOARD_ITEM* drawing : board->Drawings() )
{
if( drawing->Type() == PCB_TEXT_T )
{
TEXTE_PCB* text = static_cast<TEXTE_PCB*>( drawing );
if( text->GetShownText().Matches( wxT( "*${*}*" ) ) )
{
addMarkerToPcb( new MARKER_PCB( userUnits(), DRCE_UNRESOLVED_VARIABLE,
text->GetPosition(), text ) );
}
}
}
}

View File

@ -100,7 +100,9 @@ enum PCB_DRC_CODE {
DRCE_ZERO_LENGTH_TRACK,
DRCE_TRACK_IN_PAD,
DRCE_LAST = DRCE_TRACK_IN_PAD
DRCE_UNRESOLVED_VARIABLE,
DRCE_LAST = DRCE_UNRESOLVED_VARIABLE
};
@ -246,9 +248,12 @@ private:
void testCopperTextAndGraphics();
///> Tests for items placed on disabled layers (causing false connections).
// Tests for items placed on disabled layers (causing false connections).
void testDisabledLayers();
// Test for any unresolved text variable references
void testTextVars();
/**
* Test that the board outline is contiguous and composed of valid elements
*/

View File

@ -158,6 +158,9 @@ wxString DRC_ITEM::GetErrorText() const
case DRCE_TRACK_IN_PAD:
return wxString( _( "Remove track inside pad" ) );
case DRCE_UNRESOLVED_VARIABLE:
return wxString( _( "Unresolved text variable" ) );
default:
return wxEmptyString;
}