KiCad PCB EDA Suite
GERBER_JOBFILE_WRITER Class Reference

GERBER_JOBFILE_WRITER is a class used to create Gerber job file a Gerber job file stores info to make a board: list of gerber files info about the board itsel: size, number of copper layers thickness of the board, copper and dielectric and some other info (colors, finish type ...) More...

#include <gerber_jobfile_writer.h>

Public Member Functions

 GERBER_JOBFILE_WRITER (BOARD *aPcb, REPORTER *aReporter=nullptr)
 
virtual ~GERBER_JOBFILE_WRITER ()
 
void AddGbrFile (PCB_LAYER_ID aLayer, wxString &aFilename)
 add a gerber file name and type in job file list More...
 
bool CreateJobFile (const wxString &aFullFilename)
 Creates a Gerber job file. More...
 
bool WriteJSONJobFile (const wxString &aFullFilename)
 Creates an Gerber job file in JSON format. More...
 

Private Member Functions

enum ONSIDE hasSilkLayers ()
 
enum ONSIDE hasSolderMasks ()
 
const char * sideKeyValue (enum ONSIDE aValue)
 
void addJSONHeader ()
 Add the job file header in JSON format to m_JSONbuffer. More...
 
void addJSONGeneralSpecs ()
 Add the General Specs in JSON format to m_JSONbuffer. More...
 
void addJSONFilesAttributes ()
 Add the Files Attributes section in JSON format to m_JSONbuffer. More...
 
void addJSONMaterialStackup ()
 Add the Material Stackup section in JSON format to m_JSONbuffer This is the ordered list of stackup layers (mask, paste, silk, copper, dielectric) used to make the physical board. More...
 
void addJSONDesignRules ()
 Add the Design Rules section in JSON format to m_JSONbuffer. More...
 
std::string formatStringFromUTF32 (const wxString &aText)
 A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a escaped unicode sequence of 4 hexa). More...
 
double mapValue (double aUiValue)
 A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm), with only 4 digits in mantissa for a better readability when printed using g or equivalent format. More...
 

Private Attributes

BOARDm_pcb
 
REPORTERm_reporter
 
JOBFILE_PARAMS m_params
 
double m_conversionUnits
 
json m_json
 

Detailed Description

GERBER_JOBFILE_WRITER is a class used to create Gerber job file a Gerber job file stores info to make a board: list of gerber files info about the board itsel: size, number of copper layers thickness of the board, copper and dielectric and some other info (colors, finish type ...)

note: dimensions are always in mm in Kicad job file (can be also in inches in a job file) and they are in floating point notation

Definition at line 73 of file gerber_jobfile_writer.h.

Constructor & Destructor Documentation

◆ GERBER_JOBFILE_WRITER()

GERBER_JOBFILE_WRITER::GERBER_JOBFILE_WRITER ( BOARD aPcb,
REPORTER aReporter = nullptr 
)

Definition at line 53 of file gerber_jobfile_writer.cpp.

54 {
55  m_pcb = aPcb;
56  m_reporter = aReporter;
57  m_conversionUnits = 1.0 / IU_PER_MM; // Gerber units = mm
58 }

References m_conversionUnits, m_pcb, and m_reporter.

◆ ~GERBER_JOBFILE_WRITER()

virtual GERBER_JOBFILE_WRITER::~GERBER_JOBFILE_WRITER ( )
inlinevirtual

Definition at line 78 of file gerber_jobfile_writer.h.

79  {
80  }

Member Function Documentation

◆ AddGbrFile()

void GERBER_JOBFILE_WRITER::AddGbrFile ( PCB_LAYER_ID  aLayer,
wxString &  aFilename 
)
inline

add a gerber file name and type in job file list

Parameters
aLayeris the PCB_LAYER_ID corresponding to the gerber file
aFilenameis the filename (without path) of the gerber file

Definition at line 87 of file gerber_jobfile_writer.h.

88  {
89  m_params.m_GerberFileList.Add( aFilename );
90  m_params.m_LayerId.push_back( aLayer );
91  }
wxArrayString m_GerberFileList
std::vector< PCB_LAYER_ID > m_LayerId

References JOBFILE_PARAMS::m_GerberFileList, JOBFILE_PARAMS::m_LayerId, and m_params.

Referenced by DIALOG_PLOT::Plot().

◆ addJSONDesignRules()

void GERBER_JOBFILE_WRITER::addJSONDesignRules ( )
private

Add the Design Rules section in JSON format to m_JSONbuffer.

Definition at line 445 of file gerber_jobfile_writer.cpp.

