KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2023 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 <project.h>
39
40#include <../../tests/common/console_log.h>
41
43{
44 BOARD_CONNECTED_ITEM* parent = nullptr;
45
46 for( BOARD_CONNECTED_ITEM* item : m_board->AllConnectedItems() )
47 {
48 if( item->m_Uuid == evt.uuid )
49 {
50 parent = item;
51 break;
52 };
53 }
54
55 return parent;
56}
57
58static const wxString readLine( FILE* f )
59{
60 char str[16384];
61 fgets( str, sizeof( str ) - 1, f );
62 return wxString( str );
63}
64
65
67 m_mode( PNS::ROUTER_MODE::PNS_MODE_ROUTE_SINGLE )
68{
69 m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) );
70}
71
72
73std::shared_ptr<SHAPE> PNS_LOG_FILE::parseShape( SHAPE_TYPE expectedType, wxStringTokenizer& aTokens )
74{
75 SHAPE_TYPE type = static_cast<SHAPE_TYPE> ( wxAtoi( aTokens.GetNextToken() ) );
76
77 if( type == SHAPE_TYPE::SH_SEGMENT )
78 {
79 std::shared_ptr<SHAPE_SEGMENT> sh( new SHAPE_SEGMENT );
80 VECTOR2I a, b;
81 a.x = wxAtoi( aTokens.GetNextToken() );
82 a.y = wxAtoi( aTokens.GetNextToken() );
83 b.x = wxAtoi( aTokens.GetNextToken() );
84 b.y = wxAtoi( aTokens.GetNextToken() );
85 int width = wxAtoi( aTokens.GetNextToken() );
86 sh->SetSeg( SEG( a, b ));
87 sh->SetWidth( width );
88 return sh;
89 }
90 else if( type == SHAPE_TYPE::SH_CIRCLE )
91 {
92 std::shared_ptr<SHAPE_CIRCLE> sh( new SHAPE_CIRCLE );
93 VECTOR2I a;
94 a.x = wxAtoi( aTokens.GetNextToken() );
95 a.y = wxAtoi( aTokens.GetNextToken() );
96 int radius = wxAtoi( aTokens.GetNextToken() );
97 sh->SetCenter( a );
98 sh->SetRadius( radius );
99 return sh;
100 }
101
102 return nullptr;
103}
104
105bool PNS_LOG_FILE::parseCommonPnsProps( PNS::ITEM* aItem, const wxString& cmd,
106 wxStringTokenizer& aTokens )
107{
108 if( cmd == wxS( "net" ) )
109 {
110 aItem->SetNet( m_board->FindNet( wxAtoi( aTokens.GetNextToken() ) ) );
111 return true;
112 }
113 else if( cmd == wxS( "layers" ) )
114 {
115 int start = wxAtoi( aTokens.GetNextToken() );
116 int end = wxAtoi( aTokens.GetNextToken() );
117 aItem->SetLayers( LAYER_RANGE( start, end ) );
118 return true;
119 }
120 return false;
121}
122
123std::unique_ptr<PNS::SEGMENT> PNS_LOG_FILE::parsePnsSegmentFromString( wxStringTokenizer& aTokens )
124{
125 std::unique_ptr<PNS::SEGMENT> seg( new PNS::SEGMENT() );
126
127 while( aTokens.CountTokens() )
128 {
129 wxString cmd = aTokens.GetNextToken();
130
131 if( !parseCommonPnsProps( seg.get(), cmd, aTokens ) )
132 {
133 if( cmd == wxS( "shape" ) )
134 {
135 std::shared_ptr<SHAPE> sh = parseShape( SH_SEGMENT, aTokens );
136
137 if( !sh )
138 return nullptr;
139
140 seg->SetShape( *static_cast<SHAPE_SEGMENT*>( sh.get() ) );
141
142 }
143 }
144 }
145
146 return seg;
147}
148
149std::unique_ptr<PNS::VIA> PNS_LOG_FILE::parsePnsViaFromString( wxStringTokenizer& aTokens )
150{
151 std::unique_ptr<PNS::VIA> via( new PNS::VIA() );
152
153 while( aTokens.CountTokens() )
154 {
155 wxString cmd = aTokens.GetNextToken();
156
157 if( !parseCommonPnsProps( via.get(), cmd, aTokens ) )
158 {
159 if( cmd == wxS( "shape" ) )
160 {
161 std::shared_ptr<SHAPE> sh = parseShape( SH_CIRCLE, aTokens );
162
163 if( !sh )
164 return nullptr;
165
166 SHAPE_CIRCLE* sc = static_cast<SHAPE_CIRCLE*>( sh.get() );
167
168 via->SetPos( sc->GetCenter() );
169 via->SetDiameter( 2 * sc->GetRadius() );
170 }
171 else if( cmd == wxS( "drill" ) )
172 {
173 via->SetDrill( wxAtoi( aTokens.GetNextToken() ) );
174 }
175 }
176 }
177
178 return via;
179}
180
181
182std::unique_ptr<PNS::ITEM> PNS_LOG_FILE::parseItemFromString( wxStringTokenizer& aTokens )
183{
184 wxString type = aTokens.GetNextToken();
185
186 if( type == wxS( "segment" ) )
187 return parsePnsSegmentFromString( aTokens );
188 else if( type == wxS( "via" ) )
189 return parsePnsViaFromString( aTokens );
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 const PNS::VIA* va = static_cast<const PNS::VIA*>(a);
208 const PNS::VIA* 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 const PNS::SEGMENT* sa = static_cast<const PNS::SEGMENT*>(a);
223 const PNS::SEGMENT* 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
236const std::set<PNS::ITEM*> deduplicate( const std::vector<PNS::ITEM*>& items )
237{
238 std::set<PNS::ITEM*> rv;
239
240 for( PNS::ITEM* item : items )
241 {
242 bool isDuplicate = false;
243
244 for( PNS::ITEM* ritem : rv )
245 {
246 if( comparePnsItems( ritem, item) )
247 {
248 isDuplicate = true;
249 break;
250 }
251
252 if( !isDuplicate )
253 rv.insert( item );
254 }
255 }
256
257 return rv;
258}
259
260
262{
263 COMMIT_STATE check( aOther );
264
265 //printf("pre-compare: %d/%d\n", check.m_addedItems.size(), check.m_removedIds.size() );
266 //printf("pre-compare (log): %d/%d\n", m_addedItems.size(), m_removedIds.size() );
267
268 for( const KIID& uuid : m_removedIds )
269 {
270 if( check.m_removedIds.find( uuid ) != check.m_removedIds.end() )
271 check.m_removedIds.erase( uuid );
272 else
273 return false; // removed twice? wtf
274 }
275
276 std::set<PNS::ITEM*> addedItems = deduplicate( m_addedItems );
277 std::set<PNS::ITEM*> chkAddedItems = deduplicate( check.m_addedItems );
278
279 for( PNS::ITEM* item : addedItems )
280 {
281 for( PNS::ITEM* chk : chkAddedItems )
282 {
283 if( comparePnsItems( item, chk ) )
284 {
285 chkAddedItems.erase( chk );
286 break;
287 }
288 }
289 }
290
291 //printf("post-compare: %d/%d\n", chkAddedItems.size(), check.m_removedIds.size() );
292
293 if( chkAddedItems.empty() && check.m_removedIds.empty() )
294 return true;
295 else
296 return false; // Set breakpoint here to trap failing tests
297}
298
299
300bool PNS_LOG_FILE::SaveLog( const wxFileName& logFileName, REPORTER* aRpt )
301{
302 FILE* log_f = wxFopen( logFileName.GetFullPath(), "wb" );
306 m_events );
307 fprintf( log_f, "%s\n", logString.c_str().AsChar() );
308 fclose( log_f );
309
310 return true;
311}
312
313
314bool PNS_LOG_FILE::Load( const wxFileName& logFileName, REPORTER* aRpt )
315{
316 wxFileName fname_log( logFileName );
317 fname_log.SetExt( wxT( "log" ) );
318
319 wxFileName fname_dump( logFileName );
320 fname_dump.SetExt( wxT( "dump" ) );
321
322 wxFileName fname_project( logFileName );
323 fname_project.SetExt( wxT( "kicad_pro" ) );
324 fname_project.MakeAbsolute();
325
326 wxFileName fname_settings( logFileName );
327 fname_settings.SetExt( wxT( "settings" ) );
328
329 aRpt->Report( wxString::Format( wxT( "Loading router settings from '%s'" ),
330 fname_settings.GetFullPath() ) );
331
332 bool ok = m_routerSettings->LoadFromRawFile( fname_settings.GetFullPath() );
333
334 if( !ok )
335 {
336 aRpt->Report( wxT( "Failed to load routing settings. Using defaults." ),
338 }
339
340 aRpt->Report( wxString::Format( wxT( "Loading project settings from '%s'" ),
341 fname_settings.GetFullPath() ) );
342
343 m_settingsMgr.reset( new SETTINGS_MANAGER ( true ) );
344 m_settingsMgr->LoadProject( fname_project.GetFullPath() );
345 PROJECT* project = m_settingsMgr->GetProject( fname_project.GetFullPath() );
346 project->SetReadOnly();
347
348 try
349 {
351 aRpt->Report( wxString::Format( wxT("Loading board snapshot from '%s'"),
352 fname_dump.GetFullPath() ) );
353
354 m_board.reset( io.LoadBoard( fname_dump.GetFullPath(), nullptr, nullptr ) );
355 m_board->SetProject( project );
356
357 std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE );
358
359 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
360
361 bds.m_DRCEngine = drcEngine;
362 bds.m_UseConnectedTrackWidth = project->GetLocalSettings().m_AutoTrackWidth;
363
364 m_board->SynchronizeNetsAndNetClasses( true );
365
366 drcEngine->SetBoard( m_board.get() );
367 drcEngine->SetDesignSettings( &bds );
368 drcEngine->SetLogReporter( aRpt );
369 drcEngine->InitEngine( wxFileName() );
370 }
371 catch( const PARSE_ERROR& parse_error )
372 {
373 aRpt->Report( wxString::Format( "parse error : %s (%s)\n",
374 parse_error.Problem(),
375 parse_error.What() ),
377
378 return false;
379 }
380
381 FILE* f = fopen( fname_log.GetFullPath().c_str(), "rb" );
382
383 aRpt->Report( wxString::Format( "Loading log from '%s'", fname_log.GetFullPath() ) );
384
385 if( !f )
386 {
387 aRpt->Report( wxT( "Failed to load log" ), RPT_SEVERITY_ERROR );
388 return false;
389 }
390
391 while( !feof( f ) )
392 {
393 wxString line = readLine( f );
394 wxStringTokenizer tokens( line );
395
396 if( !tokens.CountTokens() )
397 continue;
398
399 wxString cmd = tokens.GetNextToken();
400
401 if( cmd == wxT( "mode" ) )
402 {
403 m_mode = static_cast<PNS::ROUTER_MODE>( wxAtoi( tokens.GetNextToken() ) );
404 }
405 else if( cmd == wxT( "event" ) )
406 {
407 m_events.push_back( std::move( PNS::LOGGER::ParseEvent( line ) ) );
408 }
409 else if ( cmd == wxT( "added" ) )
410 {
411 m_parsed_items.push_back( std::move( parseItemFromString( tokens ) ) );
412 m_commitState.m_addedItems.push_back( m_parsed_items.back().get() );
413 }
414 else if ( cmd == wxT( "removed" ) )
415 {
416 m_commitState.m_removedIds.insert( KIID( tokens.GetNextToken() ) );
417 }
418 }
419
420 fclose( f );
421
422 return true;
423}
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:49
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const STRING_UTF8_MAP *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
Base class for PNS router board items.
Definition: pns_item.h:97
void SetLayers(const LAYER_RANGE &aLayers)
Definition: pns_item.h:196
virtual NET_HANDLE Net() const
Definition: pns_item.h:193
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:166
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:192
@ SEGMENT_T
Definition: pns_item.h:105
const LAYER_RANGE & Layers() const
Definition: pns_item.h:195
static wxString FormatLogFileAsString(int aMode, const std::vector< ITEM * > &aAddedItems, const std::set< KIID > &aRemovedItems, const std::vector< ITEM * > &aHeads, const std::vector< EVENT_ENTRY > &aEvents)
Definition: pns_logger.cpp:67
static EVENT_ENTRY ParseEvent(const wxString &aLine)
Definition: pns_logger.cpp:103
Contain all persistent settings of the router, such as the mode, optimization effort,...
const SEG & Seg() const
Definition: pns_segment.h:84
int Width() const override
Definition: pns_segment.h:79
const VECTOR2I & Pos() const
Definition: pns_via.h:128
int Diameter() const
Definition: pns_via.h:142
int Drill() const
Definition: pns_via.h:150
BOARD_CONNECTED_ITEM * ItemById(const PNS::LOGGER::EVENT_ENTRY &evt)
bool Load(const wxFileName &logFileName, REPORTER *aRpt)
bool SaveLog(const wxFileName &logFileName, REPORTER *aRpt)
PNS::ROUTER_MODE m_mode
Definition: pns_log_file.h:118
std::unique_ptr< PNS::SEGMENT > parsePnsSegmentFromString(wxStringTokenizer &aTokens)
std::shared_ptr< BOARD > m_board
Definition: pns_log_file.h:115
std::shared_ptr< SETTINGS_MANAGER > m_settingsMgr
Definition: pns_log_file.h:112
std::shared_ptr< SHAPE > parseShape(SHAPE_TYPE expectedType, wxStringTokenizer &aTokens)
std::vector< std::unique_ptr< PNS::ITEM > > m_parsed_items
Definition: pns_log_file.h:117
std::unique_ptr< PNS::ITEM > parseItemFromString(wxStringTokenizer &aTokens)
std::unique_ptr< PNS::VIA > parsePnsViaFromString(wxStringTokenizer &aTokens)
bool parseCommonPnsProps(PNS::ITEM *aItem, const wxString &cmd, wxStringTokenizer &aTokens)
COMMIT_STATE m_commitState
Definition: pns_log_file.h:116
std::vector< PNS::LOGGER::EVENT_ENTRY > m_events
Definition: pns_log_file.h:114
std::unique_ptr< PNS::ROUTING_SETTINGS > m_routerSettings
Definition: pns_log_file.h:113
Container for project specific data.
Definition: project.h:62
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
int GetRadius() const
Definition: shape_circle.h:108
const VECTOR2I GetCenter() const
Definition: shape_circle.h:113
Push and Shove diff pair dimensions (gap) settings dialog.
ROUTER_MODE
Definition: pns_router.h:62
bool comparePnsItems(const PNS::ITEM *a, const PNS::ITEM *b)
static const wxString readLine(FILE *f)
const std::set< PNS::ITEM * > deduplicate(const std::vector< PNS::ITEM * > &items)
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
SHAPE_TYPE
Lists all supported shapes.
Definition: shape.h:46
@ SH_CIRCLE
circle
Definition: shape.h:50
@ SH_SEGMENT
line segment
Definition: shape.h:48
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:120
Definition: pns_logger.h:56
KIID uuid
Definition: pns_logger.h:59
std::set< KIID > m_removedIds
Definition: pns_log_file.h:65
bool Compare(const COMMIT_STATE &aOther)
std::vector< PNS::ITEM * > m_addedItems
Definition: pns_log_file.h:66
std::vector< PNS::ITEM * > m_heads
Definition: pns_log_file.h:67