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
 
nlohmann::ordered_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 71 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 54 of file gerber_jobfile_writer.cpp.

55{
56 m_pcb = aPcb;
57 m_reporter = aReporter;
58 m_conversionUnits = 1.0 / pcbIUScale.IU_PER_MM; // Gerber units = mm
59}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
const double IU_PER_MM
Definition: base_units.h:77

References EDA_IU_SCALE::IU_PER_MM, m_conversionUnits, m_pcb, m_reporter, and pcbIUScale.

◆ ~GERBER_JOBFILE_WRITER()

virtual GERBER_JOBFILE_WRITER::~GERBER_JOBFILE_WRITER ( )
inlinevirtual

Definition at line 76 of file gerber_jobfile_writer.h.

77 {
78 }

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 85 of file gerber_jobfile_writer.h.

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

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

Referenced by PCBNEW_JOBS_HANDLER::JobExportGerbers(), and DIALOG_PLOT::Plot().

◆ addJSONDesignRules()

void GERBER_JOBFILE_WRITER::addJSONDesignRules ( )
private

Add the Design Rules section in JSON format to m_JSONbuffer.

Definition at line 463 of file gerber_jobfile_writer.cpp.

464{
465 // Add the Design Rules section in JSON format to m_JSONbuffer
466 // Job file support a few design rules:
467 std::shared_ptr<NET_SETTINGS>& netSettings = m_pcb->GetDesignSettings().m_NetSettings;
468
469 int minclearanceOuter = netSettings->m_DefaultNetClass->GetClearance();
470 bool hasInnerLayers = m_pcb->GetCopperLayerCount() > 2;
471
472 // Search a smaller clearance in other net classes, if any.
473 for( const auto& [ name, netclass ] : netSettings->m_NetClasses )
474 minclearanceOuter = std::min( minclearanceOuter, netclass->GetClearance() );
475
476 // job file knows different clearance types.
477 // Kicad knows only one clearance for pads and tracks
478 int minclearance_track2track = minclearanceOuter;
479
480 // However, pads can have a specific clearance defined for a pad or a footprint,
481 // and min clearance can be dependent on layers.
482 // Search for a minimal pad clearance:
483 int minPadClearanceOuter = netSettings->m_DefaultNetClass->GetClearance();
484 int minPadClearanceInner = netSettings->m_DefaultNetClass->GetClearance();
485
486 for( FOOTPRINT* footprint : m_pcb->Footprints() )
487 {
488 for( PAD* pad : footprint->Pads() )
489 {
490 for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
491 {
492 int padClearance = pad->GetOwnClearance( layer );
493
494 if( layer == B_Cu || layer == F_Cu )
495 minPadClearanceOuter = std::min( minPadClearanceOuter, padClearance );
496 else
497 minPadClearanceInner = std::min( minPadClearanceInner, padClearance );
498 }
499 }
500 }
501
502 m_json["DesignRules"] = { {
503 { "Layers", "Outer" },
504 { "PadToPad", mapValue( minPadClearanceOuter ) },
505 { "PadToTrack", mapValue( minPadClearanceOuter ) },
506 { "TrackToTrack", mapValue( minclearance_track2track ) }
507 } };
508
509 // Until this is changed in Kicad, use the same value for internal tracks
510 int minclearanceInner = minclearanceOuter;
511
512 // Output the minimal track width
513 int mintrackWidthOuter = INT_MAX;
514 int mintrackWidthInner = INT_MAX;
515
516 for( PCB_TRACK* track : m_pcb->Tracks() )
517 {
518 if( track->Type() == PCB_VIA_T )
519 continue;
520
521 if( track->GetLayer() == B_Cu || track->GetLayer() == F_Cu )
522 mintrackWidthOuter = std::min( mintrackWidthOuter, track->GetWidth() );
523 else
524 mintrackWidthInner = std::min( mintrackWidthInner, track->GetWidth() );
525 }
526
527 if( mintrackWidthOuter != INT_MAX )
528 m_json["DesignRules"][0]["MinLineWidth"] = mapValue( mintrackWidthOuter );
529
530 // Output the minimal zone to xx clearance
531 // Note: zones can have a zone clearance set to 0
532 // if happens, the actual zone clearance is the clearance of its class
533 minclearanceOuter = INT_MAX;
534 minclearanceInner = INT_MAX;
535
536 for( ZONE* zone : m_pcb->Zones() )
537 {
538 if( zone->GetIsRuleArea() || !zone->IsOnCopperLayer() )
539 continue;
540
541 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
542 {
543 int zclerance = zone->GetOwnClearance( layer );
544
545 if( layer == B_Cu || layer == F_Cu )
546 minclearanceOuter = std::min( minclearanceOuter, zclerance );
547 else
548 minclearanceInner = std::min( minclearanceInner, zclerance );
549 }
550 }
551
552 if( minclearanceOuter != INT_MAX )
553 m_json["DesignRules"][0]["TrackToRegion"] = mapValue( minclearanceOuter );
554
555 if( minclearanceOuter != INT_MAX )
556 m_json["DesignRules"][0]["RegionToRegion"] = mapValue( minclearanceOuter );
557
558 if( hasInnerLayers )
559 {
560 m_json["DesignRules"] += nlohmann::ordered_json( {
561 { "Layers", "Inner" },
562 { "PadToPad", mapValue( minPadClearanceInner ) },
563 { "PadToTrack", mapValue( minPadClearanceInner ) },
564 { "TrackToTrack", mapValue( minclearance_track2track ) }
565 } );
566
567 if( mintrackWidthInner != INT_MAX )
568 m_json["DesignRules"][1]["MinLineWidth"] = mapValue( mintrackWidthInner );
569
570 if( minclearanceInner != INT_MAX )
571 m_json["DesignRules"][1]["TrackToRegion"] = mapValue( minclearanceInner );
572
573 if( minclearanceInner != INT_MAX )
574 m_json["DesignRules"][1]["RegionToRegion"] = mapValue( minclearanceInner );
575 }
576}
const char * name
Definition: DXF_plotter.cpp:56
std::shared_ptr< NET_SETTINGS > m_NetSettings
ZONES & Zones()
Definition: board.h:313
FOOTPRINTS & Footprints()
Definition: board.h:307
int GetCopperLayerCount() const
Definition: board.cpp:541
TRACKS & Tracks()
Definition: board.h:304
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:682
nlohmann::ordered_json m_json
double mapValue(double aUiValue)
A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm),...
Definition: pad.h:59
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ B_Cu
Definition: layer_ids.h:95
@ F_Cu
Definition: layer_ids.h:64
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102

