KiCad PCB EDA Suite
pcbnew_scripting_helpers.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) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
5  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <Python.h>
31 #undef HAVE_CLOCK_GETTIME // macro is defined in Python.h and causes redefine warning
32 
34 
35 #include <action_plugin.h>
36 #include <board.h>
37 #include <board_design_settings.h>
38 #include <pcb_marker.h>
39 #include <cstdlib>
40 #include <drc/drc_engine.h>
41 #include <drc/drc_item.h>
42 #include <fp_lib_table.h>
43 #include <io_mgr.h>
44 #include <string_utils.h>
45 #include <macros.h>
47 #include <project.h>
49 #include <specctra.h>
52 #include <locale_io.h>
53 #include <wx/app.h>
54 
55 
56 static PCB_EDIT_FRAME* s_PcbEditFrame = nullptr;
58 
59 
61 {
62  if( s_PcbEditFrame )
63  return s_PcbEditFrame->GetBoard();
64  else
65  return nullptr;
66 }
67 
68 
70 {
71  s_PcbEditFrame = aPcbEditFrame;
72 }
73 
74 
75 BOARD* LoadBoard( wxString& aFileName )
76 {
77  // Loading a new board is not possible if running inside KiCad
78  if( s_PcbEditFrame )
79  return nullptr;
80 
81  if( aFileName.EndsWith( KiCadPcbFileExtension ) )
82  return LoadBoard( aFileName, IO_MGR::KICAD_SEXP );
83  else if( aFileName.EndsWith( LegacyPcbFileExtension ) )
84  return LoadBoard( aFileName, IO_MGR::LEGACY );
85 
86  // as fall back for any other kind use the legacy format
87  return LoadBoard( aFileName, IO_MGR::LEGACY );
88 }
89 
90 
92 {
93  if( !s_SettingsManager )
94  {
95  if( s_PcbEditFrame )
96  {
98  }
99  else
100  {
101  // Ensure wx system settings stuff is available
102  static_cast<void>( wxTheApp );
103  s_SettingsManager = new SETTINGS_MANAGER( true );
104  }
105  }
106 
107  return s_SettingsManager;
108 }
109 
110 
112 {
113  // For some reasons, LoadProject() needs a C locale, so ensure we have the right locale
114  // This is mainly when running QA Python tests
116 
118 
119  if( !project )
120  {
123  }
124 
125  return project;
126 }
127 
128 
129 BOARD* LoadBoard( wxString& aFileName, IO_MGR::PCB_FILE_T aFormat )
130 {
131  // Loading a new board is not possible if running inside KiCad
132  wxASSERT( !s_PcbEditFrame );
133 
134  wxFileName pro = aFileName;
135  pro.SetExt( ProjectFileExtension );
136  pro.MakeAbsolute();
137  wxString projectPath = pro.GetFullPath();
138 
139  // Ensure the "C" locale is temporary set, before reading any file
140  // It also avoid wxWidget alerts about locale issues, later, when using Python 3
142 
143  PROJECT* project = GetSettingsManager()->GetProject( projectPath );
144 
145  if( !project )
146  {
147  GetSettingsManager()->LoadProject( projectPath );
148  project = GetSettingsManager()->GetProject( projectPath );
149  }
150 
151  // Board cannot be loaded without a project, so create the default project
152  if( !project )
154 
155  BOARD* brd = IO_MGR::Load( aFormat, aFileName );
156 
157  if( brd )
158  {
159  brd->SetProject( project );
160 
161  // Move legacy view settings to local project settings
162  if( !brd->m_LegacyVisibleLayers.test( Rescue ) )
163  project->GetLocalSettings().m_VisibleLayers = brd->m_LegacyVisibleLayers;
164 
166  project->GetLocalSettings().m_VisibleItems = brd->m_LegacyVisibleItems;
167 
169  bds.m_DRCEngine = std::make_shared<DRC_ENGINE>( brd, &bds );
170 
171  try
172  {
173  wxFileName rules = pro;
174  rules.SetExt( DesignRulesFileExtension );
175  bds.m_DRCEngine->InitEngine( rules );
176  }
177  catch( ... )
178  {
179  // Best efforts...
180  }
181 
182  for( PCB_MARKER* marker : brd->ResolveDRCExclusions() )
183  brd->Add( marker );
184 
185  brd->BuildConnectivity();
186  brd->BuildListOfNets();
188  }
189 
190  return brd;
191 }
192 
193 
195 {
196  // Creating a new board is not possible if running inside KiCad
197  if( s_PcbEditFrame )
198  return nullptr;
199 
200  BOARD* brd = new BOARD();
201 
202  brd->SetProject( GetDefaultProject() );
203 
204  return brd;
205 }
206 
207 
208 bool SaveBoard( wxString& aFileName, BOARD* aBoard, IO_MGR::PCB_FILE_T aFormat )
209 {
210  aBoard->BuildConnectivity();
212 
213  try
214  {
215  IO_MGR::Save( aFormat, aFileName, aBoard, nullptr );
216  }
217  catch( ... )
218  {
219  return false;
220  }
221 
222  wxFileName pro = aFileName;
223  pro.SetExt( ProjectFileExtension );
224  pro.MakeAbsolute();
225  wxString projectPath = pro.GetFullPath();
226 
227  GetSettingsManager()->SaveProjectAs( pro.GetFullPath() );
228 
229  return true;
230 }
231 
232 
233 bool SaveBoard( wxString& aFileName, BOARD* aBoard )
234 {
235  return SaveBoard( aFileName, aBoard, IO_MGR::KICAD_SEXP );
236 }
237 
238 
240 {
241  BOARD* board = GetBoard();
242 
243  if( !board )
244  return nullptr;
245 
246  PROJECT* project = board->GetProject();
247 
248  if( !project )
249  return nullptr;
250 
251  return project->PcbFootprintLibs();
252 }
253 
254 
255 wxArrayString GetFootprintLibraries()
256 {
257  wxArrayString footprintLibraryNames;
258 
260 
261  if( !tbl )
262  return footprintLibraryNames;
263 
264  for( const wxString& name : tbl->GetLogicalLibs() )
265  footprintLibraryNames.Add( name );
266 
267  return footprintLibraryNames;
268 }
269 
270 
271 wxArrayString GetFootprints( const wxString& aNickName )
272 {
273  wxArrayString footprintNames;
274 
276 
277  if( !tbl )
278  return footprintNames;
279 
280  tbl->FootprintEnumerate( footprintNames, aNickName, true );
281 
282  return footprintNames;
283 }
284 
285 
286 bool ExportSpecctraDSN( wxString& aFullFilename )
287 {
288  if( s_PcbEditFrame )
289  {
290  bool ok = s_PcbEditFrame->ExportSpecctraFile( aFullFilename );
291  return ok;
292  }
293  else
294  {
295  return false;
296  }
297 }
298 
299 
300 bool ExportSpecctraDSN( BOARD* aBoard, wxString& aFullFilename )
301 {
302  try
303  {
304  ExportBoardToSpecctraFile( aBoard, aFullFilename );
305  }
306  catch( ... )
307  {
308  return false;
309  }
310 
311  return true;
312 }
313 
314 
315 bool ExportVRML( const wxString& aFullFileName, double aMMtoWRMLunit, bool aExport3DFiles,
316  bool aUseRelativePaths, const wxString& a3D_Subdir, double aXRef, double aYRef )
317 {
318  if( s_PcbEditFrame )
319  {
320  bool ok = s_PcbEditFrame->ExportVRML_File( aFullFileName, aMMtoWRMLunit,
321  aExport3DFiles, aUseRelativePaths,
322  a3D_Subdir, aXRef, aYRef );
323  return ok;
324  }
325  else
326  {
327  return false;
328  }
329 }
330 
331 bool ImportSpecctraSES( wxString& aFullFilename )
332 {
333  if( s_PcbEditFrame )
334  {
335  bool ok = s_PcbEditFrame->ImportSpecctraSession( aFullFilename );
336  return ok;
337  }
338  else
339  {
340  return false;
341  }
342 }
343 
344 
345 bool ExportFootprintsToLibrary( bool aStoreInNewLib, const wxString& aLibName, wxString* aLibPath )
346 {
347  if( s_PcbEditFrame )
348  {
349  s_PcbEditFrame->ExportFootprintsToLibrary( aStoreInNewLib, aLibName, aLibPath );
350  return true;
351  }
352  else
353  {
354  return false;
355  }
356 }
357 
358 void Refresh()
359 {
360  if( s_PcbEditFrame )
361  {
362  auto board = s_PcbEditFrame->GetBoard();
363  board->BuildConnectivity();
364 
365  // Re-init everything: this is the easy way to do that
368  }
369 }
370 
371 
373 {
374  if( s_PcbEditFrame )
376 }
377 
378 
380 {
381  if( s_PcbEditFrame )
382  return static_cast<int>( s_PcbEditFrame->GetUserUnits() );
383 
384  return -1;
385 }
386 
387 
389 {
391 }
392 
393 
394 bool WriteDRCReport( BOARD* aBoard, const wxString& aFileName, EDA_UNITS aUnits,
395  bool aReportAllTrackErrors )
396 {
397  wxCHECK( aBoard, false );
398 
399  BOARD_DESIGN_SETTINGS& bds = aBoard->GetDesignSettings();
400  std::shared_ptr<DRC_ENGINE> engine = bds.m_DRCEngine;
401 
402  if( !engine )
403  {
404  bds.m_DRCEngine = std::make_shared<DRC_ENGINE>( aBoard, &bds );
405  engine = bds.m_DRCEngine;
406  }
407 
408  wxCHECK( engine, false );
409 
410  wxFileName fn = aBoard->GetFileName();
411  fn.SetExt( DesignRulesFileExtension );
412  wxString drcRulesPath = s_SettingsManager->Prj().AbsolutePath( fn.GetFullName() );
413 
414  try
415  {
416  engine->InitEngine( drcRulesPath );
417  }
418  catch( PARSE_ERROR& )
419  {
420  return false;
421  }
422 
423  std::vector<std::shared_ptr<DRC_ITEM>> footprints;
424  std::vector<std::shared_ptr<DRC_ITEM>> unconnected;
425  std::vector<std::shared_ptr<DRC_ITEM>> violations;
426 
427  engine->SetProgressReporter( nullptr );
428 
429  engine->SetViolationHandler(
430  [&]( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
431  {
432  if( aItem->GetErrorCode() == DRCE_MISSING_FOOTPRINT
433  || aItem->GetErrorCode() == DRCE_DUPLICATE_FOOTPRINT
434  || aItem->GetErrorCode() == DRCE_EXTRA_FOOTPRINT
435  || aItem->GetErrorCode() == DRCE_NET_CONFLICT )
436  {
437  footprints.push_back( aItem );
438  }
439  else if( aItem->GetErrorCode() == DRCE_UNCONNECTED_ITEMS )
440  {
441  unconnected.push_back( aItem );
442  }
443  else
444  {
445  violations.push_back( aItem );
446  }
447  } );
448 
449  engine->RunTests( aUnits, aReportAllTrackErrors, false );
450  engine->ClearViolationHandler();
451 
452  // TODO: Unify this with DIALOG_DRC::writeReport
453 
454  FILE* fp = wxFopen( aFileName, wxT( "w" ) );
455 
456  if( fp == nullptr )
457  return false;
458 
459  std::map<KIID, EDA_ITEM*> itemMap;
460  aBoard->FillItemMap( itemMap );
461 
462  fprintf( fp, "** Drc report for %s **\n", TO_UTF8( aBoard->GetFileName() ) );
463 
464  wxDateTime now = wxDateTime::Now();
465 
466  fprintf( fp, "** Created on %s **\n", TO_UTF8( now.Format( wxT( "%F %T" ) ) ) );
467 
468  fprintf( fp, "\n** Found %d DRC violations **\n", static_cast<int>( violations.size() ) );
469 
470  for( const std::shared_ptr<DRC_ITEM>& item : violations )
471  {
472  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
473  fprintf( fp, "%s", TO_UTF8( item->ShowReport( aUnits, severity, itemMap ) ) );
474  }
475 
476  fprintf( fp, "\n** Found %d unconnected pads **\n", static_cast<int>( unconnected.size() ) );
477 
478  for( const std::shared_ptr<DRC_ITEM>& item : unconnected )
479  {
480  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
481  fprintf( fp, "%s", TO_UTF8( item->ShowReport( aUnits, severity, itemMap ) ) );
482  }
483 
484  fprintf( fp, "\n** Found %d Footprint errors **\n", static_cast<int>( footprints.size() ) );
485 
486  for( const std::shared_ptr<DRC_ITEM>& item : footprints )
487  {
488  SEVERITY severity = bds.GetSeverity( item->GetErrorCode() );
489  fprintf( fp, "%s", TO_UTF8( item->ShowReport( aUnits, severity, itemMap ) ) );
490  }
491 
492  fprintf( fp, "\n** End of Report **\n" );
493  fclose( fp );
494 
495  return true;
496 }
void UpdateUserInterface()
Update the layer manager and other widgets from the board setup (layer and items visibility,...
BOARD * LoadBoard(wxString &aFileName)
bool WriteDRCReport(BOARD *aBoard, const wxString &aFileName, EDA_UNITS aUnits, bool aReportAllTrackErrors)
Run the DRC check on the given board and writes the results to a report file.
void BuildListOfNets()
Definition: board.h:663
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
static bool IsActionRunning()
Container for project specific data.
Definition: project.h:62
SETTINGS_MANAGER * GetSettingsManager() const
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
int GetUserUnits()
Return the currently selected user unit value for the interface.
void SaveProjectAs(const wxString &aFullPath)
Sets the currently loaded project path and saves it (pointers remain valid) Note that this will not m...
const std::string ProjectFileExtension
const std::string LegacyPcbFileExtension
void ActivateGalCanvas() override
Set the #m_Pcb member in such as way as to ensure deleting any previous BOARD.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
const std::string DesignRulesFileExtension
bool ExportFootprintsToLibrary(bool aStoreInNewLib, const wxString &aLibName, wxString *aLibPath)
Save footprints in a library:
wxArrayString GetFootprints(const wxString &aNickName)
Get the names of all of the footprints available in a footprint library.
PROJECT * GetProject() const
Definition: board.h:360
const std::string KiCadPcbFileExtension
void ScriptingSetPcbEditFrame(PCB_EDIT_FRAME *aPcbEditFrame)
bool ExportVRML_File(const wxString &aFullFileName, double aMMtoWRMLunit, bool aExport3DFiles, bool aUseRelativePaths, const wxString &a3D_Subdir, double aXRef, double aYRef)
Create the file(s) exporting current BOARD to a VRML file.
const wxString & GetFileName() const
Definition: board.h:228
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:589
void ExportBoardToSpecctraFile(BOARD *aBoard, const wxString &aFullFilename)
Helper method to export board to DSN file.
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:269
This file contains miscellaneous commonly used macros and functions.
bool IsActionRunning()
Are we currently in an action plugin?
wxArrayString GetFootprintLibraries()
Get the nicknames of all of the footprint libraries configured in pcbnew in both the project and glob...
This is the end of the layers used for visibility bit masks in Pcbnew.
Definition: layer_ids.h:221
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aNickname, bool aBestEfforts)
Return a list of footprint names contained within the library given by aNickname.
void SynchronizeNetsAndNetClasses()
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition: board.cpp:1410
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:607
std::vector< PCB_MARKER * > ResolveDRCExclusions()
Rebuild DRC markers from the serialized data in BOARD_DESIGN_SETTINGS.
Definition: board.cpp:207
#define GAL_LAYER_INDEX(x)
Use this macro to convert a GAL layer to a 0-indexed offset from LAYER_VIAS.
Definition: layer_ids.h:248
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
static SETTINGS_MANAGER * s_SettingsManager
bool ImportSpecctraSES(wxString &aFullFilename)
Import a specctra *.ses file and use it to relocate MODULEs and to replace all vias and tracks in an ...
void ExportFootprintsToLibrary(bool aStoreInNewLib, const wxString &aLibName=wxEmptyString, wxString *aLibPath=nullptr)
Save footprints in a library:
Definition of file extensions used in Kicad.
SEVERITY GetSeverity(int aDRCErrorCode)
void BuildConnectivity()
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition: board.cpp:136
void UpdateUserInterface()
Update the layer manager and other widgets from the board setup (layer and items visibility,...
SEVERITY
FP_LIB_TABLE * GetFootprintLibraryTable()
bool ExportSpecctraDSN(wxString &aFullFilename)
Will export the current BOARD to a specctra dsn file.
SETTINGS_MANAGER * GetSettingsManager()
PROJECT * GetDefaultProject()
BOARD * GetBoard()
EDA_UNITS
Definition: eda_units.h:38
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
void SetProject(PROJECT *aProject)
Link a board to a given project.
Definition: board.cpp:142
bool ImportSpecctraSession(const wxString &aFullFilename)
Import a specctra *.ses file and use it to relocate MODULEs and to replace all vias and tracks in an ...
bool SaveBoard(wxString &aFileName, BOARD *aBoard, IO_MGR::PCB_FILE_T aFormat)
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
Class PCBNEW_ACTION_PLUGINS.
Legacy Pcbnew file formats prior to s-expression.
Definition: io_mgr.h:55
const char * name
Definition: DXF_plotter.cpp:56
bool ExportVRML(const wxString &aFullFileName, double aMMtoWRMLunit, bool aExport3DFiles, bool aUseRelativePaths, const wxString &a3D_Subdir, double aXRef, double aYRef)
Export the current BOARD to a VRML (wrl) file.
static void Save(PCB_FILE_T aFileType, const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=nullptr)
Write either a full aBoard to a storage file in a format that this implementation knows about,...
Definition: io_mgr.cpp:174
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
The main frame for Pcbnew.
BOARD * CreateEmptyBoard()
Construct a default BOARD with a temporary (no filename) project.
BOARD * GetBoard() const
static BOARD * Load(PCB_FILE_T aFileType, const wxString &aFileName, BOARD *aAppendToMe=nullptr, const PROPERTIES *aProperties=nullptr, PROJECT *aProject=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Find the requested PLUGIN and if found, calls the PLUGIN::Load() function on it using the arguments p...
Definition: io_mgr.cpp:158
PCB_FILE_T
The set of file types that the IO_MGR knows about, and for which there has been a plugin written.
Definition: io_mgr.h:53
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Definition: board.cpp:947
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition: board.h:264
std::shared_ptr< DRC_ENGINE > m_DRCEngine
PROJECT * GetProject(const wxString &aFullPath) const
Retrieves a loaded project by name.
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
static PCB_EDIT_FRAME * s_PcbEditFrame
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.
bool ExportSpecctraFile(const wxString &aFullFilename)
Export the current BOARD to a specctra dsn file.
S-expression Pcbnew file format.
Definition: io_mgr.h:56
Container for design settings for a BOARD object.
GAL_SET m_LegacyVisibleItems
Definition: board.h:265