416 lines
11 KiB
C++
416 lines
11 KiB
C++
|
/*
|
||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||
|
*
|
||
|
* Copyright (C) 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 "pns_log.h"
|
||
|
|
||
|
#include <qa/common/console_log.h>
|
||
|
|
||
|
#include <pcbnew/drc/drc_test_provider.h>
|
||
|
|
||
|
using namespace PNS;
|
||
|
|
||
|
static const wxString readLine( FILE* f )
|
||
|
{
|
||
|
char str[16384];
|
||
|
fgets( str, sizeof( str ) - 1, f );
|
||
|
return wxString( str );
|
||
|
}
|
||
|
|
||
|
PNS_LOG_FILE::PNS_LOG_FILE()
|
||
|
{
|
||
|
m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
bool PNS_LOG_FILE::Load( const std::string& logName, const std::string boardName )
|
||
|
{
|
||
|
FILE* f = fopen( logName.c_str(), "rb" );
|
||
|
|
||
|
if (!f)
|
||
|
return false;
|
||
|
|
||
|
while( !feof( f ) )
|
||
|
{
|
||
|
wxStringTokenizer tokens( readLine( f ) );
|
||
|
if( !tokens.CountTokens() )
|
||
|
continue;
|
||
|
|
||
|
wxString cmd = tokens.GetNextToken();
|
||
|
|
||
|
if (cmd == "event")
|
||
|
{
|
||
|
EVENT_ENTRY evt;
|
||
|
evt.p.x = wxAtoi( tokens.GetNextToken() );
|
||
|
evt.p.y = wxAtoi( tokens.GetNextToken() );
|
||
|
evt.type = (PNS::LOGGER::EVENT_TYPE) wxAtoi( tokens.GetNextToken() );
|
||
|
evt.uuid = KIID( tokens.GetNextToken() );
|
||
|
m_events.push_back(evt);
|
||
|
}
|
||
|
else if (cmd == "config")
|
||
|
{
|
||
|
m_routerSettings->SetMode( (PNS::PNS_MODE) wxAtoi( tokens.GetNextToken() ) );
|
||
|
m_routerSettings->SetRemoveLoops( wxAtoi( tokens.GetNextToken() ) );
|
||
|
m_routerSettings->SetFixAllSegments( wxAtoi( tokens.GetNextToken() ) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose( f );
|
||
|
|
||
|
try {
|
||
|
PCB_IO io;
|
||
|
m_board.reset( io.Load( boardName.c_str(), nullptr, nullptr ) );
|
||
|
|
||
|
std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE );
|
||
|
|
||
|
CONSOLE_LOG consoleLog;
|
||
|
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||
|
|
||
|
bds.m_DRCEngine = drcEngine;
|
||
|
|
||
|
drcEngine->SetBoard( m_board.get() );
|
||
|
drcEngine->SetDesignSettings( &bds );
|
||
|
drcEngine->SetLogReporter( new CONSOLE_MSG_REPORTER ( &consoleLog ) );
|
||
|
drcEngine->InitEngine(wxFileName());
|
||
|
|
||
|
} catch ( const PARSE_ERROR& parse_error ) {
|
||
|
printf("parse error : %s (%s)\n",
|
||
|
(const char *) parse_error.Problem().c_str(),
|
||
|
(const char *) parse_error.What().c_str() );
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
PNS_TEST_ENVIRONMENT::PNS_TEST_ENVIRONMENT()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
PNS_TEST_ENVIRONMENT::~PNS_TEST_ENVIRONMENT()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_ENVIRONMENT::SetMode( PNS::ROUTER_MODE mode )
|
||
|
{
|
||
|
m_mode = mode;
|
||
|
}
|
||
|
|
||
|
|
||
|
void PNS_TEST_ENVIRONMENT::createRouter()
|
||
|
{
|
||
|
m_iface.reset ( new PNS_KICAD_IFACE_BASE);
|
||
|
m_router.reset( new ROUTER );
|
||
|
m_iface->SetBoard( m_board.get() );
|
||
|
m_router->SetInterface( m_iface.get() );
|
||
|
m_router->ClearWorld();
|
||
|
m_router->SetMode( m_mode );
|
||
|
m_router->SyncWorld();
|
||
|
m_router->LoadSettings( new PNS::ROUTING_SETTINGS (nullptr, ""));
|
||
|
m_router->Settings().SetMode( PNS::RM_Shove );
|
||
|
m_router->Settings().SetOptimizeDraggedTrack( true );
|
||
|
|
||
|
m_debugDecorator.Clear();
|
||
|
m_iface->SetDebugDecorator( &m_debugDecorator );
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_ENVIRONMENT::ReplayLog ( PNS_LOG_FILE* aLog, int aStartEventIndex, int aFrom, int aTo )
|
||
|
{
|
||
|
|
||
|
m_board = aLog->GetBoard();
|
||
|
|
||
|
createRouter();
|
||
|
|
||
|
m_router->LoadSettings( aLog->GetRoutingSettings() );
|
||
|
|
||
|
printf("Router mode: %d\n", m_router->Settings().Mode() );
|
||
|
|
||
|
for( auto evt : aLog->Events() )
|
||
|
{
|
||
|
auto item = aLog->ItemById(evt);
|
||
|
ITEM* ritem = item ? m_router->GetWorld()->FindItemByParent( item ) : nullptr;
|
||
|
|
||
|
switch(evt.type)
|
||
|
{
|
||
|
case LOGGER::EVT_START_ROUTE:
|
||
|
{
|
||
|
m_debugDecorator.NewStage("route-start", 0);
|
||
|
printf(" rtr start-route (%d, %d) %p \n", evt.p.x, evt.p.y, ritem);
|
||
|
m_router->StartRouting( evt.p, ritem, ritem ? ritem->Layers().Start() : F_Cu );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LOGGER::EVT_START_DRAG:
|
||
|
{
|
||
|
m_debugDecorator.NewStage("drag-start", 0);
|
||
|
bool rv = m_router->StartDragging( evt.p, ritem, 0 );
|
||
|
printf(" rtr start-drag (%d, %d) %p ret %d\n", evt.p.x, evt.p.y, ritem, rv?1:0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LOGGER::EVT_FIX:
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case LOGGER::EVT_MOVE:
|
||
|
{
|
||
|
m_debugDecorator.NewStage("move", 0);
|
||
|
printf(" move -> (%d, %d)\n", evt.p.x, evt.p.y );
|
||
|
m_router->Move( evt.p, ritem );
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
PNS::NODE* node = nullptr;
|
||
|
|
||
|
|
||
|
if( m_router->GetState() == PNS::ROUTER::ROUTE_TRACK )
|
||
|
{
|
||
|
m_debugDecorator.BeginGroup( "head");
|
||
|
|
||
|
auto traces = m_router->Placer()->Traces();
|
||
|
for ( const auto& t : traces.CItems() )
|
||
|
{
|
||
|
const LINE *l = static_cast<LINE*>(t.item);
|
||
|
const auto& sh = l->CLine();
|
||
|
|
||
|
m_debugDecorator.AddLine( sh, 4, 10000 );
|
||
|
}
|
||
|
|
||
|
m_debugDecorator.EndGroup();
|
||
|
|
||
|
node = m_router->Placer()->CurrentNode(true);
|
||
|
}
|
||
|
else if( m_router->GetState() == PNS::ROUTER::DRAG_SEGMENT )
|
||
|
{
|
||
|
node = m_router->GetDragger()->CurrentNode();
|
||
|
}
|
||
|
|
||
|
if(!node)
|
||
|
return;
|
||
|
|
||
|
NODE::ITEM_VECTOR removed, added;
|
||
|
|
||
|
node->GetUpdatedItems( removed, added );
|
||
|
|
||
|
if( ! added.empty() )
|
||
|
{
|
||
|
bool first = true;
|
||
|
m_debugDecorator.BeginGroup( "node-added-items");
|
||
|
|
||
|
for( auto t : added )
|
||
|
{
|
||
|
if( t->OfKind( PNS::ITEM::SEGMENT_T ) )
|
||
|
{
|
||
|
auto s = static_cast<PNS::SEGMENT*>(t);
|
||
|
m_debugDecorator.AddSegment( s->Seg(), 2 );
|
||
|
first = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_debugDecorator.EndGroup();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
PNS_TEST_DEBUG_DECORATOR::STAGE* PNS_TEST_DEBUG_DECORATOR::currentStage()
|
||
|
{
|
||
|
if (m_stages.empty() )
|
||
|
m_stages.push_back( new STAGE() );
|
||
|
|
||
|
return m_stages.back();
|
||
|
}
|
||
|
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::BeginGroup( std::string name )
|
||
|
{
|
||
|
STAGE* st = currentStage();
|
||
|
DEBUG_ENT *ent = new DEBUG_ENT();
|
||
|
|
||
|
ent->m_name = name;
|
||
|
ent->m_iter = m_iter;
|
||
|
|
||
|
if( m_activeEntry )
|
||
|
{
|
||
|
m_activeEntry->AddChild( ent );
|
||
|
}
|
||
|
|
||
|
printf("LOG BeginGroup %s %p\n", name.c_str(), ent );
|
||
|
|
||
|
m_activeEntry = ent;
|
||
|
m_grouping = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::EndGroup( )
|
||
|
{
|
||
|
printf("LOG EndGroup\n" );
|
||
|
|
||
|
if( !m_activeEntry )
|
||
|
return;
|
||
|
|
||
|
m_activeEntry = m_activeEntry->m_parent;
|
||
|
|
||
|
if( !m_activeEntry )
|
||
|
m_grouping = false;
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::addEntry( DEBUG_ENT* ent )
|
||
|
{
|
||
|
auto st = currentStage();
|
||
|
m_activeEntry->AddChild( ent );
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::AddPoint( VECTOR2I aP, int aColor, int aSize, const std::string aName )
|
||
|
{
|
||
|
auto sh = new SHAPE_LINE_CHAIN;
|
||
|
|
||
|
sh->Append( aP.x - aSize, aP.y - aSize);
|
||
|
sh->Append( aP.x + aSize, aP.y + aSize);
|
||
|
sh->Append( aP.x, aP.y );
|
||
|
sh->Append( aP.x - aSize, aP.y + aSize );
|
||
|
sh->Append( aP.x + aSize, aP.y - aSize );
|
||
|
|
||
|
DEBUG_ENT* ent = new DEBUG_ENT();
|
||
|
|
||
|
ent->m_shapes.push_back( sh );
|
||
|
ent->m_color = aColor;
|
||
|
ent->m_width = 30000;
|
||
|
ent->m_iter = m_iter;
|
||
|
ent->m_name = aName;
|
||
|
|
||
|
addEntry( ent );
|
||
|
}
|
||
|
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::AddLine( const SHAPE_LINE_CHAIN& aLine, int aType, int aWidth,
|
||
|
const std::string aName )
|
||
|
{
|
||
|
auto sh = new SHAPE_LINE_CHAIN( aLine );
|
||
|
DEBUG_ENT* ent = new DEBUG_ENT();
|
||
|
|
||
|
ent->m_shapes.push_back( sh );
|
||
|
ent->m_color = aType;
|
||
|
ent->m_width = aWidth;
|
||
|
ent->m_name = aName;
|
||
|
ent->m_iter = m_iter;
|
||
|
|
||
|
addEntry( ent );
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::AddSegment( SEG aS, int aColor, const std::string aName )
|
||
|
{
|
||
|
auto sh = new SHAPE_LINE_CHAIN ( { aS.A, aS.B } );
|
||
|
DEBUG_ENT* ent = new DEBUG_ENT();
|
||
|
|
||
|
ent->m_shapes.push_back( sh );
|
||
|
ent->m_color = aColor;
|
||
|
ent->m_width = 10000;
|
||
|
ent->m_name = aName;
|
||
|
ent->m_iter = m_iter;
|
||
|
addEntry( ent );
|
||
|
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::AddBox( BOX2I aB, int aColor, const std::string aName )
|
||
|
{
|
||
|
auto sh = new SHAPE_RECT ( aB.GetPosition(), aB.GetWidth(), aB.GetHeight() );
|
||
|
DEBUG_ENT* ent = new DEBUG_ENT();
|
||
|
|
||
|
ent->m_shapes.push_back( sh );
|
||
|
ent->m_color = aColor;
|
||
|
ent->m_width = 10000;
|
||
|
ent->m_name = aName;
|
||
|
ent->m_iter = m_iter;
|
||
|
addEntry( ent );
|
||
|
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::AddDirections( VECTOR2D aP, int aMask, int aColor, const std::string aName )
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::Message( const wxString msg )
|
||
|
{
|
||
|
DEBUG_ENT* ent = new DEBUG_ENT();
|
||
|
ent->m_msg = msg.c_str();
|
||
|
addEntry( ent );
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::Clear()
|
||
|
{
|
||
|
//dec_dbg("clear");
|
||
|
}
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::NewStage(const std::string& name, int iter)
|
||
|
{
|
||
|
m_stages.push_back( new STAGE );
|
||
|
m_activeEntry = m_stages.back()->m_entries;
|
||
|
}
|
||
|
|
||
|
|
||
|
void PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT::IterateTree( std::function<bool(PNS_TEST_DEBUG_DECORATOR::DEBUG_ENT*)> visitor, int depth )
|
||
|
{
|
||
|
printf("LOG D:%d iter: %p\n", depth, this );
|
||
|
if( ! visitor( this ) )
|
||
|
return;
|
||
|
|
||
|
|
||
|
for( auto child : m_children )
|
||
|
{
|
||
|
child->IterateTree( visitor, depth+1 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOX2I PNS_TEST_DEBUG_DECORATOR::GetStageExtents(int stage) const
|
||
|
{
|
||
|
STAGE* st = m_stages[stage];
|
||
|
BOX2I bb;
|
||
|
bool first = true;
|
||
|
|
||
|
auto visitor = [ & ] ( DEBUG_ENT *ent ) -> bool
|
||
|
{
|
||
|
for( auto sh : ent->m_shapes )
|
||
|
{
|
||
|
if ( first )
|
||
|
bb = sh->BBox();
|
||
|
else
|
||
|
bb.Merge( sh->BBox() );
|
||
|
|
||
|
first = false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
return bb;
|
||
|
}
|