References B_Cu, F_Cu, BOARD::Footprints(), BOARD::GetCopperLayerCount(), BOARD::GetDesignSettings(), m_json, BOARD_DESIGN_SETTINGS::m_NetSettings, m_pcb, mapValue(), name, pad, PCB_VIA_T, BOARD::Tracks(), and BOARD::Zones().

Referenced by WriteJSONJobFile().

◆ addJSONFilesAttributes()

void GERBER_JOBFILE_WRITER::addJSONFilesAttributes ( )
private

Add the Files Attributes section in JSON format to m_JSONbuffer.

Definition at line 336 of file gerber_jobfile_writer.cpp.

337{
338 // Add the Files Attributes section in JSON format to m_JSONbuffer
339 m_json["FilesAttributes"] = nlohmann::ordered_json::array();
340
341 for( unsigned ii = 0; ii < m_params.m_GerberFileList.GetCount(); ii++ )
342 {
343 wxString& name = m_params.m_GerberFileList[ii];
344 PCB_LAYER_ID layer = m_params.m_LayerId[ii];
345 wxString gbr_layer_id;
346 bool skip_file = false; // true to skip files which should not be in job file
347 const char* polarity = "Positive";
348
349 nlohmann::ordered_json file_json;
350
351 if( layer <= B_Cu )
352 {
353 gbr_layer_id = wxT( "Copper,L" );
354
355 if( layer == B_Cu )
356 gbr_layer_id << m_pcb->GetCopperLayerCount();
357 else
358 gbr_layer_id << layer + 1;
359
360 gbr_layer_id << wxT( "," );
361
362 if( layer == B_Cu )
363 gbr_layer_id << wxT( "Bot" );
364 else if( layer == F_Cu )
365 gbr_layer_id << wxT( "Top" );
366 else
367 gbr_layer_id << wxT( "Inr" );
368 }
369
370 else
371 {
372 switch( layer )
373 {
374 case B_Adhes:
375 gbr_layer_id = wxT( "Glue,Bot" );
376 break;
377 case F_Adhes:
378 gbr_layer_id = wxT( "Glue,Top" );
379 break;
380
381 case B_Paste:
382 gbr_layer_id = wxT( "SolderPaste,Bot" );
383 break;
384 case F_Paste:
385 gbr_layer_id = wxT( "SolderPaste,Top" );
386 break;
387
388 case B_SilkS:
389 gbr_layer_id = wxT( "Legend,Bot" );
390 break;
391 case F_SilkS:
392 gbr_layer_id = wxT( "Legend,Top" );
393 break;
394
395 case B_Mask:
396 gbr_layer_id = wxT( "SolderMask,Bot" );
397 polarity = "Negative";
398 break;
399 case F_Mask:
400 gbr_layer_id = wxT( "SolderMask,Top" );
401 polarity = "Negative";
402 break;
403
404 case Edge_Cuts:
405 gbr_layer_id = wxT( "Profile" );
406 break;
407
408 case B_Fab:
409 gbr_layer_id = wxT( "AssemblyDrawing,Bot" );
410 break;
411 case F_Fab:
412 gbr_layer_id = wxT( "AssemblyDrawing,Top" );
413 break;
414
415 case Margin:
416 case B_CrtYd:
417 case F_CrtYd:
418 skip_file = true;
419 break;
420
421 case Dwgs_User:
422 case Cmts_User:
423 case Eco1_User:
424 case Eco2_User:
425 case User_1:
426 case User_2:
427 case User_3:
428 case User_4:
429 case User_5:
430 case User_6:
431 case User_7:
432 case User_8:
433 case User_9:
434 gbr_layer_id = wxT( "Other,User" );
435 break;
436
437 default:
438 skip_file = true;
439
440 if( m_reporter )
441 m_reporter->Report( wxT( "Unexpected layer id in job file" ), RPT_SEVERITY_ERROR );
442
443 break;
444 }
445 }
446
447 if( !skip_file )
448 {
449 // name can contain non ASCII7 chars.
450 // Ensure the name is JSON compatible.
451 std::string strname = formatStringFromUTF32( name );
452
453 file_json["Path"] = strname.c_str();
454 file_json["FileFunction"] = gbr_layer_id;
455 file_json["FilePolarity"] = polarity;
456
457 m_json["FilesAttributes"] += file_json;
458 }
459 }
460}
std::string formatStringFromUTF32(const wxString &aText)
A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a e...
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
@ User_8
Definition: layer_ids.h:130
@ F_CrtYd
Definition: layer_ids.h:117
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ Cmts_User
Definition: layer_ids.h:110
@ User_6
Definition: layer_ids.h:128
@ User_7
Definition: layer_ids.h:129
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ User_5
Definition: layer_ids.h:127
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ User_9
Definition: layer_ids.h:131
@ F_Fab
Definition: layer_ids.h:120
@ Margin
Definition: layer_ids.h:114
@ F_SilkS
Definition: layer_ids.h:104
@ B_CrtYd
Definition: layer_ids.h:116
@ Eco2_User
Definition: layer_ids.h:112
@ User_3
Definition: layer_ids.h:125
@ User_1
Definition: layer_ids.h:123
@ B_SilkS
Definition: layer_ids.h:103
@ User_4
Definition: layer_ids.h:126
@ User_2
Definition: layer_ids.h:124
@ B_Fab
Definition: layer_ids.h:119
@ RPT_SEVERITY_ERROR

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(), RPT_SEVERITY_ERROR, User_1, User_2, User_3, User_4, User_5, User_6, User_7, User_8, and User_9.

