KiCad PCB EDA Suite
pns_log_file.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020-2022 KiCad Developers.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24
25// WARNING - this Tom's crappy PNS hack tool code. Please don't complain about its quality
26// (unless you want to improve it).
27
28#include "pns_log_file.h"
29
30#include <router/pns_segment.h>
31
33
36
37#include <../../unittests/common/console_log.h>
38
40{
41 BOARD_CONNECTED_ITEM* parent = nullptr;
42
43 for( auto item : m_board->AllConnectedItems() )
44 {
45 if( item->m_Uuid == evt.uuid )
46 {
47 parent = item;
48 break;
49 };
50 }
51
52 return parent;
53}
54
55static const wxString readLine( FILE* f )
56{
57 char str[16384];
58 fgets( str, sizeof( str ) - 1, f );
59 return wxString( str );
60}
61
62
65{
66 m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) );
67}
68
69static std::shared_ptr<SHAPE> parseShape( SHAPE_TYPE expectedType, wxStringTokenizer& aTokens )
70{
71 SHAPE_TYPE type = static_cast<SHAPE_TYPE> ( wxAtoi( aTokens.GetNextToken() ) );
72
73 if( type == SHAPE_TYPE::SH_SEGMENT )
74 {
75 std::shared_ptr<SHAPE_SEGMENT> sh( new SHAPE_SEGMENT );
76 VECTOR2I a,b;
77 a.x = wxAtoi( aTokens.GetNextToken() );
78 a.y = wxAtoi( aTokens.GetNextToken() );
79 b.x = wxAtoi( aTokens.GetNextToken() );
80 b.y = wxAtoi( aTokens.GetNextToken() );
81 int width = wxAtoi( aTokens.GetNextToken() );
82 sh->SetSeg( SEG( a, b ));
83 sh->SetWidth( width );
84 return sh;
85 }
86 else if ( type == SHAPE_TYPE::SH_CIRCLE )
87 {
88
89 std::shared_ptr<SHAPE_CIRCLE> sh( new SHAPE_CIRCLE );
90 VECTOR2I a;
91 a.x = wxAtoi( aTokens.GetNextToken() );
92 a.y = wxAtoi( aTokens.GetNextToken() );
93 int radius = wxAtoi( aTokens.GetNextToken() );
94 sh->SetCenter( a );
95 sh->SetRadius( radius );
96 return sh;
97 }
98
99 return nullptr;
100}
101
102bool parseCommonPnsProps( PNS::ITEM* aItem, const wxString& cmd, wxStringTokenizer& aTokens )
103{
104 if( cmd == "net" )
105 {
106 aItem->SetNet( wxAtoi( aTokens.GetNextToken() ) );
107 return true;
108 } else if ( cmd == "layers" )
109 {
110 int start = wxAtoi( aTokens.GetNextToken() );
111 int end = wxAtoi( aTokens.GetNextToken() );
112 aItem->SetLayers( LAYER_RANGE( start, end ));
113 return true;
114 }
115 return false;
116
117}
118
119static PNS::SEGMENT* parsePnsSegmentFromString( PNS::SEGMENT* aSeg, wxStringTokenizer& aTokens )
120{
121 PNS::SEGMENT* seg = new ( PNS::SEGMENT );
122
123 while( aTokens.CountTokens() )
124 {
125 wxString cmd = aTokens.GetNextToken();
126 if( !parseCommonPnsProps( seg, cmd, aTokens ) )
127 {
128 if ( cmd == "shape" )
129 {
130 auto sh = parseShape( SH_SEGMENT, aTokens );
131
132 if(!sh)
133 return nullptr;
134
135 seg->SetShape( *static_cast<SHAPE_SEGMENT*>(sh.get()) );
136
137 }
138 }
139 }
140
141 return seg;
142}
143
144static PNS::VIA* parsePnsViaFromString( PNS::VIA* aSeg, wxStringTokenizer& aTokens )
145{
146 PNS::VIA* via = new ( PNS::VIA );
147
148 while( aTokens.CountTokens() )
149 {
150 wxString cmd = aTokens.GetNextToken();
151 if( !parseCommonPnsProps( via, cmd, aTokens ) )
152 {
153 if ( cmd == "shape" )
154 {
155 auto sh = parseShape( SH_CIRCLE, aTokens );
156
157 if(!sh)
158 return nullptr;
159
160 auto *sc = static_cast<SHAPE_CIRCLE*>( sh.get() );
161
162 via->SetPos( sc->GetCenter() );
163 via->SetDiameter( 2 * sc->GetRadius() );
164 }
165 else if ( cmd == "drill" )
166 {
167 via->SetDrill( wxAtoi( aTokens.GetNextToken() ) );
168 }
169 }
170 }
171
172 return via;
173}
174
175
176static PNS::ITEM* parseItemFromString( wxStringTokenizer& aTokens )
177{
178 wxString type = aTokens.GetNextToken();
179
180 if( type == "segment" )
181 {
182 auto seg = new PNS::SEGMENT();
183 return parsePnsSegmentFromString( seg, aTokens );
184 }
185 else if( type == "via" )
186 {
187 auto seg = new PNS::VIA();
188 return parsePnsViaFromString( seg, aTokens );
189 }
190
191 return nullptr;
192}
193
194bool comparePnsItems( const PNS::ITEM*a , const PNS::ITEM* b )
195{
196 if( a->Kind() != b->Kind() )
197 return false;
198
199 if( a->Net() != b->Net() )
200 return false;
201
202 if( a->Layers() != b->Layers() )
203 return false;
204
205 if( a->Kind() == PNS::ITEM::VIA_T )
206 {
207 auto va = static_cast<const PNS::VIA*>(a);
208 auto vb = static_cast<const PNS::VIA*>(b);
209
210 if( va->Diameter() != vb->Diameter() )
211 return false;
212
213 if( va->Drill() != vb->Drill() )
214 return false;
215
216 if( va->Pos() != vb->Pos() )
217 return false;
218
219 }
220 else if ( a->Kind() == PNS::ITEM::SEGMENT_T )
221 {
222 auto sa = static_cast<const PNS::SEGMENT*>(a);
223 auto sb = static_cast<const PNS::SEGMENT*>(b);
224
225 if( sa->Seg() != sb->Seg() )
226 return false;
227
228 if( sa->Width() != sb->Width() )
229 return false;
230 }
231
232 return true;
233}
234
235
237{
238 COMMIT_STATE check( aOther );
239
240 //printf("pre-compare: %d/%d\n", check.m_addedItems.size(), check.m_removedIds.size() );
241 //printf("pre-compare (log): %d/%d\n", m_addedItems.size(), m_removedIds.size() );
242
243 for( auto uuid : m_removedIds )
244 {
245 if( check.m_removedIds.find( uuid ) != check.m_removedIds.end() )
246 {
247 check.m_removedIds.erase( uuid );
248 }
249 else
250 {
251 return false; // removed twice? wtf
252 }
253 }
254
255 for( auto item : m_addedItems )
256 {
257 for( auto chk : check.m_addedItems )
258 {
259 if( comparePnsItems( item, chk ) )
260 {
261 check.m_addedItems.erase( chk );
262 break;
263 }
264 }
265 }
266
267 //printf("post-compare: %d/%d\n", check.m_addedItems.size(), check.m_removedIds.size() );
268
269 return check.m_addedItems.empty() && check.m_removedIds.empty();
270}
271
272
273bool PNS_LOG_FILE::Load( const wxFileName& logFileName, REPORTER* aRpt )
274{
275 wxFileName fname_log( logFileName );
276 fname_log.SetExt( wxT( "log" ) );
277
278 wxFileName fname_dump( logFileName );
279 fname_dump.SetExt( wxT( "dump" ) );
280
281 wxFileName fname_project( logFileName );
282 fname_project.SetExt( wxT( "kicad_pro" ) );
283 fname_project.MakeAbsolute();
284
285 wxFileName fname_settings( logFileName );
286 fname_settings.SetExt( wxT( "settings" ) );
287
288
289 FILE* f = fopen( fname_log.GetFullPath().c_str(), "rb" );
290
291 aRpt->Report( wxString::Format( "Loading log from '%s'", fname_log.GetFullPath() ) );
292
293 if( !f )
294 return false;
295
296 while( !feof( f ) )
297 {
298 wxStringTokenizer tokens( readLine( f ) );
299
300 if( !tokens.CountTokens() )
301 continue;
302
303 wxString cmd = tokens.GetNextToken();
304
305 if( cmd == wxT("mode") )
306 {
307 m_mode = static_cast<PNS::ROUTER_MODE>( wxAtoi( tokens.GetNextToken() ) );
308 }
309 else if( cmd == wxT("event") )
310 {
311 EVENT_ENTRY evt;
312 evt.p.x = wxAtoi( tokens.GetNextToken() );
313 evt.p.y = wxAtoi( tokens.GetNextToken() );
314 evt.type = (PNS::LOGGER::EVENT_TYPE) wxAtoi( tokens.GetNextToken() );
315 evt.uuid = KIID( tokens.GetNextToken() );
316 m_events.push_back( evt );
317 }
318 else if ( cmd == wxT("added") )
319 {
320 auto item = parseItemFromString( tokens );
321 m_commitState.m_addedItems.insert( item );
322 }
323 else if ( cmd == wxT("removed") )
324 {
325 m_commitState.m_removedIds.insert( KIID( tokens.GetNextToken() ) );
326 }
327 }
328
329 fclose( f );
330
331 aRpt->Report( wxString::Format( wxT("Loading router settings from '%s'"), fname_settings.GetFullPath() ) );
332
333 bool ok = m_routerSettings->LoadFromRawFile( fname_settings.GetFullPath() );
334
335 if( !ok )
336 {
337 aRpt->Report( wxString::Format( wxT("Failed to load routing settings. Usign defaults.")) , RPT_SEVERITY_WARNING );
338 }
339
340 aRpt->Report( wxString::Format( wxT("Loading project settings from '%s'"), fname_settings.GetFullPath() ) );
341
342 m_settingsMgr.reset( new SETTINGS_MANAGER ( true ) );
343 m_settingsMgr->LoadProject( fname_project.GetFullPath() );
344
345 try
346 {
347 PCB_PLUGIN io;
348 aRpt->Report( wxString::Format( wxT("Loading board snapshot from '%s'"), fname_dump.GetFullPath() ) );
349
350 m_board.reset( io.Load( fname_dump.GetFullPath(), nullptr, nullptr ) );
351 m_board->SetProject( m_settingsMgr->GetProject( fname_project.GetFullPath() ) );
352
353 std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE );
354
355 CONSOLE_LOG consoleLog;
356 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
357
358 bds.m_DRCEngine = drcEngine;
359
360 m_board->SynchronizeNetsAndNetClasses( true );
361
362 drcEngine->SetBoard( m_board.get() );
363 drcEngine->SetDesignSettings( &bds );
364 drcEngine->SetLogReporter( new CONSOLE_MSG_REPORTER( &consoleLog ) );
365 drcEngine->InitEngine( wxFileName() );
366 }
367 catch( const PARSE_ERROR& parse_error )
368 {
369 aRpt->Report( wxString::Format( "parse error : %s (%s)\n", parse_error.Problem(),
370 parse_error.What() ), RPT_SEVERITY_ERROR );
371
372 return false;
373 }
374
375 return true;
376}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
Design Rule Checker object that performs all the DRC tests.
Definition: drc_engine.h:83
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:46
Definition: kiid.h:48
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
A PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
Definition: pcb_plugin.h:261
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const STRING_UTF8_MAP *aProperties=nullptr, PROJECT *aProject=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Load information from some input file format that this PLUGIN implementation knows about into either ...
Base class for PNS router board items.
Definition: pns_item.h:56
void SetLayers(const LAYER_RANGE &aLayers)
Definition: pns_item.h:157
void SetNet(int aNet)
Definition: pns_item.h:153
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:132
@ SEGMENT_T
Definition: pns_item.h:66
const LAYER_RANGE & Layers() const
Definition: pns_item.h:156
int Net() const
Definition: pns_item.h:154
Contain all persistent settings of the router, such as the mode, optimization effort,...
void SetShape(const SHAPE_SEGMENT &aShape)
Definition: pns_segment.h:122
bool Load(const wxFileName &logFileName, REPORTER *aRpt)
PNS::ROUTER_MODE m_mode
Definition: pns_log_file.h:102
std::shared_ptr< BOARD > m_board
Definition: pns_log_file.h:100
std::shared_ptr< SETTINGS_MANAGER > m_settingsMgr
Definition: pns_log_file.h:97
BOARD_CONNECTED_ITEM * ItemById(const EVENT_ENTRY &evt)
COMMIT_STATE m_commitState
Definition: pns_log_file.h:101
std::vector< EVENT_ENTRY > m_events
Definition: pns_log_file.h:99
std::unique_ptr< PNS::ROUTING_SETTINGS > m_routerSettings
Definition: pns_log_file.h:98
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Definition: seg.h:42
Push and Shove diff pair dimensions (gap) settings dialog.
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_ROUTE_SINGLE
Definition: pns_router.h:63
static PNS::VIA * parsePnsViaFromString(PNS::VIA *aSeg, wxStringTokenizer &aTokens)
static std::shared_ptr< SHAPE > parseShape(SHAPE_TYPE expectedType, wxStringTokenizer &aTokens)
bool parseCommonPnsProps(PNS::ITEM *aItem, const wxString &cmd, wxStringTokenizer &aTokens)
static PNS::ITEM * parseItemFromString(wxStringTokenizer &aTokens)
bool comparePnsItems(const PNS::ITEM *a, const PNS::ITEM *b)
static const wxString readLine(FILE *f)
static PNS::SEGMENT * parsePnsSegmentFromString(PNS::SEGMENT *aSeg, wxStringTokenizer &aTokens)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
SHAPE_TYPE
Lists all supported shapes.
Definition: shape.h:43
@ SH_CIRCLE
circle
Definition: shape.h:47
@ SH_SEGMENT
line segment
Definition: shape.h:45
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:119
std::set< KIID > m_removedIds
Definition: pns_log_file.h:74
std::set< PNS::ITEM * > m_addedItems
Definition: pns_log_file.h:75
bool Compare(const COMMIT_STATE &aOther)
Definition: pns_log_file.h:57
KIID uuid
Definition: pns_log_file.h:61
VECTOR2I p
Definition: pns_log_file.h:58
PNS::LOGGER::EVENT_TYPE type
Definition: pns_log_file.h:59