446 {
447  // Add the Design Rules section in JSON format to m_JSONbuffer
448  // Job file support a few design rules:
449  const BOARD_DESIGN_SETTINGS& dsnSettings = m_pcb->GetDesignSettings();
450  NETCLASS defaultNC = *dsnSettings.GetDefault();
451  int minclearanceOuter = defaultNC.GetClearance();
452  bool hasInnerLayers = m_pcb->GetCopperLayerCount() > 2;
453 
454  // Search a smaller clearance in other net classes, if any.
455  for( const std::pair<const wxString, NETCLASSPTR>& entry : dsnSettings.GetNetClasses() )
456  minclearanceOuter = std::min( minclearanceOuter, entry.second->GetClearance() );
457 
458  // job file knows different clearance types.
459  // Kicad knows only one clearance for pads and tracks
460  int minclearance_track2track = minclearanceOuter;
461 
462  // However, pads can have a specific clearance defined for a pad or a footprint,
463  // and min clearance can be dependent on layers.
464  // Search for a minimal pad clearance:
465  int minPadClearanceOuter = defaultNC.GetClearance();
466  int minPadClearanceInner = defaultNC.GetClearance();
467 
468  for( MODULE* module : m_pcb->Modules() )
469  {
470  for( auto& pad : module->Pads() )
471  {
472  if( ( pad->GetLayerSet() & LSET::InternalCuMask() ).any() )
473  minPadClearanceInner = std::min( minPadClearanceInner, pad->GetClearance() );
474 
475  if( ( pad->GetLayerSet() & LSET::ExternalCuMask() ).any() )
476  minPadClearanceOuter = std::min( minPadClearanceOuter, pad->GetClearance() );
477  }
478  }
479 
480  m_json["DesignRules"] = { {
481  { "Layers", "Outer" },
482  { "PadToPad", mapValue( minPadClearanceOuter ) },
483  { "PadToTrack", mapValue( minPadClearanceOuter ) },
484  { "TrackToTrack", mapValue( minclearance_track2track ) }
485  } };
486 
487  // Until this is changed in Kicad, use the same value for internal tracks
488  int minclearanceInner = minclearanceOuter;
489 
490  // Output the minimal track width
491  int mintrackWidthOuter = INT_MAX;
492  int mintrackWidthInner = INT_MAX;
493 
494  for( TRACK* track : m_pcb->Tracks() )
495  {
496  if( track->Type() == PCB_VIA_T )
497  continue;
498 
499  if( track->GetLayer() == B_Cu || track->GetLayer() == F_Cu )
500  mintrackWidthOuter = std::min( mintrackWidthOuter, track->GetWidth() );
501  else
502  mintrackWidthInner = std::min( mintrackWidthInner, track->GetWidth() );
503  }
504 
505  if( mintrackWidthOuter != INT_MAX )
506  m_json["DesignRules"][0]["MinLineWidth"] = mapValue( mintrackWidthOuter );
507 
508  // Output the minimal zone to xx clearance
509  // Note: zones can have a zone clearance set to 0
510  // if happens, the actual zone clearance is the clearance of its class
511  minclearanceOuter = INT_MAX;
512  minclearanceInner = INT_MAX;
513 
514  for( int ii = 0; ii < m_pcb->GetAreaCount(); ii++ )
515  {
516  ZONE_CONTAINER* zone = m_pcb->GetArea( ii );
517 
518  if( zone->GetIsKeepout() || !zone->IsOnCopperLayer() )
519  continue;
520 
521  int zclerance = zone->GetClearance();
522 
523  if( zone->GetLayer() == B_Cu || zone->GetLayer() == F_Cu )
524  minclearanceOuter = std::min( minclearanceOuter, zclerance );
525  else
526  minclearanceInner = std::min( minclearanceInner, zclerance );
527  }
528 
529  if( minclearanceOuter != INT_MAX )
530  m_json["DesignRules"][0]["TrackToRegion"] = mapValue( minclearanceOuter );
531 
532  if( minclearanceOuter != INT_MAX )
533  m_json["DesignRules"][0]["RegionToRegion"] = mapValue( minclearanceOuter );
534 
535  if( hasInnerLayers )
536  {
537  m_json["DesignRules"] += json( {
538  { "Layers", "Inner" },
539  { "PadToPad", mapValue( minPadClearanceInner ) },
540  { "PadToTrack", mapValue( minPadClearanceInner ) },
541  { "TrackToTrack", mapValue( minclearance_track2track ) }
542  } );
543 
544  if( mintrackWidthInner != INT_MAX )
545  m_json["DesignRules"][1]["MinLineWidth"] = mapValue( mintrackWidthInner );
546 
547  if( minclearanceInner != INT_MAX )
548  m_json["DesignRules"][1]["TrackToRegion"] = mapValue( minclearanceInner );
549 
550  if( minclearanceInner != INT_MAX )
551  m_json["DesignRules"][1]["RegionToRegion"] = mapValue( minclearanceInner );
552  }
553 }
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
double mapValue(double aUiValue)
A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm),...
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:236
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
int GetClearance(wxString *aSource=nullptr) const
Definition: netclass.h:158
nlohmann::json json
Definition: gerbview.cpp:40
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:932
MODULES & Modules()
Definition: class_board.h:266
NETCLASS handles a collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:49
static LSET InternalCuMask()
Function InternalCuMask() returns a complete set of internal copper layers, which is all Cu layers ex...
Definition: lset.cpp:672
static LSET ExternalCuMask()
Function ExternalCuMask returns a mask holding the Front and Bottom layers.
Definition: lset.cpp:742
NETCLASSES & GetNetClasses() const
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:702
virtual int GetClearance(BOARD_ITEM *aItem=nullptr, wxString *aSource=nullptr) const
Function GetClearance returns the clearance in internal units.
int GetCopperLayerCount() const
Function GetCopperLayerCount.
NETCLASS * GetDefault() const
Function GetDefault.
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:897
TRACKS & Tracks()
Definition: class_board.h:257
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: class_zone.cpp:242
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.