Referenced by WriteJSONJobFile().

◆ addJSONGeneralSpecs()

void GERBER_JOBFILE_WRITER::addJSONGeneralSpecs ( )
private

Add the General Specs in JSON format to m_JSONbuffer.

Definition at line 234 of file gerber_jobfile_writer.cpp.

235{
236 m_json["GeneralSpecs"] = nlohmann::ordered_json( {} );
237 m_json["GeneralSpecs"]["ProjectId"] = nlohmann::ordered_json( {} );
238
239 // Creates the ProjectId. Format is (from Gerber file format doc):
240 // ProjectId,<project id>,<project GUID>,<revision id>*%
241 // <project id> is the name of the project, restricted to basic ASCII symbols only,
242 // and comma not accepted
243 // All illegal chars will be replaced by underscore
244 // Rem: <project id> accepts only ASCII 7 code (only basic ASCII codes are allowed in gerber files).
245 //
246 // <project GUID> is a string which is an unique id of a project.
247 // However Kicad does not handle such a project GUID, so it is built from the board name
248 wxFileName fn = m_pcb->GetFileName();
249 wxString msg = fn.GetFullName();
250
251 // Build a <project GUID>, from the board name
252 wxString guid = GbrMakeProjectGUIDfromString( msg );
253
254 // build the <project id> string: this is the board short filename (without ext)
255 // and all non ASCII chars are replaced by '_', to be compatible with .gbr files.
256 msg = fn.GetName();
257
258 // build the <rec> string. All non ASCII chars and comma are replaced by '_'
260
261 if( rev.IsEmpty() )
262 rev = wxT( "rev?" );
263
264 m_json["GeneralSpecs"]["ProjectId"]["Name"] = msg.ToAscii();
265 m_json["GeneralSpecs"]["ProjectId"]["GUID"] = guid;
266 m_json["GeneralSpecs"]["ProjectId"]["Revision"] = rev.ToAscii();
267
268 // output the board size in mm:
270
271 m_json["GeneralSpecs"]["Size"]["X"] = mapValue( brect.GetWidth() );
272 m_json["GeneralSpecs"]["Size"]["Y"] = mapValue( brect.GetHeight() );
273
274
275 // Add some data to the JSON header, GeneralSpecs:
276 // number of copper layers
277 m_json["GeneralSpecs"]["LayerNumber"] = m_pcb->GetCopperLayerCount();
278
279 // Board thickness
280 m_json["GeneralSpecs"]["BoardThickness"] =
282
283 // Copper finish
285
286 if( !brd_stackup.m_FinishType.IsEmpty() )
287 m_json["GeneralSpecs"]["Finish"] = brd_stackup.m_FinishType;
288
289 if( brd_stackup.m_HasDielectricConstrains )
290 m_json["GeneralSpecs"]["ImpedanceControlled"] = true;
291
292 if( brd_stackup.m_CastellatedPads )
293 m_json["GeneralSpecs"]["Castellated"] = true;
294
295 if( brd_stackup.m_EdgePlating )
296 m_json["GeneralSpecs"]["EdgePlating"] = true;
297
298 if( brd_stackup.m_EdgeConnectorConstraints )
299 {
300 m_json["GeneralSpecs"]["EdgeConnector"] = true;
301
302 m_json["GeneralSpecs"]["EdgeConnectorBevelled"] =
304 }
305
306#if 0 // Not yet in use
307 /* The board type according to IPC-2221. There are six primary board types:
308 - Type 1 - Single-sided
309 - Type 2 - Double-sided
310 - Type 3 - Multilayer, TH components only
311 - Type 4 - Multilayer, with TH, blind and/or buried vias.
312 - Type 5 - Multilayer metal-core board, TH components only
313 - Type 6 - Multilayer metal-core
314 */
315 m_json["GeneralSpecs"]["IPC-2221-Type"] = 4;
316
317 /* Via protection: key words:
318 Ia Tented - Single-sided
319 Ib Tented - Double-sided
320 IIa Tented and Covered - Single-sided
321 IIb Tented and Covered - Double-sided
322 IIIa Plugged - Single-sided
323 IIIb Plugged - Double-sided
324 IVa Plugged and Covered - Single-sided
325 IVb Plugged and Covered - Double-sided
326 V Filled (fully plugged)
327 VI Filled and Covered
328 VIII Filled and Capped
329 None...No protection
330 */
331 m_json["GeneralSpecs"]["ViaProtection"] = "Ib";
332#endif
333}
@ BS_EDGE_CONNECTOR_BEVELLED
Definition: board_stackup.h:57
int GetBoardThickness() const
The full thickness of the board including copper and masks.
BOARD_STACKUP & GetStackupDescriptor()
Manage layers needed to make a physical board.
bool m_CastellatedPads
True if castellated pads exist.
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
const BOX2I GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition: board.h:823
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:632
const wxString & GetFileName() const
Definition: board.h:302
PROJECT * GetProject() const
Definition: board.h:440
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
const wxString & GetRevision() const
Definition: title_block.h:86
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:58
wxString GbrMakeProjectGUIDfromString(const wxString &aText)
Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad proje...

