KiCad PCB EDA Suite
gbr_metadata.h File Reference

Handle special data (items attributes) during plot. More...

Go to the source code of this file.

Classes

class  GBR_APERTURE_METADATA
 
class  GBR_METADATA
 Metadata which can be added in a gerber file as attribute in X2 format. More...
 

Enumerations

enum  GBR_NC_STRING_FORMAT { GBR_NC_STRING_FORMAT_X1 , GBR_NC_STRING_FORMAT_X2 , GBR_NC_STRING_FORMAT_GBRJOB , GBR_NC_STRING_FORMAT_NCDRILL }
 Create a gerber TF.CreationDate attribute. More...
 

Functions

wxString GbrMakeCreationDateAttributeString (GBR_NC_STRING_FORMAT aFormat)
 
wxString GbrMakeProjectGUIDfromString (const wxString &aText)
 Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad project has no specific GUID. More...
 
std::string FormatStringToGerber (const wxString &aString)
 Normalize aString and convert it to a Gerber std::string. More...
 
wxString ConvertNotAllowedCharsInGerber (const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
 Normalize aString and convert it to a Gerber compatible wxString. More...
 
wxString FormatStringFromGerber (const wxString &aString)
 Convert a gerber string into a 16 bit Unicode string. More...
 
bool FormatNetAttribute (std::string &aPrintedText, std::string &aLastNetAttributes, const GBR_NETLIST_METADATA *aData, bool &aClearPreviousAttributes, bool aUseX1StructuredComment)
 Generate the string to set a net attribute for a graphic object to print to a gerber file. More...
 

Detailed Description

Handle special data (items attributes) during plot.

Used in Gerber plotter to generate auxiliary data during plot (for instance info associated to apertures and flashed pads)

Definition in file gbr_metadata.h.

Enumeration Type Documentation

◆ GBR_NC_STRING_FORMAT

Create a gerber TF.CreationDate attribute.

The attribute value must conform to the full version of the ISO 8601 date and time format, including time and time zone.

Example of structured comment (compatible X1 gerber) G04 #@! TF.CreationDate,2018-11-21T08:49:16+01:00* (example of X1 attribute)

Example NC drill files ; #@! TF.CreationDate,2018-11-21T08:49:16+01:00* (example of NC drill comment)

Example of X2 attribute: TF.CreationDate,2018-11-06T08:25:24+01:00*%

Note
This is the date the Gerber file is effectively created, not the time the project PCB was started.
Parameters
aFormatstring compatibility: X1, X2, GBRJOB or NC drill syntax.
Enumerator
GBR_NC_STRING_FORMAT_X1 
GBR_NC_STRING_FORMAT_X2 
GBR_NC_STRING_FORMAT_GBRJOB 
GBR_NC_STRING_FORMAT_NCDRILL 

Definition at line 59 of file gbr_metadata.h.

60{
65};
@ GBR_NC_STRING_FORMAT_X1
Definition: gbr_metadata.h:61
@ GBR_NC_STRING_FORMAT_NCDRILL
Definition: gbr_metadata.h:64
@ GBR_NC_STRING_FORMAT_X2
Definition: gbr_metadata.h:62
@ GBR_NC_STRING_FORMAT_GBRJOB
Definition: gbr_metadata.h:63

Function Documentation

◆ ConvertNotAllowedCharsInGerber()

wxString ConvertNotAllowedCharsInGerber ( const wxString &  aString,
bool  aAllowUtf8Chars,
bool  aQuoteString 
)

Normalize aString and convert it to a Gerber compatible wxString.

Normalization means convert to a hexadecimal 16 bit sequence Unicode and on request convert any code > 0x7F. Illegal characters are ',' '*' '' '\'.

Parameters
aStringthe string to convert.
aAllowUtf8Charsfalse to convert non ASCII7 values to Unicode sequence.
aQuoteStringtrue to double quote the returned string.
Returns
a without illegal chars (and converted non ASCII7 chars on request)

Definition at line 435 of file gbr_metadata.cpp.

437{
438 /* format string means convert any code > 0x7E and unauthorized codes to a hexadecimal
439 * 16 bits sequence Unicode
440 * However if aAllowUtf8Chars is true only unauthorized codes will be escaped, because some
441 * Gerber files accept UTF8 chars.
442 * unauthorized codes are ',' '*' '%' '\' '"' and are used as separators in Gerber files
443 */
444 wxString txt;
445
446 if( aQuoteString )
447 txt << "\"";
448
449 for( unsigned ii = 0; ii < aString.Length(); ++ii )
450 {
451 wxChar code = aString[ii];
452 bool convert = false;
453
454 switch( code )
455 {
456 case '\\':
457 case '%':
458 case '*':
459 case ',':
460 convert = true;
461 break;
462
463 case '"':
464 if( aQuoteString )
465 convert = true;
466 break;
467
468 default:
469 break;
470 }
471
472 if( !aAllowUtf8Chars && code > 0x7F )
473 convert = true;
474
475 if( convert )
476 {
477 // Convert code to 4 hexadecimal digit
478 // (Gerber allows only 4 hexadecimal digit) in escape seq:
479 // "\uXXXX", XXXX is the Unicode 16 bits hexa value
480 char hexa[32];
481 sprintf( hexa,"\\u%4.4X", code & 0xFFFF);
482 txt += hexa;
483 }
484 else
485 {
486 txt += code;
487 }
488 }
489
490 if( aQuoteString )
491 txt << "\"";
492
493 return txt;
494}

References convert.

Referenced by PLACEFILE_GERBER_WRITER::CreatePlaceFile(), FormatStringToGerber(), and GBR_DATA_FIELD::GetGerberString().

◆ FormatNetAttribute()

bool FormatNetAttribute ( std::string &  aPrintedText,
std::string &  aLastNetAttributes,
const GBR_NETLIST_METADATA aData,
bool &  aClearPreviousAttributes,
bool  aUseX1StructuredComment 
)

Generate the string to set a net attribute for a graphic object to print to a gerber file.

Parameters
aPrintedTextis the string to print.
aLastNetAttributesis the current full set of attributes.
aDatais the GBR_NETLIST_METADATA associated to the graphic object (can be NULL if no associated metadata, and aClearPreviousAttributes will be set to false)
aClearPreviousAttributesreturns true if the full set of attributes must be deleted from file before adding new attribute (happens when a previous attribute no longer exists).
aUseX1StructuredCommentfalse in X2 mode and true in X1 mode to add the net attribute in compatible X1 structured comment (i.e. prefixed by "G04 #@! ")
Returns
false if nothing can be done (GBR_NETLIST_METADATA has GBR_APERTURE_ATTRIB_NONE, and true if OK. If the new attribute(s) is the same as current attribute(s), aPrintedText will be empty.

Definition at line 542 of file gbr_metadata.cpp.

545{
546 aClearPreviousAttributes = false;
547 wxString prepend_string;
548 wxString eol_string;
549
550 if( aUseX1StructuredComment )
551 {
552 prepend_string = "G04 #@! ";
553 eol_string = "*\n";
554 }
555 else
556 {
557 prepend_string = "%";
558 eol_string = "*%\n";
559 }
560
561 // print a Gerber net attribute record.
562 // it is added to the object attributes dictionary
563 // On file, only modified or new attributes are printed.
564 if( aData == nullptr )
565 return false;
566
567 std::string pad_attribute_string;
568 std::string net_attribute_string;
569 std::string cmp_attribute_string;
570
572 return false; // idle command: do nothing
573
575 {
576 // print info associated to a flashed pad (cmpref, pad name, and optionally pin function)
577 // example1: %TO.P,R5,3*%
578 // example2: %TO.P,R5,3,reset*%
579 pad_attribute_string = prepend_string + "TO.P,";
580 pad_attribute_string += FormatStringToGerber( aData->m_Cmpref ) + ",";
581
582 if( aData->m_Padname.IsEmpty() )
583 {
584 // Happens for "mechanical" or never connected pads
585 pad_attribute_string += FormatStringToGerber( NO_PAD_NAME );
586 }
587 else
588 {
589 pad_attribute_string += aData->m_Padname.GetGerberString();
590
591 // In Pcbnew, the pin function comes from the schematic.
592 // so it exists only for named pads
593 if( !aData->m_PadPinFunction.IsEmpty() )
594 {
595 pad_attribute_string += ',';
596 pad_attribute_string += aData->m_PadPinFunction.GetGerberString();
597 }
598 }
599
600 pad_attribute_string += eol_string;
601 }
602
604 {
605 // print info associated to a net
606 // example: %TO.N,Clk3*%
607 net_attribute_string = prepend_string + "TO.N,";
608
609 if( aData->m_Netname.IsEmpty() )
610 {
611 if( aData->m_NotInNet )
612 {
613 // Happens for not connectable pads: mechanical pads
614 // and pads with no padname/num
615 // In this case the net name must be left empty
616 }
617 else
618 {
619 // Happens for not connected pads: use a normalized
620 // dummy name
621 net_attribute_string += FormatStringToGerber( NO_NET_NAME );
622 }
623 }
624 else
625 {
626 net_attribute_string += FormatStringToGerber( aData->m_Netname );
627 }
628
629 net_attribute_string += eol_string;
630 }
631
634 {
635 // print info associated to a footprint
636 // example: %TO.C,R2*%
637 // Because GBR_NETINFO_PAD option already contains this info, it is not
638 // created here for a GBR_NETINFO_PAD attribute
639 cmp_attribute_string = prepend_string + "TO.C,";
640 cmp_attribute_string += FormatStringToGerber( aData->m_Cmpref ) + eol_string;
641 }
642
643 // the full list of requested attributes:
644 std::string full_attribute_string = pad_attribute_string + net_attribute_string
645 + cmp_attribute_string;
646 // the short list of requested attributes
647 // (only modified or new attributes are stored here):
648 std::string short_attribute_string;
649
650 // Attributes have changed: update attribute string, and see if the previous attribute
651 // list (dictionary in Gerber language) must be cleared
652 if( aLastNetAttributes != full_attribute_string )
653 {
654 // first, remove no longer existing attributes.
655 // Because in KiCad the full attribute list is evaluated for each object,
656 // the entire dictionary is cleared
657 // If m_TryKeepPreviousAttributes is true, only the no longer existing attribute
658 // is cleared.
659 // Note: to avoid interaction between clear attributes and set attributes
660 // the clear attribute is inserted first.
661 bool clearDict = false;
662
663 if( aLastNetAttributes.find( "TO.P," ) != std::string::npos )
664 {
665 if( pad_attribute_string.empty() ) // No more this attribute
666 {
667 if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
668 short_attribute_string.insert( 0, prepend_string + "TO.P" + eol_string );
669 else
670 clearDict = true;
671 }
672 else if( aLastNetAttributes.find( pad_attribute_string ) == std::string::npos )
673 {
674 // This attribute has changed
675 short_attribute_string += pad_attribute_string;
676 }
677 }
678 else // New attribute
679 {
680 short_attribute_string += pad_attribute_string;
681 }
682
683 if( aLastNetAttributes.find( "TO.N," ) != std::string::npos )
684 {
685 if( net_attribute_string.empty() ) // No more this attribute
686 {
687 if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
688 short_attribute_string.insert( 0, prepend_string + "TO.N" + eol_string );
689 else
690 clearDict = true;
691 }
692 else if( aLastNetAttributes.find( net_attribute_string ) == std::string::npos )
693 {
694 // This attribute has changed.
695 short_attribute_string += net_attribute_string;
696 }
697 }
698 else // New attribute
699 {
700 short_attribute_string += net_attribute_string;
701 }
702
703 if( aLastNetAttributes.find( "TO.C," ) != std::string::npos )
704 {
705 if( cmp_attribute_string.empty() ) // No more this attribute
706 {
707 if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
708 {
709 // Refinement:
710 // the attribute will be cleared only if there is no pad attribute.
711 // If a pad attribute exists, the component name exists so the old
712 // TO.C value will be updated, therefore no need to clear it before updating
713 if( pad_attribute_string.empty() )
714 short_attribute_string.insert( 0, prepend_string + "TO.C" + eol_string );
715 }
716 else
717 {
718 clearDict = true;
719 }
720 }
721 else if( aLastNetAttributes.find( cmp_attribute_string ) == std::string::npos )
722 {
723 // This attribute has changed.
724 short_attribute_string += cmp_attribute_string;
725 }
726 }
727 else // New attribute
728 {
729 short_attribute_string += cmp_attribute_string;
730 }
731
732 aClearPreviousAttributes = clearDict;
733
734 aLastNetAttributes = full_attribute_string;
735
736 if( clearDict )
737 aPrintedText = full_attribute_string;
738 else
739 aPrintedText = short_attribute_string;
740 }
741
742 return true;
743}
std::string GetGerberString() const
int m_NetAttribType
the type of net info (used to define the gerber string to create)
wxString m_Cmpref
the component reference parent of the data
@ GBR_NETINFO_NET
print info associated to a net (TO.N attribute)
@ GBR_NETINFO_UNSPECIFIED
idle command (no command)
@ GBR_NETINFO_CMP
print info associated to a component (TO.C attribute)
@ GBR_NETINFO_PAD
print info associated to a flashed pad (TO.P attribute)
GBR_DATA_FIELD m_PadPinFunction
for a pad: the pin function (defined in schematic)
bool m_TryKeepPreviousAttributes
If true, do not clear all attributes when a attribute has changed.
bool m_NotInNet
true if a pad of a footprint cannot be connected (for instance a mechanical NPTH, ot a not named pad)...
GBR_DATA_FIELD m_Padname
for a flashed pad: the pad name ((TO.P attribute)
wxString m_Netname
for items associated to a net: the netname
#define NO_NET_NAME
#define NO_PAD_NAME
std::string FormatStringToGerber(const wxString &aString)
Normalize aString and convert it to a Gerber std::string.

References FormatStringToGerber(), GBR_NETLIST_METADATA::GBR_NETINFO_CMP, GBR_NETLIST_METADATA::GBR_NETINFO_NET, GBR_NETLIST_METADATA::GBR_NETINFO_PAD, GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED, GBR_DATA_FIELD::GetGerberString(), GBR_DATA_FIELD::IsEmpty(), GBR_NETLIST_METADATA::m_Cmpref, GBR_NETLIST_METADATA::m_NetAttribType, GBR_NETLIST_METADATA::m_Netname, GBR_NETLIST_METADATA::m_NotInNet, GBR_NETLIST_METADATA::m_Padname, GBR_NETLIST_METADATA::m_PadPinFunction, GBR_NETLIST_METADATA::m_TryKeepPreviousAttributes, NO_NET_NAME, and NO_PAD_NAME.

Referenced by GERBER_PLOTTER::formatNetAttribute().

◆ FormatStringFromGerber()

wxString FormatStringFromGerber ( const wxString &  aString)

Convert a gerber string into a 16 bit Unicode string.

Parameters
aStringthe gerber string to format.
Returns
a 16 bit Unicode string.

Definition at line 369 of file gbr_metadata.cpp.

370{
371 // make the inverse conversion of FormatStringToGerber()
372 // It converts a "normalized" gerber string containing escape sequences
373 // and convert it to a 16 bits Unicode char
374 // and return a wxString (Unicode 16) from the gerber string
375 // Note the initial gerber string can already contain Unicode chars.
376 wxString txt; // The string converted from Gerber string
377
378 unsigned count = aString.Length();
379
380 for( unsigned ii = 0; ii < count; ++ii )
381 {
382 unsigned code = aString[ii];
383
384 if( code == '\\' && ii < count-5 && aString[ii+1] == 'u' )
385 {
386 // Note the latest Gerber X2 spec (2019 06) uses \uXXXX to encode
387 // the Unicode XXXX hexadecimal value
388 // If 4 chars next to 'u' are hexadecimal chars,
389 // Convert these 4 hexadecimal digits to a 16 bit Unicode
390 // (Gerber allows only 4 hexadecimal digits)
391 // If an error occurs, the escape sequence is not translated,
392 // and used "as this"
393 long value = 0;
394 bool error = false;
395
396 for( int jj = 0; jj < 4; jj++ )
397 {
398 value <<= 4;
399 code = aString[ii+jj+2];
400
401 int hexa = char2Hex( code );
402
403 if( hexa >= 0 )
404 value += hexa;
405 else
406 {
407 error = true;
408 break;
409 }
410 }
411
412 if( !error )
413 {
414 if( value >= ' ' ) // Is a valid wxChar ?
415 txt.Append( wxChar( value ) );
416
417 ii += 5;
418 }
419 else
420 {
421 txt.Append( aString[ii] );
422 continue;
423 }
424 }
425 else
426 {
427 txt.Append( aString[ii] );
428 }
429 }
430
431 return txt;
432}
int char2Hex(unsigned aCode)

References char2Hex().

Referenced by GERBER_FILE_IMAGE::ExecuteRS274XCommand().

◆ FormatStringToGerber()

std::string FormatStringToGerber ( const wxString &  aString)

Normalize aString and convert it to a Gerber std::string.

Normalization means convert any code > 0x7F and unauthorized code to a hexadecimal 16 bit sequence Unicode. Illegal characters are ',' '*' '' '\'.

Parameters
aStringthe string to convert.
Returns
an ASCII7 coded compliant gerber string.

Definition at line 512 of file gbr_metadata.cpp.

513{
514 wxString converted;
515
516 /* format string means convert any code > 0x7E and unauthorized codes to a hexadecimal
517 * 16 bits sequence Unicode
518 * unauthorized codes are ',' '*' '%' '\'
519 * This conversion is not made for quoted strings, because if the string is
520 * quoted, the conversion is expected to be already made, and the returned string must use
521 * UTF8 encoding
522 */
523 if( !aString.IsEmpty() && ( aString[0] != '\"' || aString[aString.Len()-1] != '\"' ) )
524 converted = ConvertNotAllowedCharsInGerber( aString, false, false );
525 else
526 converted = aString;
527
528 // Convert the char string to std::string. Be careful when converting a wxString to
529 // a std::string: using static_cast<const char*> is mandatory
530 std::string txt = static_cast<const char*>( converted.utf8_str() );
531
532 return txt;
533}
wxString ConvertNotAllowedCharsInGerber(const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
Normalize aString and convert it to a Gerber compatible wxString.

References ConvertNotAllowedCharsInGerber().

Referenced by FormatNetAttribute().

◆ GbrMakeCreationDateAttributeString()

wxString GbrMakeCreationDateAttributeString ( GBR_NC_STRING_FORMAT  aFormat)

Definition at line 37 of file gbr_metadata.cpp.

38{
39 // creates the CreationDate attribute:
40 // The attribute value must conform to the full version of the ISO 8601
41 // date and time format, including time and time zone. Note that this is
42 // the date the Gerber file was effectively created,
43 // not the time the project of PCB was started
44 wxDateTime date( wxDateTime::GetTimeNow() );
45
46 // Date format: see http://www.cplusplus.com/reference/ctime/strftime
47 wxString timezone_offset; // ISO 8601 offset from UTC in timezone
48 timezone_offset = date.Format( "%z" ); // Extract the time zone offset
49
50 // The time zone offset format is +mm or +hhmm (or -mm or -hhmm)
51 // (mm = number of minutes, hh = number of hours. 1h00mn is returned as +0100)
52 // we want +(or -) hh:mm
53 if( timezone_offset.Len() > 3 ) // format +hhmm or -hhmm found
54 // Add separator between hours and minutes
55 timezone_offset.insert( 3, ":", 1 );
56
57 wxString msg;
58
59 switch( aFormat )
60 {
62 msg.Printf( wxS( "%%TF.CreationDate,%s%s*%%" ), date.FormatISOCombined(), timezone_offset );
63 break;
64
66 msg.Printf( wxS( "G04 #@! TF.CreationDate,%s%s*" ), date.FormatISOCombined(), timezone_offset );
67 break;
68
70 msg.Printf( wxS( "%s%s" ), date.FormatISOCombined(), timezone_offset );
71 break;
72
74 msg.Printf( wxS( "; #@! TF.CreationDate,%s%s" ), date.FormatISOCombined(), timezone_offset );
75 break;
76 }
77 return msg;
78}

References GBR_NC_STRING_FORMAT_GBRJOB, GBR_NC_STRING_FORMAT_NCDRILL, GBR_NC_STRING_FORMAT_X1, and GBR_NC_STRING_FORMAT_X2.

Referenced by AddGerberX2Header(), GERBER_JOBFILE_WRITER::addJSONHeader(), and EXCELLON_WRITER::writeEXCELLONHeader().

◆ GbrMakeProjectGUIDfromString()

wxString GbrMakeProjectGUIDfromString ( const wxString &  aText)

Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad project has no specific GUID.

RFC4122 is used mainly for its syntax, because fields have no meaning for Gerber files and therefore the GUID generated has no meaning because it do not use any time and time stamp specific to the project, just a random pattern (random is here a pattern specific to a project).

See en.wikipedia.org/wiki/Universally_unique_identifier

Definition at line 81 of file gbr_metadata.cpp.

82{
83 /* Gerber GUID format should be RFC4122 Version 1 or 4.
84 * See en.wikipedia.org/wiki/Universally_unique_identifier
85 * The format is:
86 * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
87 * with
88 * x = hexDigit lower/upper case
89 * and
90 * M = '1' or '4' (UUID version: 1 (basic) or 4 (random)) (we use 4: UUID random)
91 * and
92 * N = '8' or '9' or 'A|a' or 'B|b' : UUID variant 1: 2 MSB bits have meaning) (we use N = 9)
93 * N = 1000 or 1001 or 1010 or 1011 : 10xx means Variant 1 (Variant2: 110x and 111x are
94 * reserved)
95 */
96
97 wxString guid;
98
99 // Build a 32 digits GUID from the board name:
100 // guid has 32 digits, so add chars in name to be sure we can build a 32 digits guid
101 // (i.e. from a 16 char string name)
102 // In fact only 30 digits are used, and 2 UID id
103 wxString bname = aText;
104 int cnt = 16 - bname.Len();
105
106 if( cnt > 0 )
107 bname.Append( 'X', cnt );
108
109 int chr_idx = 0;
110
111 // Output the 8 first hex digits:
112 for( unsigned ii = 0; ii < 4; ii++ )
113 {
114 int cc = int( bname[chr_idx++] ) & 0xFF;
115 guid << wxString::Format( "%2.2x", cc );
116 }
117
118 // Output the 4 next hex digits:
119 guid << '-';
120
121 for( unsigned ii = 0; ii < 2; ii++ )
122 {
123 int cc = int( bname[chr_idx++] ) & 0xFF;
124 guid << wxString::Format( "%2.2x", cc );
125 }
126
127 // Output the 4 next hex digits (UUID version and 3 digits):
128 guid << "-4"; // first digit: UUID version 4 (M = 4)
129 {
130 int cc = int( bname[chr_idx++] ) << 4 & 0xFF0;
131 cc += int( bname[chr_idx] ) >> 4 & 0x0F;
132 guid << wxString::Format( "%3.3x", cc );
133 }
134
135 // Output the 4 next hex digits (UUID variant and 3 digits):
136 guid << "-9"; // first digit: UUID variant 1 (N = 9)
137 {
138 int cc = (int( bname[chr_idx++] ) & 0x0F) << 8;
139 cc += int( bname[chr_idx++] ) & 0xFF;
140 guid << wxString::Format( "%3.3x", cc );
141 }
142
143 // Output the 12 last hex digits:
144 guid << '-';
145
146 for( unsigned ii = 0; ii < 6; ii++ )
147 {
148 int cc = int( bname[chr_idx++] ) & 0xFF;
149 guid << wxString::Format( "%2.2x", cc );
150 }
151
152 return guid;
153}
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

References Format().

Referenced by AddGerberX2Header(), and GERBER_JOBFILE_WRITER::addJSONGeneralSpecs().