References B_Cu, LSET::ExternalCuMask(), F_Cu, BOARD::GetArea(), BOARD::GetAreaCount(), NETCLASS::GetClearance(), BOARD_CONNECTED_ITEM::GetClearance(), BOARD::GetCopperLayerCount(), BOARD_DESIGN_SETTINGS::GetDefault(), BOARD::GetDesignSettings(), ZONE_CONTAINER::GetIsKeepout(), ZONE_CONTAINER::GetLayer(), BOARD_DESIGN_SETTINGS::GetNetClasses(), LSET::InternalCuMask(), ZONE_CONTAINER::IsOnCopperLayer(), m_json, m_pcb, mapValue(), BOARD::Modules(), PCB_VIA_T, and BOARD::Tracks().

Referenced by WriteJSONJobFile().

◆ addJSONFilesAttributes()

void GERBER_JOBFILE_WRITER::addJSONFilesAttributes ( )
private

Add the Files Attributes section in JSON format to m_JSONbuffer.

Definition at line 334 of file gerber_jobfile_writer.cpp.

335 {
336  // Add the Files Attributes section in JSON format to m_JSONbuffer
337  m_json["FilesAttributes"] = json::array();
338 
339  for( unsigned ii = 0; ii < m_params.m_GerberFileList.GetCount(); ii++ )
340  {
341  wxString& name = m_params.m_GerberFileList[ii];
342  PCB_LAYER_ID layer = m_params.m_LayerId[ii];
343  wxString gbr_layer_id;
344  bool skip_file = false; // true to skip files which should not be in job file
345  const char* polarity = "Positive";
346  json file_json;
347 
348  if( layer <= B_Cu )
349  {
350  gbr_layer_id = "Copper,L";
351 
352  if( layer == B_Cu )
353  gbr_layer_id << m_pcb->GetCopperLayerCount();
354  else
355  gbr_layer_id << layer + 1;
356 
357  gbr_layer_id << ",";
358 
359  if( layer == B_Cu )
360  gbr_layer_id << "Bot";
361  else if( layer == F_Cu )
362  gbr_layer_id << "Top";
363  else
364  gbr_layer_id << "Inr";
365  }
366 
367  else
368  {
369  switch( layer )
370  {
371  case B_Adhes:
372  gbr_layer_id = "Glue,Bot";
373  break;
374  case F_Adhes:
375  gbr_layer_id = "Glue,Top";
376  break;
377 
378  case B_Paste:
379  gbr_layer_id = "SolderPaste,Bot";
380  break;
381  case F_Paste:
382  gbr_layer_id = "SolderPaste,Top";
383  break;
384 
385  case B_SilkS:
386  gbr_layer_id = "Legend,Bot";
387  break;
388  case F_SilkS:
389  gbr_layer_id = "Legend,Top";
390  break;
391 
392  case B_Mask:
393  gbr_layer_id = "SolderMask,Bot";
394  polarity = "Negative";
395  break;
396  case F_Mask:
397  gbr_layer_id = "SolderMask,Top";
398  polarity = "Negative";
399  break;
400 
401  case Edge_Cuts:
402  gbr_layer_id = "Profile";
403  break;
404 
405  case B_Fab:
406  gbr_layer_id = "AssemblyDrawing,Bot";
407  break;
408  case F_Fab:
409  gbr_layer_id = "AssemblyDrawing,Top";
410  break;
411 
412  case Dwgs_User:
413  case Cmts_User:
414  case Eco1_User:
415  case Eco2_User:
416  case Margin:
417  case B_CrtYd:
418  case F_CrtYd:
419  skip_file = true;
420  break;
421 
422  default:
423  skip_file = true;
424  m_reporter->Report( "Unexpected layer id in job file", RPT_SEVERITY_ERROR );
425  break;
426  }
427  }
428 
429  if( !skip_file )
430  {
431  // name can contain non ASCII7 chars.
432  // Ensure the name is JSON compatible.
433  std::string strname = formatStringFromUTF32( name );
434 
435  file_json["Path"] = strname.c_str();
436  file_json["FileFunction"] = gbr_layer_id;
437  file_json["FilePolarity"] = polarity;
438 
439  m_json["FilesAttributes"] += file_json;
440  }
441  }
442 }
std::string formatStringFromUTF32(const wxString &aText)
A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a e...
nlohmann::json json
Definition: gerbview.cpp:40
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
wxArrayString m_GerberFileList
PCB_LAYER_ID
A quick note on layer IDs:
const char * name
Definition: DXF_plotter.cpp:60
int GetCopperLayerCount() const
Function GetCopperLayerCount.
std::vector< PCB_LAYER_ID > m_LayerId