References BS_EDGE_CONNECTOR_BEVELLED, ExpandTextVars(), GbrMakeProjectGUIDfromString(), BOARD::GetBoardEdgesBoundingBox(), BOARD_DESIGN_SETTINGS::GetBoardThickness(), BOARD::GetCopperLayerCount(), BOARD::GetDesignSettings(), BOARD::GetFileName(), BOX2< Vec >::GetHeight(), BOARD::GetProject(), TITLE_BLOCK::GetRevision(), BOARD_DESIGN_SETTINGS::GetStackupDescriptor(), BOARD::GetTitleBlock(), BOX2< Vec >::GetWidth(), BOARD_STACKUP::m_CastellatedPads, BOARD_STACKUP::m_EdgeConnectorConstraints, BOARD_STACKUP::m_EdgePlating, BOARD_STACKUP::m_FinishType, BOARD_STACKUP::m_HasDielectricConstrains, 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 167 of file gerber_jobfile_writer.cpp.

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

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 579 of file gerber_jobfile_writer.cpp.

580{
581 // Add the Material Stackup section in JSON format to m_JSONbuffer
582 m_json["MaterialStackup"] = nlohmann::ordered_json::array();
583
584 // Build the candidates list:
585 LSET maskLayer;
587
588 // Ensure brd_stackup is up to date (i.e. no change made by SynchronizeWithBoard() )
589 bool uptodate = not brd_stackup.SynchronizeWithBoard( &m_pcb->GetDesignSettings() );
590
591 if( m_reporter && !uptodate && m_pcb->GetDesignSettings().m_HasStackup )
592 m_reporter->Report( _( "Board stackup settings not up to date." ), RPT_SEVERITY_ERROR );
593
594 PCB_LAYER_ID last_copper_layer = F_Cu;
595
596 // Generate the list (top to bottom):
597 for( int ii = 0; ii < brd_stackup.GetCount(); ++ii )
598 {
599 BOARD_STACKUP_ITEM* item = brd_stackup.GetStackupLayer( ii );
600
601 int sub_layer_count =
602 item->GetType() == BS_ITEM_TYPE_DIELECTRIC ? item->GetSublayersCount() : 1;
603
604 for( int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
605 {
606 // layer thickness is always in mm
607 double thickness = mapValue( item->GetThickness( sub_idx ) );
608 wxString layer_type;
609 std::string layer_name; // for comment
610
611 nlohmann::ordered_json layer_json;
612
613 switch( item->GetType() )
614 {
616 layer_type = wxT( "Copper" );
617 layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->GetBrdLayerId() ) );
618 last_copper_layer = item->GetBrdLayerId();
619 break;
620
622 layer_type = wxT( "Legend" );
623 layer_name = formatStringFromUTF32( item->GetTypeName() );
624 break;
625
627 layer_type = wxT( "SolderMask" );
628 layer_name = formatStringFromUTF32( item->GetTypeName() );
629 break;
630
632 layer_type = wxT( "SolderPaste" );
633 layer_name = formatStringFromUTF32( item->GetTypeName() );
634 break;
635
637 layer_type = wxT( "Dielectric" );
638 // The option core or prepreg is not added here, as it creates constraints
639 // in build process, not necessary wanted.
640 if( sub_layer_count > 1 )
641 {
642 layer_name =
643 formatStringFromUTF32( wxString::Format( wxT( "dielectric layer %d - %d/%d" ),
644 item->GetDielectricLayerId(), sub_idx + 1, sub_layer_count ) );
645 }
646 else
648 wxT( "dielectric layer %d" ), item->GetDielectricLayerId() ) );
649 break;
650
651 default:
652 break;
653 }
654
655 layer_json["Type"] = layer_type;
656
657 if( item->IsColorEditable() && uptodate )
658 {
659 if( IsPrmSpecified( item->GetColor( sub_idx ) ) )
660 {
661 wxString colorName = item->GetColor( sub_idx );
662
663 if( colorName.StartsWith( wxT( "#" ) ) ) // This is a user defined color,
664 // not in standard color list.
665 {
666 // In job file a color can be given by its RGB values (0...255)
667 // like R<number><G<number>B<number> notation
668 wxColor color( COLOR4D( colorName ).ToColour() );
669 colorName.Printf( wxT( "R%dG%dB%d" ),
670 color.Red(),
671 color.Green(),
672 color.Blue() );
673 }
674 else
675 {
676 const std::vector<FAB_LAYER_COLOR>& color_list =
677 GetStandardColors( item->GetType() );
678
679 // Colors for dielectric use a color list that is mainly not normalized in
680 // job file names. So if a color is in the dielectric standard color list
681 // it can be a standard name or not.
682 // Colors for solder mask and silk screen use a mainly normalized
683 // color list, but this list can also contain not normalized colors.
684 // If not normalized, use the R<number><G<number>B<number> notation
685 for( const FAB_LAYER_COLOR& prm_color : color_list )
686 {
687 if( colorName == prm_color.GetName() )
688 {
689 colorName = prm_color.GetColorAsString();
690 break;
691 }
692 }
693 }
694
695 layer_json["Color"] = colorName;
696 }
697 }
698
699 if( item->IsThicknessEditable() && uptodate )
700 layer_json["Thickness"] = thickness;
701
702 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
703 {
704 if( item->HasMaterialValue() )
705 {
706 layer_json["Material"] = item->GetMaterial( sub_idx );
707
708 // These constrains are only written if the board has impedance controlled tracks.
709 // If the board is not impedance controlled, they are useless.
710 // Do not add constrains that create more expensive boards.
711
712 if( brd_stackup.m_HasDielectricConstrains )
713 {
714 // Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
715 // a possible value
716 if( item->GetEpsilonR() > 1.0 )
717 layer_json["DielectricConstant"] = item->FormatEpsilonR( sub_idx );
718
719 // Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
720 // a possible value
721 if( item->GetLossTangent() > 0.0 )
722 layer_json["LossTangent"] = item->FormatLossTangent( sub_idx );
723 }
724 }
725
726 PCB_LAYER_ID next_copper_layer = ( PCB_LAYER_ID )( last_copper_layer + 1 );
727
728 // If the next_copper_layer is the last copper layer, the next layer id is B_Cu
729 if( next_copper_layer >= m_pcb->GetCopperLayerCount() - 1 )
730 next_copper_layer = B_Cu;
731
732 wxString subLayerName;
733
734 if( sub_layer_count > 1 )
735 subLayerName.Printf( wxT( " (%d/%d)" ), sub_idx + 1, sub_layer_count );
736
737 wxString name = wxString::Format( wxT( "%s/%s%s" ),
738 formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
739 formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ),
740 subLayerName );
741
742 layer_json["Name"] = name;
743
744 // Add a comment ("Notes"):
745 wxString note;
746
747 note << wxString::Format( wxT( "Type: %s" ), layer_name.c_str() );
748
749 note << wxString::Format( wxT( " (from %s to %s)" ),
750 formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
751 formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
752
753 layer_json["Notes"] = note;
754 }
755 else if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK
756 || item->GetType() == BS_ITEM_TYPE_SILKSCREEN )
757 {
758 if( item->HasMaterialValue() )
759 {
760 layer_json["Material"] = item->GetMaterial();
761
762 // These constrains are only written if the board has impedance controlled tracks.
763 // If the board is not impedance controlled, they are useless.
764 // Do not add constrains that create more expensive boards.
765 if( brd_stackup.m_HasDielectricConstrains )
766 {
767 // Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
768 // a possible value
769 if( item->GetEpsilonR() > 1.0 )
770 layer_json["DielectricConstant"] = item->FormatEpsilonR();
771
772 // Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
773 // a possible value
774 if( item->GetLossTangent() > 0.0 )
775 layer_json["LossTangent"] = item->FormatLossTangent();
776 }
777 }
778
779 layer_json["Name"] = layer_name.c_str();
780 }
781 else
782 {
783 layer_json["Name"] = layer_name.c_str();
784 }
785
786 m_json["MaterialStackup"].insert( m_json["MaterialStackup"].end(), layer_json );
787 }
788 }
789}
int color
Definition: DXF_plotter.cpp:57
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_COPPER
Definition: board_stackup.h:43
@ BS_ITEM_TYPE_SILKSCREEN
Definition: board_stackup.h:49
@ BS_ITEM_TYPE_DIELECTRIC
Definition: board_stackup.h:44
@ BS_ITEM_TYPE_SOLDERPASTE
Definition: board_stackup.h:46
@ BS_ITEM_TYPE_SOLDERMASK
Definition: board_stackup.h:47
Manage one layer needed to make a physical board.
Definition: board_stackup.h:91
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString GetColor(int aDielectricSubLayer=0) const
bool HasMaterialValue(int aDielectricSubLayer=0) const
PCB_LAYER_ID GetBrdLayerId() const
bool IsThicknessEditable() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
wxString FormatEpsilonR(int aDielectricSubLayer=0) const
int GetDielectricLayerId() const
bool IsColorEditable() const
wxString FormatLossTangent(int aDielectricSubLayer=0) const
double GetLossTangent(int aDielectricSubLayer=0) const
int GetCount() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
BOARD_STACKUP_ITEM * GetStackupLayer(int aIndex)
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:452
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
#define _(s)
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
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)

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(), GetStandardColors(), 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 142 of file gerber_jobfile_writer.cpp.

143{
144 bool success;
145 wxString msg;
146
147 success = WriteJSONJobFile( aFullFilename );
148
149 if( !success )
150 {
151 if( m_reporter )
152 {
153 msg.Printf( _( "Failed to create file '%s'." ), aFullFilename );
155 }
156 }
157 else if( m_reporter )
158 {
159 msg.Printf( _( "Created Gerber job file '%s'." ), aFullFilename );
161 }
162
163 return success;
164}
bool WriteJSONJobFile(const wxString &aFullFilename)
Creates an Gerber job file in JSON format.
@ RPT_SEVERITY_ACTION

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

Referenced by PCBNEW_JOBS_HANDLER::JobExportGerbers(), and 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 61 of file gerber_jobfile_writer.cpp.

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

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 80 of file gerber_jobfile_writer.cpp.

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

References B_SilkS, F_SilkS, flag, 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 97 of file gerber_jobfile_writer.cpp.

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

References B_Mask, F_Mask, flag, 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 217 of file gerber_jobfile_writer.cpp.

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

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 113 of file gerber_jobfile_writer.cpp.

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

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 187 of file gerber_jobfile_writer.cpp.

188{
189 // Note: in Gerber job file, dimensions are in mm, and are floating numbers
190 std::ofstream file( aFullFilename.ToUTF8() );
191
193
194 m_json = nlohmann::ordered_json( {} );
195
196 // output the job file header
198
199 // Add the General Specs
201
202 // Job file support a few design rules:
204
205 // output the gerber file list:
207
208 // output the board stackup:
210
211 file << std::setw( 2 ) << m_json << std::endl;
212
213 return true;
214}
void addJSONHeader()
Add the job file header 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 addJSONFilesAttributes()
Add the Files Attributes section in JSON format to m_JSONbuffer.
void addJSONGeneralSpecs()
Add the General Specs in JSON format to m_JSONbuffer.
void addJSONDesignRules()
Add the Design Rules section in JSON format to m_JSONbuffer.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
std::vector< FAB_LAYER_COLOR > dummy

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 168 of file gerber_jobfile_writer.h.

Referenced by GERBER_JOBFILE_WRITER(), and mapValue().

◆ m_json

nlohmann::ordered_json GERBER_JOBFILE_WRITER::m_json
private

◆ 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: