Schematic parity checking for CLI DRC.

This commit is contained in:
Jeff Young 2024-02-02 23:04:56 +00:00
parent 3a95bd1bd1
commit 7cc663ad77
25 changed files with 164 additions and 64 deletions

View File

@ -34,7 +34,7 @@ namespace BMP2CMP {
static struct IFACE : public KIFACE_BASE
{
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
wxWindow* CreateKiWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway,
int aCtlBits = 0 ) override
@ -103,7 +103,7 @@ PGM_BASE* PgmOrNull()
#endif
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
return start_common( aCtlBits );
}

View File

@ -24,7 +24,8 @@
#include <wx/debug.h>
JOB_DISPATCHER::JOB_DISPATCHER()
JOB_DISPATCHER::JOB_DISPATCHER( KIWAY* aKiway ) :
m_kiway( aKiway )
{
m_reporter = &NULL_REPORTER::GetInstance();
m_progressReporter = nullptr;

View File

@ -27,19 +27,21 @@
#include <jobs/job.h>
class KIWAY;
class REPORTER;
class PROGRESS_REPORTER;
class JOB_DISPATCHER
{
public:
JOB_DISPATCHER();
JOB_DISPATCHER( KIWAY* aKiway );
void Register( const std::string& aJobTypeName, std::function<int( JOB* job )> aHandler );
int RunJob( JOB* job );
void SetReporter( REPORTER* aReporter );
void SetProgressReporter( PROGRESS_REPORTER* aReporter );
protected:
KIWAY* m_kiway; // non-owning
REPORTER* m_reporter; // non-owning
PROGRESS_REPORTER* m_progressReporter; // non-owning

View File

@ -29,6 +29,6 @@ JOB_PCB_DRC::JOB_PCB_DRC( bool aIsCli ) :
m_severity( RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING ),
m_format( OUTPUT_FORMAT::REPORT ),
m_exitCodeViolations( false ),
m_parity( false )
m_parity( true )
{
}

View File

@ -311,7 +311,7 @@ KIFACE* KIWAY::KiFACE( FACE_T aFaceId, bool doLoad )
try
{
startSuccess = kiface->OnKifaceStart( m_program, m_ctl );
startSuccess = kiface->OnKifaceStart( m_program, m_ctl, this );
}
catch (...)
{

View File

@ -34,9 +34,41 @@
#include <settings/cvpcb_settings.h>
#include <display_footprints_frame.h>
#include <kiface_ids.h>
#include <project_pcb.h>
namespace CV {
int testFootprintLink( const wxString& aFootprint, PROJECT* aProject )
{
FP_LIB_TABLE* libTable = PROJECT_PCB::PcbFootprintLibs( aProject );
const FP_LIB_TABLE_ROW* libTableRow = nullptr;
LIB_ID fpID;
fpID.Parse( aFootprint );
wxString libName = fpID.GetLibNickname();
wxString fpName = fpID.GetLibItemName();
try
{
libTableRow = libTable->FindRow( libName );
}
catch( const IO_ERROR& )
{
// Error state processed below
}
if( !libTableRow )
return KIFACE_TEST_FOOTPRINT_LINK_NO_LIBRARY;
else if( !libTable->HasLibrary( libName, true ) )
return KIFACE_TEST_FOOTPRINT_LINK_LIBRARY_NOT_ENABLED;
else if( !libTable->FootprintExists( libName, fpName ) )
return KIFACE_TEST_FOOTPRINT_LINK_NO_FOOTPRINT;
else
return 0;
}
static struct IFACE : public KIFACE_BASE
{
// Of course all are virtual overloads, implementations of the KIFACE.
@ -45,7 +77,7 @@ static struct IFACE : public KIFACE_BASE
KIFACE_BASE( aName, aType )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void OnKifaceEnd() override;
@ -86,6 +118,9 @@ static struct IFACE : public KIFACE_BASE
case KIFACE_GLOBAL_FOOTPRINT_TABLE:
return (void*) &GFootprintTable;
case KIFACE_TEST_FOOTPRINT_LINK:
return (void*) testFootprintLink;
default:
return nullptr;
}
@ -145,7 +180,7 @@ FOOTPRINT_LIST_IMPL GFootprintList;
// A short lived implementation. cvpcb will get combine into Pcbnew shortly, so
// we skip setting KICAD7_FOOTPRINT_DIR here for now. User should set the environment
// variable.
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
// This is process level, not project level, initialization of the DSO.

View File

@ -488,7 +488,8 @@ void DIALOG_ERC::testErc()
{
wxBusyCursor dummy;
tester.RunTests( m_parent->GetCanvas()->GetView()->GetDrawingSheet(), m_parent, this );
tester.RunTests( m_parent->GetCanvas()->GetView()->GetDrawingSheet(), m_parent,
m_parent->Kiway().KiFACE( KIWAY::FACE_CVPCB ), &m_parent->Prj(), this );
}
// Update marker list:

View File

@ -117,7 +117,7 @@ static std::unique_ptr<SCHEMATIC> readSchematicFromFile( const std::string& aFil
}
bool generateSchematicNetlist( const wxString& aFilename, wxString& aNetlist )
bool generateSchematicNetlist( const wxString& aFilename, std::string& aNetlist )
{
std::unique_ptr<SCHEMATIC> schematic = readSchematicFromFile( aFilename.ToStdString() );
NETLIST_EXPORTER_KICAD exporter( schematic.get() );
@ -139,7 +139,7 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
UNITS_PROVIDER( schIUScale, EDA_UNITS::MILLIMETRES )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void Reset() override;
@ -373,7 +373,7 @@ PGM_BASE* PgmOrNull()
}
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
// This is process-level-initialization, not project-level-initialization of the DSO.
// Do nothing in here pertinent to a project!
@ -394,7 +394,7 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
if( !loadGlobalLibTable() )
return false;
m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>();
m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>( aKiway );
if( m_start_flags & KFCTL_CLI )
{

View File

@ -37,6 +37,7 @@
#include <memory>
#include <connection_graph.h>
#include "eeschema_helpers.h"
#include <kiway.h>
#include <sch_painter.h>
#include <locale_io.h>
#include <erc.h>
@ -64,7 +65,8 @@
#include <fields_data_model.h>
EESCHEMA_JOBS_HANDLER::EESCHEMA_JOBS_HANDLER()
EESCHEMA_JOBS_HANDLER::EESCHEMA_JOBS_HANDLER( KIWAY* aKiway ) :
JOB_DISPATCHER( aKiway )
{
Register( "bom",
std::bind( &EESCHEMA_JOBS_HANDLER::JobExportBom, this, std::placeholders::_1 ) );
@ -981,7 +983,8 @@ int EESCHEMA_JOBS_HANDLER::JobSchErc( JOB* aJob )
m_reporter->Report( _( "Running ERC...\n" ), RPT_SEVERITY_INFO );
std::unique_ptr<DS_PROXY_VIEW_ITEM> drawingSheet( getDrawingSheetProxyView( sch ) );
ercTester.RunTests( drawingSheet.get(), nullptr, m_progressReporter );
ercTester.RunTests( drawingSheet.get(), nullptr, m_kiway->KiFACE( KIWAY::FACE_CVPCB ),
&sch->Prj(), m_progressReporter );
markersProvider->SetSeverities( ercJob->m_severity );

View File

@ -29,6 +29,7 @@ namespace KIGFX
class SCH_RENDER_SETTINGS;
};
class KIWAY;
class SCHEMATIC;
class JOB_SYM_EXPORT_SVG;
class LIB_SYMBOL;
@ -40,7 +41,7 @@ class DS_PROXY_VIEW_ITEM;
class EESCHEMA_JOBS_HANDLER : public JOB_DISPATCHER
{
public:
EESCHEMA_JOBS_HANDLER();
EESCHEMA_JOBS_HANDLER( KIWAY* aKiway );
int JobExportBom( JOB* aJob );
int JobExportPythonBom( JOB* aJob );
int JobExportNetlist( JOB* aJob );

View File

@ -50,6 +50,7 @@
#include <wx/ffile.h>
#include <sim/sim_lib_mgr.h>
#include <progress_reporter.h>
#include <kiway.h>
/* ERC tests :
@ -1136,7 +1137,7 @@ int ERC_TESTER::TestSimModelIssues()
void ERC_TESTER::RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aEditFrame,
PROGRESS_REPORTER* aProgressReporter )
KIFACE* aCvPcb, PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter )
{
ERC_SETTINGS& settings = m_schematic->ErcSettings();

View File

@ -23,19 +23,19 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef _ERC_H
#define _ERC_H
#ifndef ERC_H
#define ERC_H
#include <erc_settings.h>
class NETLIST_OBJECT;
class NETLIST_OBJECT_LIST;
class SCH_SHEET_LIST;
class SCHEMATIC;
class DS_PROXY_VIEW_ITEM;
class SCH_EDIT_FRAME;
class PROGRESS_REPORTER;
struct KIFACE;
class PROJECT;
extern const wxString CommentERC_H[];
@ -136,7 +136,7 @@ public:
int TestMissingNetclasses();
void RunTests( DS_PROXY_VIEW_ITEM* aDrawingSheet, SCH_EDIT_FRAME* aEditFrame,
PROGRESS_REPORTER* aProgressReporter );
KIFACE* aCvPcb, PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter );
private:
@ -144,4 +144,4 @@ private:
};
#endif // _ERC_H
#endif // ERC_H

View File

@ -51,7 +51,8 @@ enum ERCE_T
ERCE_SIMILAR_LABELS, ///< 2 labels are equal for case insensitive comparisons.
ERCE_DIFFERENT_UNIT_FP, ///< Different units of the same symbol have different
///< footprints assigned.
ERCE_MISSING_POWER_INPUT_PIN, ///< Symbol has power input pins that are not placed on the schematic
ERCE_MISSING_POWER_INPUT_PIN, ///< Symbol has power input pins that are not placed on the
///< schematic
ERCE_MISSING_INPUT_PIN, ///< Symbol has input pins that are not placed
ERCE_MISSING_BIDI_PIN, ///< Symbol has bi-directional pins that are not placed
ERCE_MISSING_UNIT, ///< Symbol has units that are not placed on the schematic

View File

@ -56,7 +56,7 @@ static struct IFACE : public KIFACE_BASE
KIFACE_BASE( aName, aType )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void OnKifaceEnd() override;
@ -145,7 +145,7 @@ PGM_BASE* PgmOrNull()
}
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
InitSettings( new GERBVIEW_SETTINGS );
aProgram->GetSettingsManager().RegisterSettings( KifaceSettings() );

View File

@ -41,7 +41,7 @@ public:
/**
* Typically #start_common() is called from here.
*/
virtual bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override = 0;
virtual bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override = 0;
virtual void OnKifaceEnd() override
{

View File

@ -55,7 +55,12 @@ enum KIFACE_ADDR_ID : int
KIFACE_LOAD_SCHEMATIC,
KIFACE_NETLIST_SCHEMATIC,
KIFACE_SCRIPTING_LEGACY,
KIFACE_SCRIPTING
KIFACE_SCRIPTING,
KIFACE_TEST_FOOTPRINT_LINK,
KIFACE_TEST_FOOTPRINT_LINK_NO_LIBRARY,
KIFACE_TEST_FOOTPRINT_LINK_LIBRARY_NOT_ENABLED,
KIFACE_TEST_FOOTPRINT_LINK_NO_FOOTPRINT
};
#endif // KIFACE_IDS

View File

@ -174,7 +174,7 @@ struct KIFACE
* any UI because that is the duty of this function to say why it is returning
* false. Never return false without having reported to the UI why.
*/
virtual bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) = 0;
virtual bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) = 0;
/**
* Called just once just before the DSO is to be unloaded.

View File

@ -50,7 +50,7 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
UNITS_PROVIDER( drawSheetIUScale, EDA_UNITS::MILLIMETRES )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void OnKifaceEnd() override;
@ -152,7 +152,7 @@ PGM_BASE* PgmOrNull()
return process;
}
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
InitSettings( new PL_EDITOR_SETTINGS );
aProgram->GetSettingsManager().RegisterSettings( KifaceSettings() );

View File

@ -39,7 +39,7 @@ static struct IFACE : public KIFACE_BASE
KIFACE_BASE( aName, aType )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void OnKifaceEnd() override;
@ -100,7 +100,7 @@ PGM_BASE* PgmOrNull()
return process;
}
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
InitSettings( new PCB_CALCULATOR_SETTINGS );
aProgram->GetSettingsManager().RegisterSettings( KifaceSettings() );

View File

@ -82,7 +82,7 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
UNITS_PROVIDER( pcbIUScale, EDA_UNITS::MILLIMETRES )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void Reset() override;
@ -393,7 +393,7 @@ FP_LIB_TABLE GFootprintTable;
FOOTPRINT_LIST_IMPL GFootprintList;
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
// This is process-level-initialization, not project-level-initialization of the DSO.
// Do nothing in here pertinent to a project!
@ -416,7 +416,7 @@ bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
if( !loadGlobalLibTable() )
return false;
m_jobHandler = std::make_unique<PCBNEW_JOBS_HANDLER>();
m_jobHandler = std::make_unique<PCBNEW_JOBS_HANDLER>( aKiway );
if( m_start_flags & KFCTL_CLI )
{

View File

@ -56,6 +56,9 @@
#include <pcb_marker.h>
#include <project/project_file.h>
#include <exporters/export_svg.h>
#include <kiface_ids.h>
#include <netlist_reader/pcb_netlist.h>
#include <netlist_reader/netlist_reader.h>
#include <pcbnew_settings.h>
#include <pcbplot.h>
#include <pgm_base.h>
@ -70,7 +73,8 @@
#include "pcbnew_scripting_helpers.h"
PCBNEW_JOBS_HANDLER::PCBNEW_JOBS_HANDLER()
PCBNEW_JOBS_HANDLER::PCBNEW_JOBS_HANDLER( KIWAY* aKiway ) :
JOB_DISPATCHER( aKiway )
{
Register( "3d", std::bind( &PCBNEW_JOBS_HANDLER::JobExportStep, this, std::placeholders::_1 ) );
Register( "svg", std::bind( &PCBNEW_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ) );
@ -1002,6 +1006,46 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob )
m_reporter->Report( _( "Running DRC...\n" ), RPT_SEVERITY_INFO );
if( drcJob->m_parity )
{
typedef bool (*NETLIST_FN_PTR)( const wxString&, std::string& );
KIFACE* eeschema = m_kiway->KiFACE( KIWAY::FACE_SCH );
wxFileName schematicPath( drcJob->m_filename );
NETLIST_FN_PTR netlister = (NETLIST_FN_PTR) eeschema->IfaceOrAddress( KIFACE_NETLIST_SCHEMATIC );
std::string netlist_str;
NETLIST netlist;
schematicPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
if( !schematicPath.Exists() )
schematicPath.SetExt( FILEEXT::LegacySchematicFileExtension );
if( !schematicPath.Exists() )
{
m_reporter->Report( _( "Failed to find schematic for parity tests.\n" ),
RPT_SEVERITY_INFO );
}
else
{
(*netlister)( schematicPath.GetFullPath(), netlist_str );
try
{
auto lineReader = new STRING_LINE_READER( netlist_str, _( "Eeschema netlist" ) );
KICAD_NETLIST_READER netlistReader( lineReader, &netlist );
netlistReader.LoadNetlist();
}
catch( const IO_ERROR& e )
{
m_reporter->Report( _( "Failed to fetch schematic netlist for parity tests.\n" ),
RPT_SEVERITY_INFO );
}
drcEngine->SetSchematicNetlist( &netlist );
}
}
drcEngine->SetProgressReporter( nullptr );
drcEngine->SetViolationHandler(
[&]( const std::shared_ptr<DRC_ITEM>& aItem, VECTOR2I aPos, int aLayer )
@ -1017,7 +1061,8 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob )
commit.Push( _( "DRC" ), SKIP_UNDO | SKIP_SET_DIRTY );
// now "resolve" the drc exclusions again because its the only way to set exclusion status on a marker
// now "resolve" the drc exclusions again because its the only way to set exclusion status on
// a marker
for( PCB_MARKER* marker : brd->ResolveDRCExclusions( false ) )
brd->Add( marker );
@ -1034,15 +1079,19 @@ int PCBNEW_JOBS_HANDLER::JobExportDrc( JOB* aJob )
ratsnestProvider->SetSeverities( drcJob->m_severity );
fpWarningsProvider->SetSeverities( drcJob->m_severity );
m_reporter->Report(
wxString::Format( _( "Found %d violations\n" ), markersProvider->GetCount() ),
m_reporter->Report( wxString::Format( _( "Found %d violations\n" ),
markersProvider->GetCount() ),
RPT_SEVERITY_INFO );
m_reporter->Report(
wxString::Format( _( "Found %d unconnected items\n" ), ratsnestProvider->GetCount() ),
m_reporter->Report( wxString::Format( _( "Found %d unconnected items\n" ),
ratsnestProvider->GetCount() ),
RPT_SEVERITY_INFO );
if( drcJob->m_parity )
{
m_reporter->Report( wxString::Format( _( "Found %d schematic parity issues\n" ),
fpWarningsProvider->GetCount() ),
RPT_SEVERITY_INFO );
}
DRC_REPORT reportWriter( brd, units, markersProvider, ratsnestProvider, fpWarningsProvider );

View File

@ -24,6 +24,7 @@
#include <jobs/job_dispatcher.h>
#include <pcb_plot_params.h>
class KIWAY;
class BOARD;
class DS_PROXY_VIEW_ITEM;
class FOOTPRINT;
@ -33,7 +34,7 @@ class JOB_FP_EXPORT_SVG;
class PCBNEW_JOBS_HANDLER : public JOB_DISPATCHER
{
public:
PCBNEW_JOBS_HANDLER();
PCBNEW_JOBS_HANDLER( KIWAY* aKiway );
int JobExportStep( JOB* aJob );
int JobExportSvg( JOB* aJob );
int JobExportDxf( JOB* aJob );

View File

@ -38,7 +38,7 @@ MOCK_BASE_CLASS( MOCK_KIFACE_BASE, KIFACE_BASE )
MOCK_KIFACE_BASE() : KIFACE_BASE( "common_test", KIWAY::KIWAY_FACE_COUNT ) {};
virtual ~MOCK_KIFACE_BASE() {};
MOCK_METHOD( OnKifaceStart, 2, bool( PGM_BASE*, int ) );
MOCK_METHOD( OnKifaceStart, 3, bool( PGM_BASE*, int, KIWAY* ) );
MOCK_METHOD( OnKifaceEnd, 0, void() );
MOCK_METHOD( CreateKiWindow, 4, wxWindow*( wxWindow*, int, KIWAY*, int ) );
MOCK_METHOD( IfaceOrAddress, 1, void*( int ) );

View File

@ -57,7 +57,7 @@ static struct IFACE : public KIFACE_BASE
KIFACE_BASE( aName, aType )
{}
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override
{
return true;
}

View File

@ -35,7 +35,7 @@ namespace KIPYTHON {
static struct IFACE : public KIFACE_BASE
{
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override;
bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
void OnKifaceEnd() override;
@ -109,7 +109,7 @@ PGM_BASE* PgmOrNull()
}
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits )
bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
{
InitSettings( new KIPYTHON_SETTINGS );
Pgm().GetSettingsManager().RegisterSettings( KifaceSettings() );