References B_Adhes, B_CrtYd, B_Cu, B_Fab, B_Mask, B_Paste, B_SilkS, Cmts_User, Dwgs_User, Eco1_User, Eco2_User, Edge_Cuts, F_Adhes, F_CrtYd, F_Cu, F_Fab, F_Mask, F_Paste, F_SilkS, formatStringFromUTF32(), BOARD::GetCopperLayerCount(), JOBFILE_PARAMS::m_GerberFileList, m_json, JOBFILE_PARAMS::m_LayerId, m_params, m_pcb, m_reporter, Margin, name, REPORTER::Report(), and RPT_SEVERITY_ERROR.

Referenced by WriteJSONJobFile().

◆ addJSONGeneralSpecs()

void GERBER_JOBFILE_WRITER::addJSONGeneralSpecs ( )
private

Add the General Specs in JSON format to m_JSONbuffer.

Definition at line 235 of file gerber_jobfile_writer.cpp.

236 {
237  m_json["GeneralSpecs"] = json( {} );
238  m_json["GeneralSpecs"]["ProjectId"] = json( {} );
239 
240  // Creates the ProjectId. Format is (from Gerber file format doc):
241  // ProjectId,<project id>,<project GUID>,<revision id>*%
242  // <project id> is the name of the project, restricted to basic ASCII symbols only,
243  // and comma not accepted
244  // All illegal chars will be replaced by underscore
245  // Rem: <project id> accepts only ASCII 7 code (only basic ASCII codes are allowed in gerber files).
246  //
247  // <project GUID> is a string which is an unique id of a project.
248  // However Kicad does not handle such a project GUID, so it is built from the board name
249  wxFileName fn = m_pcb->GetFileName();
250  wxString msg = fn.GetFullName();
251 
252  // Build a <project GUID>, from the board name
253  wxString guid = GbrMakeProjectGUIDfromString( msg );
254 
255  // build the <project id> string: this is the board short filename (without ext)
256  // and all non ASCII chars are replaced by '_', to be compatible with .gbr files.
257  msg = fn.GetName();
258 
259  // build the <rec> string. All non ASCII chars and comma are replaced by '_'
260  wxString rev = m_pcb->GetTitleBlock().GetRevision();
261 
262  if( rev.IsEmpty() )
263  rev = wxT( "rev?" );
264 
265  m_json["GeneralSpecs"]["ProjectId"]["Name"] = msg.ToAscii();
266  m_json["GeneralSpecs"]["ProjectId"]["GUID"] = guid;
267  m_json["GeneralSpecs"]["ProjectId"]["Revision"] = rev.ToAscii();
268 
269  // output the bord size in mm:
271 
272  m_json["GeneralSpecs"]["Size"]["X"] = mapValue( brect.GetWidth() );
273  m_json["GeneralSpecs"]["Size"]["Y"] = mapValue( brect.GetHeight() );
274 
275 
276  // Add some data to the JSON header, GeneralSpecs:
277  // number of copper layers
278  m_json["GeneralSpecs"]["LayerNumber"] = m_pcb->GetCopperLayerCount();
279 
280  // Board thickness
281  m_json["GeneralSpecs"]["BoardThickness"] =
283 
284  // Copper finish
286 
287  if( !brd_stackup.m_FinishType.IsEmpty() )
288  m_json["GeneralSpecs"]["Finish"] = brd_stackup.m_FinishType;
289 
290  if( brd_stackup.m_CastellatedPads )
291  m_json["GeneralSpecs"]["Castellated"] = true;
292 
293  if( brd_stackup.m_EdgePlating )
294  m_json["GeneralSpecs"]["EdgePlating"] = true;
295 
296  if( brd_stackup.m_EdgeConnectorConstraints )
297  {
298  m_json["GeneralSpecs"]["EdgeConnector"] = true;
299 
300  m_json["GeneralSpecs"]["EdgeConnectorBevelled"] =
301  ( brd_stackup.m_EdgeConnectorConstraints == BS_EDGE_CONNECTOR_BEVELLED );
302  }
303 
304 #if 0 // Not yet in use
305  /* The board type according to IPC-2221. There are six primary board types:
306  - Type 1 - Single-sided
307  - Type 2 - Double-sided
308  - Type 3 - Multilayer, TH components only
309  - Type 4 - Multilayer, with TH, blind and/or buried vias.
310  - Type 5 - Multilayer metal-core board, TH components only
311  - Type 6 - Multilayer metal-core
312  */
313  m_json["GeneralSpecs"]["IPC-2221-Type"] = 4;
314 
315  /* Via protection: key words:
316  Ia Tented - Single-sided
317  Ib Tented - Double-sided
318  IIa Tented and Covered - Single-sided
319  IIb Tented and Covered - Double-sided
320  IIIa Plugged - Single-sided
321  IIIb Plugged - Double-sided
322  IVa Plugged and Covered - Single-sided
323  IVb Plugged and Covered - Double-sided
324  V Filled (fully plugged)
325  VI Filled and Covered
326  VIII Filled and Capped
327  None...No protection
328  */
329  m_json["GeneralSpecs"]["ViaProtection"] = "Ib";
330 #endif
331 }
double mapValue(double aUiValue)
A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm),...
this class manage the layers needed to make a physical board they are solder mask,...
const EDA_RECT GetBoardEdgesBoundingBox() const
Function GetBoardEdgesBoundingBox Returns the board bounding box calculated using exclusively the boa...
Definition: class_board.h:798
int GetWidth() const
Definition: eda_rect.h:119
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
nlohmann::json json
Definition: gerbview.cpp:40
const wxString & GetFileName() const
Definition: class_board.h:255
BOARD_STACKUP & GetStackupDescriptor()
const wxString & GetRevision() const
Definition: title_block.h:89
wxString GbrMakeProjectGUIDfromString(wxString &aText)
A helper function to build a project GUID using format RFC4122 Version 1 or 4 from the project name,...
int GetHeight() const
Definition: eda_rect.h:120
TITLE_BLOCK & GetTitleBlock()
Definition: class_board.h:578
int GetCopperLayerCount() const
Function GetCopperLayerCount.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44

