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
42std::vector<BOARD_CONNECTED_ITEM*> PNS_LOG_FILE::ItemsById( const PNS::LOGGER::EVENT_ENTRY& evt )
43{
44 std::vector<BOARD_CONNECTED_ITEM*> parents;
45
46 parents.resize( evt.uuids.size() );
47
48 printf("u %zu p %zu\n", evt.uuids.size(), parents.size() );
49
50 for( BOARD_CONNECTED_ITEM* item : m_board->AllConnectedItems() )
51 {
52 for( int i = 0; i < evt.uuids.size(); i++ )
53 {
54 if( item->m_Uuid == evt.uuids[i] )
55 {
56 parents[i] = item;
57 break;
58 };
59 }
60 }
61
62 return parents;
63}
64
66{
67 auto parents = ItemsById( evt );
68 if ( parents.size() > 0 )
69 return parents[0];
70
71 return nullptr;
72}
73
74
75static const wxString readLine( FILE* f )
76{
77 char str[16384];
78 fgets( str, sizeof( str ) - 1, f );
79 return wxString( str );
80}
81
82
84 m_mode( PNS::ROUTER_MODE::PNS_MODE_ROUTE_SINGLE )
85{
86 m_routerSettings.reset( new PNS::ROUTING_SETTINGS( nullptr, "" ) );
87}
88
89
90std::shared_ptr<SHAPE> PNS_LOG_FILE::parseShape( SHAPE_TYPE expectedType, wxStringTokenizer& aTokens )
91{
92 SHAPE_TYPE type = static_cast<SHAPE_TYPE> ( wxAtoi( aTokens.GetNextToken() ) );
93
94 if( type == SHAPE_TYPE::SH_SEGMENT )
95 {
96 std::shared_ptr<SHAPE_SEGMENT> sh( new SHAPE_SEGMENT );
97 VECTOR2I a, b;
98 a.x = wxAtoi( aTokens.GetNextToken() );
99 a.y = wxAtoi( aTokens.GetNextToken() );
100 b.x = wxAtoi( aTokens.GetNextToken() );
101 b.y = wxAtoi( aTokens.GetNextToken() );
102 int width = wxAtoi( aTokens.GetNextToken() );
103 sh->SetSeg( SEG( a, b ));
104 sh->SetWidth( width );
105 return sh;
106 }
107 else if( type == SHAPE_TYPE::SH_CIRCLE )
108 {
109 std::shared_ptr<SHAPE_CIRCLE> sh( new SHAPE_CIRCLE );
110 VECTOR2I a;
111 a.x = wxAtoi( aTokens.GetNextToken() );
112 a.y = wxAtoi( aTokens.GetNextToken() );
113 int radius = wxAtoi( aTokens.GetNextToken() );
114 sh->SetCenter( a );
115 sh->SetRadius( radius );
116 return sh;
117 }
118
119 return nullptr;
120}
121
122bool PNS_LOG_FILE::parseCommonPnsProps( PNS::ITEM* aItem, const wxString& cmd,
123 wxStringTokenizer& aTokens )
124{
125 if( cmd == wxS( "net" ) )
126 {
127 aItem->SetNet( m_board->FindNet( wxAtoi( aTokens.GetNextToken() ) ) );
128 return true;
129 }
130 else if( cmd == wxS( "layers" ) )
131 {
132 int start = wxAtoi( aTokens.GetNextToken() );
133 int end = wxAtoi( aTokens.GetNextToken() );
134 aItem->SetLayers( PNS_LAYER_RANGE( start, end ) );
135 return true;
136 }
137 return false;
138}
139
140std::unique_ptr<PNS::SEGMENT> PNS_LOG_FILE::parsePnsSegmentFromString( wxStringTokenizer& aTokens )
141{
142 std::unique_ptr<PNS::SEGMENT> seg( new PNS::SEGMENT() );
143
144 while( aTokens.CountTokens() )
145 {
146 wxString cmd = aTokens.GetNextToken();
147
148 if( !parseCommonPnsProps( seg.get(), cmd, aTokens ) )
149 {
150 if( cmd == wxS( "shape" ) )
151 {
152 std::shared_ptr<SHAPE> sh = parseShape( SH_SEGMENT, aTokens );
153
154 if( !sh )
155 return nullptr;
156
157 seg->SetShape( *static_cast<SHAPE_SEGMENT*>( sh.get() ) );
158
159 }
160 }
161 }
162
163 return seg;
164}
165
166std::unique_ptr<PNS::VIA> PNS_LOG_FILE::parsePnsViaFromString( wxStringTokenizer& aTokens )
167{
168 std::unique_ptr<PNS::VIA> via( new PNS::VIA() );
169
170 while( aTokens.CountTokens() )
171 {
172 wxString cmd = aTokens.GetNextToken();
173
174 if( !parseCommonPnsProps( via.get(), cmd, aTokens ) )
175 {
176 if( cmd == wxS( "shape" ) )
177 {
178 std::shared_ptr<SHAPE> sh = parseShape( SH_CIRCLE, aTokens );
179
180 if( !sh )
181 return nullptr;
182
183 SHAPE_CIRCLE* sc = static_cast<SHAPE_CIRCLE*>( sh.get() );
184
185 via->SetPos( sc->GetCenter() );
186 via->SetDiameter( PNS::VIA::ALL_LAYERS, 2 * sc->GetRadius() );
187 }
188 else if( cmd == wxS( "drill" ) )
189 {
190 via->SetDrill( wxAtoi( aTokens.GetNextToken() ) );
191 }
192 }
193 }
194
195 return via;
196}
197
198
199std::unique_ptr<PNS::ITEM> PNS_LOG_FILE::parseItemFromString( wxStringTokenizer& aTokens )
200{
201 wxString type = aTokens.GetNextToken();
202
203 if( type == wxS( "segment" ) )
204 return parsePnsSegmentFromString( aTokens );
205 else if( type == wxS( "via" ) )
206 return parsePnsViaFromString( aTokens );
207
208 return nullptr;
209}
210
211bool comparePnsItems( const PNS::ITEM* a , const PNS::ITEM* b )
212{
213 if( a->Kind() != b->Kind() )
214 return false;
215
216 if( a->Net() != b->Net() )
217 return false;
218
219 if( a->Layers() != b->Layers() )
220 return false;
221
222 if( a->Kind() == PNS::ITEM::VIA_T )
223 {
224 const PNS::VIA* va = static_cast<const PNS::VIA*>(a);
225 const PNS::VIA* vb = static_cast<const PNS::VIA*>(b);
226
227 // TODO(JE) padstacks
229 return false;
230
231 if( va->Drill() != vb->Drill() )
232 return false;
233
234 if( va->Pos() != vb->Pos() )
235 return false;
236
237 }
238 else if ( a->Kind() == PNS::ITEM::SEGMENT_T )
239 {
240 const PNS::SEGMENT* sa = static_cast<const PNS::SEGMENT*>(a);
241 const PNS::SEGMENT* sb = static_cast<const PNS::SEGMENT*>(b);
242
243 if( sa->Seg() != sb->Seg() )
244 return false;
245
246 if( sa->Width() != sb->Width() )
247 return false;
248 }
249
250 return true;
251}
252
253
254const std::set<PNS::ITEM*> deduplicate( const std::vector<PNS::ITEM*>& items )
255{
256 std::set<PNS::ITEM*> rv;
257
258 for( PNS::ITEM* item : items )
259 {
260 bool isDuplicate = false;
261
262 for( PNS::ITEM* ritem : rv )
263 {
264 if( comparePnsItems( ritem, item) )
265 {
266 isDuplicate = true;
267 break;
268 }
269
270 if( !isDuplicate )
271 rv.insert( item );
272 }
273 }
274
275 return rv;
276}
277
278
280{
281 COMMIT_STATE check( aOther );
282
283 //printf("pre-compare: %d/%d\n", check.m_addedItems.size(), check.m_removedIds.size() );
284 //printf("pre-compare (log): %d/%d\n", m_addedItems.size(), m_removedIds.size() );
285
286 for( const KIID& uuid : m_removedIds )
287 {
288 if( check.m_removedIds.find( uuid ) != check.m_removedIds.end() )
289 check.m_removedIds.erase( uuid );
290 else
291 return false; // removed twice? wtf
292 }
293
294 std::set<PNS::ITEM*> addedItems = deduplicate( m_addedItems );
295 std::set<PNS::ITEM*> chkAddedItems = deduplicate( check.m_addedItems );
296
297 for( PNS::ITEM* item : addedItems )
298 {
299 for( PNS::ITEM* chk : chkAddedItems )
300 {
301 if( comparePnsItems( item, chk ) )
302 {
303 chkAddedItems.erase( chk );
304 break;
305 }
306 }
307 }
308
309 //printf("post-compare: %d/%d\n", chkAddedItems.size(), check.m_removedIds.size() );
310
311 if( chkAddedItems.empty() && check.m_removedIds.empty() )
312 return true;
313 else
314 return false; // Set breakpoint here to trap failing tests
315}
316
317
318bool PNS_LOG_FILE::SaveLog( const wxFileName& logFileName, REPORTER* aRpt )
319{
320 FILE* log_f = wxFopen( logFileName.GetFullPath(), "wb" );
324 m_events );
325 fprintf( log_f, "%s\n", logString.c_str().AsChar() );
326 fclose( log_f );
327
328 return true;
329}
330
331
332bool PNS_LOG_FILE::Load( const wxFileName& logFileName, REPORTER* aRpt )
333{
334 wxFileName fname_log( logFileName );
335 fname_log.SetExt( wxT( "log" ) );
336
337 wxFileName fname_dump( logFileName );
338 fname_dump.SetExt( wxT( "dump" ) );
339
340 wxFileName fname_project( logFileName );
341 fname_project.SetExt( wxT( "kicad_pro" ) );
342 fname_project.MakeAbsolute();
343
344 wxFileName fname_settings( logFileName );
345 fname_settings.SetExt( wxT( "settings" ) );
346
347 aRpt->Report( wxString::Format( wxT( "Loading router settings from '%s'" ),
348 fname_settings.GetFullPath() ) );
349
350 bool ok = m_routerSettings->LoadFromRawFile( fname_settings.GetFullPath() );
351
352 if( !ok )
353 {
354 aRpt->Report( wxT( "Failed to load routing settings. Using defaults." ),
356 }
357
358 aRpt->Report( wxString::Format( wxT( "Loading project settings from '%s'" ),
359 fname_settings.GetFullPath() ) );
360
361 m_settingsMgr.reset( new SETTINGS_MANAGER ( true ) );
362 m_settingsMgr->LoadProject( fname_project.GetFullPath() );
363 PROJECT* project = m_settingsMgr->GetProject( fname_project.GetFullPath() );
364 project->SetReadOnly();
365
366 try
367 {
369 aRpt->Report( wxString::Format( wxT("Loading board snapshot from '%s'"),
370 fname_dump.GetFullPath() ) );
371
372 m_board.reset( io.LoadBoard( fname_dump.GetFullPath(), nullptr, nullptr ) );
373 m_board->SetProject( project );
374
375 std::shared_ptr<DRC_ENGINE> drcEngine( new DRC_ENGINE );
376
377 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
378
379 bds.m_DRCEngine = drcEngine;
380 bds.m_UseConnectedTrackWidth = project->GetLocalSettings().m_AutoTrackWidth;
381
382 m_board->SynchronizeNetsAndNetClasses( true );
383
384 drcEngine->SetBoard( m_board.get() );
385 drcEngine->SetDesignSettings( &bds );
386 drcEngine->SetLogReporter( aRpt );
387 drcEngine->InitEngine( wxFileName() );
388 }
389 catch( const PARSE_ERROR& parse_error )
390 {
391 aRpt->Report( wxString::Format( "parse error : %s (%s)\n",
392 parse_error.Problem(),
393 parse_error.What() ),
395
396 return false;
397 }
398
399 FILE* f = fopen( fname_log.GetFullPath().c_str(), "rb" );
400
401 aRpt->Report( wxString::Format( "Loading log from '%s'", fname_log.GetFullPath() ) );
402
403 if( !f )
404 {
405 aRpt->Report( wxT( "Failed to load log" ), RPT_SEVERITY_ERROR );
406 return false;
407 }
408
409 while( !feof( f ) )
410 {
411 wxString line = readLine( f );
412 wxStringTokenizer tokens( line );
413
414 if( !tokens.CountTokens() )
415 continue;
416
417 wxString cmd = tokens.GetNextToken();
418
419 if( cmd == wxT( "mode" ) )
420 {
421 m_mode = static_cast<PNS::ROUTER_MODE>( wxAtoi( tokens.GetNextToken() ) );
422 }
423 else if( cmd == wxT( "event" ) )
424 {
425 m_events.push_back( std::move( PNS::LOGGER::ParseEvent( line ) ) );
426 }
427 else if ( cmd == wxT( "added" ) )
428 {
429 m_parsed_items.push_back( std::move( parseItemFromString( tokens ) ) );
430 m_commitState.m_addedItems.push_back( m_parsed_items.back().get() );
431 }
432 else if ( cmd == wxT( "removed" ) )
433 {
434 m_commitState.m_removedIds.insert( KIID( tokens.GetNextToken() ) );
435 }
436 }
437
438 fclose( f );
439
440 return true;
441}
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:89
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
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *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 PNS_LAYER_RANGE &aLayers)
Definition: pns_item.h:200
const PNS_LAYER_RANGE & Layers() const
Definition: pns_item.h:199
virtual NET_HANDLE Net() const
Definition: pns_item.h:197
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:170
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:196
@ SEGMENT_T
Definition: pns_item.h:106
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:79
static EVENT_ENTRY ParseEvent(const wxString &aLine)
Definition: pns_logger.cpp:128
Contain all persistent settings of the router, such as the mode, optimization effort,...
const SEG & Seg() const
Definition: pns_segment.h:90
int Width() const override
Definition: pns_segment.h:85
int Diameter(int aLayer) const
Definition: pns_via.h:191
const VECTOR2I & Pos() const
Definition: pns_via.h:175
int Drill() const
Definition: pns_via.h:211
static constexpr int ALL_LAYERS
Definition: pns_via.h:76
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
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:119
std::unique_ptr< PNS::SEGMENT > parsePnsSegmentFromString(wxStringTokenizer &aTokens)
std::shared_ptr< BOARD > m_board
Definition: pns_log_file.h:116
std::shared_ptr< SETTINGS_MANAGER > m_settingsMgr
Definition: pns_log_file.h:113
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:118
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:117
std::vector< PNS::LOGGER::EVENT_ENTRY > m_events
Definition: pns_log_file.h:115
std::vector< BOARD_CONNECTED_ITEM * > ItemsById(const PNS::LOGGER::EVENT_ENTRY &evt)
std::unique_ptr< PNS::ROUTING_SETTINGS > m_routerSettings
Definition: pns_log_file.h:114
Container for project specific data.
Definition: project.h:64
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
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:118
const VECTOR2I GetCenter() const
Definition: shape_circle.h:123
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:57
std::vector< KIID > uuids
Definition: pns_logger.h:60
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