KiCad PCB EDA Suite
gerber_jobfile_writer.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) 2018 Jean_Pierre Charras <jp.charras at wanadoo.fr>
5 * Copyright (C) 1992-2022 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 <fstream>
31#include <iomanip>
32#include <vector>
33
34#include <build_version.h>
35#include <locale_io.h>
36#include <pcb_edit_frame.h>
37#include <plotters/plotter.h>
38
39#include <board.h>
41#include <footprint.h>
42#include <pad.h>
43#include <pcb_track.h>
44#include <zone.h>
45
47#include <gbr_metadata.h>
49#include <pcbplot.h>
50#include <reporter.h>
52
53
55{
56 m_pcb = aPcb;
57 m_reporter = aReporter;
58 m_conversionUnits = 1.0 / pcbIUScale.IU_PER_MM; // Gerber units = mm
59}
60
61std::string GERBER_JOBFILE_WRITER::formatStringFromUTF32( const wxString& aText )
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}
78
79
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}
95
96
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}
112
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}
140
141
142bool GERBER_JOBFILE_WRITER::CreateJobFile( const wxString& aFullFilename )
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}
165
166
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}
185
186
187bool GERBER_JOBFILE_WRITER::WriteJSONJobFile( const wxString& aFullFilename )
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}
215
216
217double GERBER_JOBFILE_WRITER::mapValue( double aUiValue )
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}
232
233
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}
334
335
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}
461
462
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}
577
578
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
const char * name
Definition: DXF_plotter.cpp:56
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_EDGE_CONNECTOR_BEVELLED
Definition: board_stackup.h:57
@ 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
wxString GetBuildVersion()
Get the full KiCad version string.
std::shared_ptr< NET_SETTINGS > m_NetSettings
int GetBoardThickness() const
The full thickness of the board including copper and masks.
BOARD_STACKUP & GetStackupDescriptor()
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
Manage layers needed to make a physical board.
bool m_CastellatedPads
True if castellated pads exist.
int GetCount() 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_ITEM * GetStackupLayer(int aIndex)
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.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:265
const BOX2I GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition: board.h:823
ZONES & Zones()
Definition: board.h:313
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:632
FOOTPRINTS & Footprints()
Definition: board.h:307
int GetCopperLayerCount() const
Definition: board.cpp:541
TRACKS & Tracks()
Definition: board.h:304
const wxString & GetFileName() const
Definition: board.h:302
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:452
PROJECT * GetProject() const
Definition: board.h:440
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:682
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
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.
nlohmann::ordered_json m_json
bool CreateJobFile(const wxString &aFullFilename)
Creates a Gerber job file.
void addJSONGeneralSpecs()
Add the General Specs in JSON format to m_JSONbuffer.
bool WriteJSONJobFile(const wxString &aFullFilename)
Creates an Gerber job file in JSON format.
double mapValue(double aUiValue)
A helper function to convert a double in Pcbnew internal units to a JSON double value (in mm),...
const char * sideKeyValue(enum ONSIDE aValue)
void addJSONDesignRules()
Add the Design Rules section in JSON format to m_JSONbuffer.
std::string formatStringFromUTF32(const wxString &aText)
A helper function to convert a wxString ( therefore a Unicode text ) to a JSON compatible string (a e...
GERBER_JOBFILE_WRITER(BOARD *aPcb, REPORTER *aReporter=nullptr)
wxArrayString m_GerberFileList
std::vector< PCB_LAYER_ID > m_LayerId
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:530
Definition: pad.h:59
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
const wxString & GetRevision() const
Definition: title_block.h:86
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:58
#define _(s)
wxString GbrMakeProjectGUIDfromString(const wxString &aText)
Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad proje...
wxString GbrMakeCreationDateAttributeString(GBR_NC_STRING_FORMAT aFormat)
Handle special data (items attributes) during plot.
@ GBR_NC_STRING_FORMAT_GBRJOB
Definition: gbr_metadata.h:63
Classes used to generate a Gerber job file in JSON.
@ SIDE_BOTTOM
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ 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
@ B_Cu
Definition: layer_ids.h:95
@ 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
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:119
Plot settings, and plotting engines (PostScript, Gerber, HPGL and DXF)
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
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
const double IU_PER_MM
Definition: base_units.h:77
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
Definition of file extensions used in Kicad.