References BS_EDGE_CONNECTOR_BEVELLED, GbrMakeProjectGUIDfromString(), BOARD::GetBoardEdgesBoundingBox(), BOARD_DESIGN_SETTINGS::GetBoardThickness(), BOARD::GetCopperLayerCount(), BOARD::GetDesignSettings(), BOARD::GetFileName(), EDA_RECT::GetHeight(), TITLE_BLOCK::GetRevision(), BOARD_DESIGN_SETTINGS::GetStackupDescriptor(), BOARD::GetTitleBlock(), EDA_RECT::GetWidth(), m_json, m_pcb, and mapValue().

Referenced by WriteJSONJobFile().

◆ addJSONHeader()

void GERBER_JOBFILE_WRITER::addJSONHeader ( )
private

Add the job file header in JSON format to m_JSONbuffer.

Definition at line 166 of file gerber_jobfile_writer.cpp.

167 {
168  wxString text;
169 
170  m_json["Header"] = {
171  {
172  "GenerationSoftware",
173  {
174  { "Vendor", "KiCad" },
175  { "Application", "Pcbnew" },
176  { "Version", GetBuildVersion() }
177  }
178  },
179  {
180  // The attribute value must conform to the full version of the ISO 8601
181  // date and time format, including time and time zone.
183  }
184  };
185 }
wxString GbrMakeCreationDateAttributeString(GBR_NC_STRING_FORMAT aFormat)
wxString GetBuildVersion()
Get the full KiCad version string.

References GBR_NC_STRING_FORMAT_GBRJOB, GbrMakeCreationDateAttributeString(), GetBuildVersion(), and m_json.

Referenced by WriteJSONJobFile().

◆ addJSONMaterialStackup()

void GERBER_JOBFILE_WRITER::addJSONMaterialStackup ( )
private

Add the Material Stackup section in JSON format to m_JSONbuffer This is the ordered list of stackup layers (mask, paste, silk, copper, dielectric) used to make the physical board.

Therefore not all layers are listed here

Definition at line 556 of file gerber_jobfile_writer.cpp.

557 {
558  // Add the Material Stackup section in JSON format to m_JSONbuffer
559  m_json["MaterialStackup"] = json::array();
560 
561  // Build the candidates list:
562  LSET maskLayer;
564 
565  // Ensure brd_stackup is up to date (i.e. no change made by SynchronizeWithBoard() )
566  bool uptodate = not brd_stackup.SynchronizeWithBoard( &m_pcb->GetDesignSettings() );
567 
568  if( !uptodate && m_pcb->GetDesignSettings().m_HasStackup )
569  m_reporter->Report( _( "Board stackup settings not up to date\n"
570  "Please fix the stackup" ),
572 
573  PCB_LAYER_ID last_copper_layer = F_Cu;
574 
575  // Generate the list (top to bottom):
576  for( int ii = 0; ii < brd_stackup.GetCount(); ++ii )
577  {
578  BOARD_STACKUP_ITEM* item = brd_stackup.GetStackupLayer( ii );
579 
580  int sub_layer_count =
581  item->GetType() == BS_ITEM_TYPE_DIELECTRIC ? item->GetSublayersCount() : 1;
582 
583  for( int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
584  {
585  // layer thickness is always in mm
586  double thickness = mapValue( item->GetThickness( sub_idx ) );
587  wxString layer_type;
588  std::string layer_name; // for comment
589  json layer_json;
590 
591  switch( item->GetType() )
592  {
593  case BS_ITEM_TYPE_COPPER:
594  layer_type = "Copper";
595  layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->GetBrdLayerId() ) );
596  last_copper_layer = item->GetBrdLayerId();
597  break;
598 
600  layer_type = "Legend";
601  layer_name = formatStringFromUTF32( item->GetTypeName() );
602  break;
603 
605  layer_type = "SolderMask";
606  layer_name = formatStringFromUTF32( item->GetTypeName() );
607  break;
608 
610  layer_type = "SolderPaste";
611  layer_name = formatStringFromUTF32( item->GetTypeName() );
612  break;
613 
615  layer_type = "Dielectric";
616  // The option core or prepreg is not added here, as it creates constraints
617  // in build process, not necessary wanted.
618  if( sub_layer_count > 1 )
619  {
620  layer_name =
621  formatStringFromUTF32( wxString::Format( "dielectric layer %d - %d/%d",
622  item->GetDielectricLayerId(), sub_idx + 1, sub_layer_count ) );
623  }
624  else
626  "dielectric layer %d", item->GetDielectricLayerId() ) );
627  break;
628 
629  default:
630  break;
631  }
632 
633  layer_json["Type"] = layer_type;
634 
635  if( item->IsColorEditable() && uptodate )
636  {
637  if( IsPrmSpecified( item->GetColor() ) )
638  {
639  wxString colorName = item->GetColor();
640 
641  if( colorName.StartsWith( "#" ) ) // This is a user defined color.
642  {
643  // In job file a color can be given by its RGB values (0...255)
644  wxColor color( colorName );
645  colorName.Printf( "R%dG%dB%d", color.Red(), color.Green(), color.Blue() );
646  }
647 
648  layer_json["Color"] = colorName;
649  }
650  }
651 
652  if( item->IsThicknessEditable() && uptodate )
653  layer_json["Thickness"] = thickness;
654 
655  if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
656  {
657  if( item->HasMaterialValue() )
658  {
659  layer_json["Material"] = item->GetMaterial( sub_idx );
660 
661  // These constrains are only written if the board has impedance controlled tracks.
662  // If the board is not impedance controlled, they are useless.
663  // Do not add constrains that create more expensive boards.
664  if( brd_stackup.m_HasDielectricConstrains )
665  {
666  // Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
667  // a possible value
668  if( item->GetEpsilonR() > 1.0 )
669  layer_json["DielectricConstant"] = item->FormatEpsilonR( sub_idx );
670 
671  // Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
672  // a possible value
673  if( item->GetLossTangent() > 0.0 )
674  layer_json["LossTangent"] = item->FormatLossTangent( sub_idx );
675  }
676  }
677 
678  PCB_LAYER_ID next_copper_layer = ( PCB_LAYER_ID )( last_copper_layer + 1 );
679 
680  // If the next_copper_layer is the last copper layer, the next layer id is B_Cu
681  if( next_copper_layer >= m_pcb->GetCopperLayerCount() - 1 )
682  next_copper_layer = B_Cu;
683 
684  wxString subLayerName;
685 
686  if( sub_layer_count > 1 )
687  subLayerName.Printf( " (%d/%d)", sub_idx + 1, sub_layer_count );
688 
689  wxString name = wxString::Format( "%s/%s%s",
690  formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
691  formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ),
692  subLayerName );
693 
694  layer_json["Name"] = name;
695 
696  // Add a comment ("Notes"):
697  wxString note;
698 
699  note << wxString::Format( "Type: %s", layer_name.c_str() );
700 
701  note << wxString::Format( " (from %s to %s)",
702  formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
703  formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
704 
705  layer_json["Notes"] = note;
706  }
707  else if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK
708  || item->GetType() == BS_ITEM_TYPE_SILKSCREEN )
709  {
710  if( item->HasMaterialValue() )
711  {
712  layer_json["Material"] = item->GetMaterial();
713 
714  // These constrains are only written if the board has impedance controlled tracks.
715  // If the board is not impedance controlled, they are useless.
716  // Do not add constrains that create more expensive boards.
717  if( brd_stackup.m_HasDielectricConstrains )
718  {
719  // Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
720  // a possible value
721  if( item->GetEpsilonR() > 1.0 )
722  layer_json["DielectricConstant"] = item->FormatEpsilonR();
723 
724  // Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
725  // a possible value
726  if( item->GetLossTangent() > 0.0 )
727  layer_json["LossTangent"] = item->FormatLossTangent();
728  }
729  }
730 
731  layer_json["Name"] = layer_name.c_str();
732  }
733  else
734  {
735  layer_json["Name"] = layer_name.c_str();
736  }
737 
738  m_json["MaterialStackup"].insert( m_json["MaterialStackup"].end(), layer_json );
739  }
740  }
741 }
BOARD_STACKUP_ITEM_TYPE GetType() const
std::string formatStringFromUTF32(const wxString &aText)
A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a e...
BOARD_STACKUP_ITEM * GetStackupLayer(int aIndex)
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer.
bool HasMaterialValue(int aDielectricSubLayer=0) const
double mapValue(double aUiValue)
A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm),...
this class manage the layers needed to make a physical board they are solder mask,...
bool IsPrmSpecified(const wxString &aPrmValue)
int color
Definition: DXF_plotter.cpp:61
wxString GetColor() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
nlohmann::json json
Definition: gerbview.cpp:40
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
double GetLossTangent(int aDielectricSubLayer=0) const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
BOARD_STACKUP & GetStackupDescriptor()
PCB_LAYER_ID
A quick note on layer IDs:
bool IsThicknessEditable() const
LSET is a set of PCB_LAYER_IDs.
int GetThickness(int aDielectricSubLayer=0) const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString FormatEpsilonR(int aDielectricSubLayer=0) const
wxString GetTypeName() const
wxString FormatLossTangent(int aDielectricSubLayer=0) const
this class manage one layer needed to make a physical board it can be a solder mask,...
PCB_LAYER_ID GetBrdLayerId() const
const char * name
Definition: DXF_plotter.cpp:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
int GetDielectricLayerId() const
#define _(s)
Definition: 3d_actions.cpp:33
int GetCopperLayerCount() const
Function GetCopperLayerCount.
bool m_HasStackup
Set to true if the board has a stackup management.
wxString GetMaterial(int aDielectricSubLayer=0) const

References _, B_Cu, BS_ITEM_TYPE_COPPER, BS_ITEM_TYPE_DIELECTRIC, BS_ITEM_TYPE_SILKSCREEN, BS_ITEM_TYPE_SOLDERMASK, BS_ITEM_TYPE_SOLDERPASTE, color, F_Cu, Format(), BOARD_STACKUP_ITEM::FormatEpsilonR(), BOARD_STACKUP_ITEM::FormatLossTangent(), formatStringFromUTF32(), BOARD_STACKUP_ITEM::GetBrdLayerId(), BOARD_STACKUP_ITEM::GetColor(), BOARD::GetCopperLayerCount(), BOARD_STACKUP::GetCount(), BOARD::GetDesignSettings(), BOARD_STACKUP_ITEM::GetDielectricLayerId(), BOARD_STACKUP_ITEM::GetEpsilonR(), BOARD::GetLayerName(), BOARD_STACKUP_ITEM::GetLossTangent(), BOARD_STACKUP_ITEM::GetMaterial(), BOARD_DESIGN_SETTINGS::GetStackupDescriptor(), BOARD_STACKUP::GetStackupLayer(), BOARD_STACKUP_ITEM::GetSublayersCount(), BOARD_STACKUP_ITEM::GetThickness(), BOARD_STACKUP_ITEM::GetType(), BOARD_STACKUP_ITEM::GetTypeName(), BOARD_STACKUP_ITEM::HasMaterialValue(), BOARD_STACKUP_ITEM::IsColorEditable(), IsPrmSpecified(), BOARD_STACKUP_ITEM::IsThicknessEditable(), BOARD_STACKUP::m_HasDielectricConstrains, BOARD_DESIGN_SETTINGS::m_HasStackup, m_json, m_pcb, m_reporter, mapValue(), name, REPORTER::Report(), RPT_SEVERITY_ERROR, and BOARD_STACKUP::SynchronizeWithBoard().

Referenced by WriteJSONJobFile().

◆ CreateJobFile()

bool GERBER_JOBFILE_WRITER::CreateJobFile ( const wxString &  aFullFilename)

Creates a Gerber job file.

Parameters
aFullFilename= the full filename
Returns
true, or false if the file cannot be created

Definition at line 141 of file gerber_jobfile_writer.cpp.

142 {
143  bool success;
144  wxString msg;
145 
146  success = WriteJSONJobFile( aFullFilename );
147 
148  if( !success )
149  {
150  if( m_reporter )
151  {
152  msg.Printf( _( "Unable to create job file \"%s\"" ), aFullFilename );
154  }
155  }
156  else if( m_reporter )
157  {
158  msg.Printf( _( "Create Gerber job file \"%s\"" ), aFullFilename );
160  }
161 
162  return success;
163 }
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
bool WriteJSONJobFile(const wxString &aFullFilename)
Creates an Gerber job file in JSON format.
#define _(s)
Definition: 3d_actions.cpp:33

References _, m_reporter, REPORTER::Report(), RPT_SEVERITY_ACTION, RPT_SEVERITY_ERROR, and WriteJSONJobFile().

Referenced by DIALOG_PLOT::Plot().

◆ formatStringFromUTF32()

std::string GERBER_JOBFILE_WRITER::formatStringFromUTF32 ( const wxString &  aText)
private

A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a escaped unicode sequence of 4 hexa).

Definition at line 60 of file gerber_jobfile_writer.cpp.

61 {
62  std::string fmt_text; // the text after UTF32 to UTF8 conversion
63 
64  for( unsigned long letter : aText )
65  {
66  if( letter >= ' ' && letter <= 0x7F )
67  fmt_text += char( letter );
68  else
69  {
70  char buff[16];
71  sprintf( buff, "\\u%4.4lX", letter );
72  fmt_text += buff;
73  }
74  }
75  return fmt_text;
76 }

Referenced by addJSONFilesAttributes(), and addJSONMaterialStackup().

◆ hasSilkLayers()

enum ONSIDE GERBER_JOBFILE_WRITER::hasSilkLayers ( )
private
Returns
SIDE_NONE if no silk screen layer is in list SIDE_TOP if top silk screen layer is in list SIDE_BOTTOM if bottom silk screen layer is in list SIDE_BOTH if top and bottom silk screen layers are in list

Definition at line 79 of file gerber_jobfile_writer.cpp.

80 {
81  int flag = SIDE_NONE;
82 
83  for( unsigned ii = 0; ii < m_params.m_LayerId.size(); ii++ )
84  {
85  if( m_params.m_LayerId[ii] == B_SilkS )
86  flag |= SIDE_BOTTOM;
87 
88  if( m_params.m_LayerId[ii] == F_SilkS )
89  flag |= SIDE_TOP;
90  }
91 
92  return (enum ONSIDE) flag;
93 }
std::vector< PCB_LAYER_ID > m_LayerId

References B_SilkS, F_SilkS, JOBFILE_PARAMS::m_LayerId, m_params, SIDE_BOTTOM, SIDE_NONE, and SIDE_TOP.

◆ hasSolderMasks()

enum ONSIDE GERBER_JOBFILE_WRITER::hasSolderMasks ( )
private
Returns
SIDE_NONE if no soldermask layer is in list SIDE_TOP if top soldermask layer is in list SIDE_BOTTOM if bottom soldermask layer is in list SIDE_BOTH if top and bottom soldermask layers are in list

Definition at line 96 of file gerber_jobfile_writer.cpp.

97 {
98  int flag = SIDE_NONE;
99 
100  for( unsigned ii = 0; ii < m_params.m_LayerId.size(); ii++ )
101  {
102  if( m_params.m_LayerId[ii] == B_Mask )
103  flag |= SIDE_BOTTOM;
104 
105  if( m_params.m_LayerId[ii] == F_Mask )
106  flag |= SIDE_TOP;
107  }
108 
109  return (enum ONSIDE) flag;
110 }
std::vector< PCB_LAYER_ID > m_LayerId

References B_Mask, F_Mask, JOBFILE_PARAMS::m_LayerId, m_params, SIDE_BOTTOM, SIDE_NONE, and SIDE_TOP.

◆ mapValue()

double GERBER_JOBFILE_WRITER::mapValue ( double  aUiValue)
private

A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm), with only 4 digits in mantissa for a better readability when printed using g or equivalent format.

Definition at line 218 of file gerber_jobfile_writer.cpp.

219 {
220  // A helper function to convert aUiValue in Json units (mm) and to have
221  // 4 digits in Json in mantissa when using %g to print it
222  // i.e. displays values truncated in 0.1 microns.
223  // This is enough for a Json file
224  char buffer[128];
225  sprintf( buffer, "%.4f", aUiValue * m_conversionUnits );
226 
227  long double output;
228  sscanf( buffer, "%Lg", &output );
229 
230  return output;
231 
232 }

References m_conversionUnits.

Referenced by addJSONDesignRules(), addJSONGeneralSpecs(), and addJSONMaterialStackup().

◆ sideKeyValue()

const char * GERBER_JOBFILE_WRITER::sideKeyValue ( enum ONSIDE  aValue)
private
Returns
the key associated to sides used for some layers No TopOnly BotOnly Both

Definition at line 112 of file gerber_jobfile_writer.cpp.

113 {
114  // return the key associated to sides used for some layers
115  // "No, TopOnly, BotOnly or Both"
116  const char* value = nullptr;
117 
118  switch( aValue )
119  {
120  case SIDE_NONE:
121  value = "No";
122  break;
123 
124  case SIDE_TOP:
125  value = "TopOnly";
126  break;
127 
128  case SIDE_BOTTOM:
129  value = "BotOnly";
130  break;
131 
132  case SIDE_BOTH:
133  value = "Both";
134  break;
135  }
136 
137  return value;
138 }

References SIDE_BOTH, SIDE_BOTTOM, SIDE_NONE, and SIDE_TOP.

◆ WriteJSONJobFile()

bool GERBER_JOBFILE_WRITER::WriteJSONJobFile ( const wxString &  aFullFilename)

Creates an Gerber job file in JSON format.

Parameters
aFullFilename= the full filename
aParams= true for a NPTH file, false for a PTH file
Returns
true, or false if the file cannot be created

Definition at line 188 of file gerber_jobfile_writer.cpp.

189 {
190  // Note: in Gerber job file, dimensions are in mm, and are floating numbers
191  std::ofstream file( aFullFilename.ToUTF8() );
192 
194 
195  m_json = json( {} );
196 
197  // output the job file header
198  addJSONHeader();
199 
200  // Add the General Specs
202 
203  // Job file support a few design rules:
205 
206  // output the gerber file list:
208 
209  // output the board stackup:
211 
212  file << std::setw( 2 ) << m_json << std::endl;
213 
214  return true;
215 }
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
void addJSONHeader()
Add the job file header in JSON format to m_JSONbuffer.
nlohmann::json json
Definition: gerbview.cpp:40
void addJSONFilesAttributes()
Add the Files Attributes section in JSON format to m_JSONbuffer.
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
void addJSONDesignRules()
Add the Design Rules section in JSON format to m_JSONbuffer.
void addJSONMaterialStackup()
Add the Material Stackup section in JSON format to m_JSONbuffer This is the ordered list of stackup l...
void addJSONGeneralSpecs()
Add the General Specs in JSON format to m_JSONbuffer.

References addJSONDesignRules(), addJSONFilesAttributes(), addJSONGeneralSpecs(), addJSONHeader(), addJSONMaterialStackup(), dummy(), and m_json.

Referenced by CreateJobFile().

Member Data Documentation

◆ m_conversionUnits

double GERBER_JOBFILE_WRITER::m_conversionUnits
private

Definition at line 170 of file gerber_jobfile_writer.h.

Referenced by GERBER_JOBFILE_WRITER(), and mapValue().

◆ m_json

◆ m_params

JOBFILE_PARAMS GERBER_JOBFILE_WRITER::m_params
private

◆ m_pcb

BOARD* GERBER_JOBFILE_WRITER::m_pcb
private

◆ m_reporter

REPORTER* GERBER_JOBFILE_WRITER::m_reporter
private

The documentation for this class was generated from the following files: