KiCad PCB EDA Suite
gbr_metadata.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) 2018 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 
31 #include <fctsys.h>
32 #include <gbr_metadata.h>
33 
34 
35 wxString GbrMakeProjectGUIDfromString( wxString& aText )
36 {
37  /* Gerber GUID format should be RFC4122 Version 1 or 4.
38  * See en.wikipedia.org/wiki/Universally_unique_identifier
39  * The format is:
40  * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
41  * with
42  * x = hexDigit lower/upper case
43  * and
44  * M = '1' or '4' (UUID version: 1 (basic) or 4 (random)) (we use 4: UUID random)
45  * and
46  * N = '8' or '9' or 'A|a' or 'B|b' : UUID variant 1: 2 MSB bits have meaning) (we use N = 9)
47  * N = 1000 or 1001 or 1010 or 1011 : 10xx means Variant 1 (Variant2: 110x and 111x are reserved)
48  */
49 
50  wxString guid;
51 
52  // Build a 32 digits GUID from the board name:
53  // guid has 32 digits, so add chars in name to be sure we can build a 32 digits guid
54  // (i.e. from a 16 char string name)
55  // In fact only 30 digits are used, and 2 UID id
56  wxString bname = aText;
57  int cnt = 16 - bname.Len();
58 
59  if( cnt > 0 )
60  bname.Append( 'X', cnt );
61 
62  int chr_idx = 0;
63 
64  // Output the 8 first hex digits:
65  for( unsigned ii = 0; ii < 4; ii++ )
66  {
67  int cc = int( bname[chr_idx++] ) & 0xFF;
68  guid << wxString::Format( "%2.2x", cc );
69  }
70 
71  // Output the 4 next hex digits:
72  guid << '-';
73 
74  for( unsigned ii = 0; ii < 2; ii++ )
75  {
76  int cc = int( bname[chr_idx++] ) & 0xFF;
77  guid << wxString::Format( "%2.2x", cc );
78  }
79 
80  // Output the 4 next hex digits (UUID version and 3 digits):
81  guid << "-4"; // first digit: UUID version 4 (M = 4)
82  {
83  int cc = int( bname[chr_idx++] ) << 4 & 0xFF0;
84  cc += int( bname[chr_idx] ) >> 4 & 0x0F;
85  guid << wxString::Format( "%3.3x", cc );
86  }
87 
88  // Output the 4 next hex digits (UUID variant and 3 digits):
89  guid << "-9"; // first digit: UUID variant 1 (N = 9)
90  {
91  int cc = (int( bname[chr_idx++] ) & 0x0F) << 8;
92  cc += int( bname[chr_idx++] ) & 0xFF;
93  guid << wxString::Format( "%3.3x", cc );
94  }
95 
96  // Output the 12 last hex digits:
97  guid << '-';
98 
99  for( unsigned ii = 0; ii < 6; ii++ )
100  {
101  int cc = int( bname[chr_idx++] ) & 0xFF;
102  guid << wxString::Format( "%2.2x", cc );
103  }
104 
105  return guid;
106 }
107 
108 
110  bool aUseX1StructuredComment )
111 {
112  std::string attribute_string;
113 
114  // generate a string to print a Gerber Aperture attribute
115  switch( aAttribute )
116  {
117  case GBR_APERTURE_ATTRIB_END: // Dummy value (aAttribute must be < GBR_APERTURE_ATTRIB_END)
118  case GBR_APERTURE_ATTRIB_NONE: // idle command: do nothing
119  break;
120 
121  case GBR_APERTURE_ATTRIB_ETCHEDCMP: // print info associated to an item
122  // which connects 2 different nets
123  // (Net tees, microwave component)
124  attribute_string = "TA.AperFunction,EtchedComponent";
125  break;
126 
127  case GBR_APERTURE_ATTRIB_CONDUCTOR: // print info associated to a track
128  attribute_string = "TA.AperFunction,Conductor";
129  break;
130 
131  case GBR_APERTURE_ATTRIB_CUTOUT: // print info associated to a outline
132  attribute_string = "TA.AperFunction,CutOut";
133  break;
134 
135  case GBR_APERTURE_ATTRIB_VIAPAD: // print info associated to a flashed via
136  attribute_string = "TA.AperFunction,ViaPad";
137  break;
138 
139  case GBR_APERTURE_ATTRIB_NONCONDUCTOR: // print info associated to a item on a copper layer
140  // which is not a track (for instance a text)
141  attribute_string = "TA.AperFunction,NonConductor";
142  break;
143 
144  case GBR_APERTURE_ATTRIB_COMPONENTPAD: // print info associated to a flashed
145  // through hole component on outer layer
146  attribute_string = "TA.AperFunction,ComponentPad";
147  break;
148 
149  case GBR_APERTURE_ATTRIB_SMDPAD_SMDEF: // print info associated to a flashed for SMD pad.
150  // with solder mask defined from the copper shape
151  // Excluded BGA pads which have their own type
152  attribute_string = "TA.AperFunction,SMDPad,SMDef";
153  break;
154 
155  case GBR_APERTURE_ATTRIB_SMDPAD_CUDEF: // print info associated to a flashed SMD pad with
156  // a solder mask defined by the solder mask
157  attribute_string = "TA.AperFunction,SMDPad,CuDef";
158  break;
159 
160  case GBR_APERTURE_ATTRIB_BGAPAD_SMDEF: // print info associated to flashed BGA pads with
161  // a solder mask defined by the copper shape
162  attribute_string = "TA.AperFunction,BGAPad,SMDef";
163  break;
164 
165  case GBR_APERTURE_ATTRIB_BGAPAD_CUDEF: // print info associated to a flashed BGA pad with
166  // a solder mask defined by the solder mask
167  attribute_string = "TA.AperFunction,BGAPad,CuDef";
168  break;
169 
170  case GBR_APERTURE_ATTRIB_CONNECTORPAD: // print info associated to a flashed edge connector pad (outer layers)
171  attribute_string = "TA.AperFunction,ConnectorPad";
172  break;
173 
174  case GBR_APERTURE_ATTRIB_WASHERPAD: // print info associated to flashed mechanical pads (NPTH)
175  attribute_string = "TA.AperFunction,WasherPad";
176  break;
177 
178  case GBR_APERTURE_ATTRIB_HEATSINKPAD: // print info associated to a flashed heat sink pad
179  // (typically for SMDs)
180  attribute_string = "TA.AperFunction,HeatsinkPad";
181  break;
182 
183  case GBR_APERTURE_ATTRIB_VIADRILL: // print info associated to a via hole in drill files
184  attribute_string = "TA.AperFunction,ViaDrill";
185  break;
186 
187  case GBR_APERTURE_ATTRIB_COMPONENTDRILL: // print info associated to a component
188  // round hole in drill files
189  attribute_string = "TA.AperFunction,ComponentDrill";
190  break;
191 
192  case GBR_APERTURE_ATTRIB_SLOTDRILL: // print info associated to a oblong hole in drill files
193  attribute_string = "TA.AperFunction,Slot";
194  break;
195  }
196 
197  std::string full_attribute_string;
198  wxString eol_string;
199 
200  if( !attribute_string.empty() )
201  {
202  if( aUseX1StructuredComment )
203  {
204  full_attribute_string = "G04 #@! ";
205  eol_string = "*\n";
206  }
207  else
208  {
209  full_attribute_string = "%";
210  eol_string = "*%\n";
211  }
212  }
213 
214  full_attribute_string += attribute_string + eol_string;
215 
216  return full_attribute_string;
217 }
218 
219 wxString FormatStringFromGerber( const wxString& aString )
220 {
221  // make the inverse conversion of formatStringToGerber()
222  // It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode
223  // and return a wxString (unicode 16) from the gerber string
224  wxString txt;
225 
226  for( unsigned ii = 0; ii < aString.Length(); ++ii )
227  {
228  unsigned code = aString[ii];
229 
230  if( code == '\\' )
231  {
232  // Convert 4 hexadecimal digits to a 16 bit unicode
233  // (Gerber allows only 4 hexadecimal digits)
234  long value = 0;
235 
236  for( int jj = 0; jj < 4; jj++ )
237  {
238  value <<= 4;
239  code = aString[++ii];
240  // Very basic conversion, but it expects a valid gerber file
241  int hexa = (code <= '9' ? code - '0' : code - 'A' + 10) & 0xF;
242  value += hexa;
243  }
244 
245  txt.Append( wxChar( value ) );
246  }
247  else
248  txt.Append( aString[ii] );
249  }
250 
251  return txt;
252 }
253 
254 
255 std::string formatStringToGerber( const wxString& aString )
256 {
257  /* format string means convert any code > 0x7F and unautorized code to a hexadecimal
258  * 16 bits sequence unicode
259  * unautorized codes are ',' '*' '%' '\'
260  */
261  std::string txt;
262 
263  txt.reserve( aString.Length() );
264 
265  for( unsigned ii = 0; ii < aString.Length(); ++ii )
266  {
267  unsigned code = aString[ii];
268  bool convert = false;
269 
270  switch( code )
271  {
272  case '\\':
273  case '%':
274  case '*':
275  case ',':
276  convert = true;
277  break;
278 
279  default:
280  break;
281  }
282 
283  if( convert || code > 0x7F )
284  {
285  txt += '\\';
286 
287  // Convert code to 4 hexadecimal digit
288  // (Gerber allows only 4 hexadecimal digit)
289  char hexa[32];
290  sprintf( hexa,"%4.4X", code & 0xFFFF);
291  txt += hexa;
292  }
293  else
294  txt += char( code );
295  }
296 
297  return txt;
298 }
299 
300 // Netname and Pan num fields cannot be empty in Gerber files
301 // Normalized names must be used, if any
302 #define NO_NET_NAME wxT( "N/C" ) // net name of not connected pads (one pad net) (normalized)
303 #define NO_PAD_NAME wxT( "" ) // pad name of pads without pad name/number (not normalized)
304 
305 bool FormatNetAttribute( std::string& aPrintedText, std::string& aLastNetAttributes,
306  GBR_NETLIST_METADATA* aData, bool& aClearPreviousAttributes,
307  bool aUseX1StructuredComment )
308 {
309  aClearPreviousAttributes = false;
310  wxString prepend_string;
311  wxString eol_string;
312 
313  if( aUseX1StructuredComment )
314  {
315  prepend_string = "G04 #@! ";
316  eol_string = "*\n";
317  }
318  else
319  {
320  prepend_string = "%";
321  eol_string = "*%\n";
322  }
323 
324  // print a Gerber net attribute record.
325  // it is added to the object attributes dictionnary
326  // On file, only modified or new attributes are printed.
327  if( aData == NULL )
328  return false;
329 
330  std::string pad_attribute_string;
331  std::string net_attribute_string;
332  std::string cmp_attribute_string;
333 
335  return false; // idle command: do nothing
336 
338  {
339  // print info associated to a flashed pad (cmpref, pad name)
340  // example: %TO.P,R5,3*%
341  pad_attribute_string = prepend_string + "TO.P,";
342  pad_attribute_string += formatStringToGerber( aData->m_Cmpref ) + ",";
343 
344  if( aData->m_Padname.IsEmpty() )
345  // Happens for "mechanical" or never connected pads
346  pad_attribute_string += formatStringToGerber( NO_PAD_NAME );
347  else
348  pad_attribute_string += formatStringToGerber( aData->m_Padname );
349 
350  pad_attribute_string += eol_string;
351  }
352 
354  {
355  // print info associated to a net
356  // example: %TO.N,Clk3*%
357  net_attribute_string = prepend_string + "TO.N,";
358 
359  if( aData->m_Netname.IsEmpty() )
360  {
361  if( aData->m_NotInNet )
362  {
363  // Happens for not connectable pads: mechanical pads
364  // and pads with no padname/num
365  // In this case the net name must be left empty
366  }
367  else
368  {
369  // Happens for not connected pads: use a normalized
370  // dummy name
371  net_attribute_string += formatStringToGerber( NO_NET_NAME );
372  }
373  }
374  else
375  net_attribute_string += formatStringToGerber( aData->m_Netname );
376 
377  net_attribute_string += eol_string;
378  }
379 
382  {
383  // print info associated to a footprint
384  // example: %TO.C,R2*%
385  // Because GBR_NETINFO_PAD option already contains this info, it is not
386  // created here for a GBR_NETINFO_PAD attribute
387  cmp_attribute_string = prepend_string + "TO.C,";
388  cmp_attribute_string += formatStringToGerber( aData->m_Cmpref ) + eol_string;
389  }
390 
391  // the full list of requested attributes:
392  std::string full_attribute_string = pad_attribute_string + net_attribute_string
393  + cmp_attribute_string;
394  // the short list of requested attributes
395  // (only modified or new attributes are stored here):
396  std::string short_attribute_string;
397 
398  if( aLastNetAttributes != full_attribute_string )
399  {
400  // first, remove no more existing attributes.
401  // Because in Kicad the full attribute list is evaluated for each object,
402  // the entire dictionnary is cleared
403  bool clearDict = false;
404 
405  if( aLastNetAttributes.find( "TO.P," ) != std::string::npos )
406  {
407  if( pad_attribute_string.empty() ) // No more this attribute
408  clearDict = true;
409  else if( aLastNetAttributes.find( pad_attribute_string )
410  == std::string::npos ) // This attribute has changed
411  short_attribute_string += pad_attribute_string;
412  }
413  else // New attribute
414  short_attribute_string += pad_attribute_string;
415 
416  if( aLastNetAttributes.find( "TO.N," ) != std::string::npos )
417  {
418  if( net_attribute_string.empty() ) // No more this attribute
419  clearDict = true;
420  else if( aLastNetAttributes.find( net_attribute_string )
421  == std::string::npos ) // This attribute has changed
422  short_attribute_string += net_attribute_string;
423  }
424  else // New attribute
425  short_attribute_string += net_attribute_string;
426 
427  if( aLastNetAttributes.find( "TO.C," ) != std::string::npos )
428  {
429  if( cmp_attribute_string.empty() ) // No more this attribute
430  clearDict = true;
431  else if( aLastNetAttributes.find( cmp_attribute_string )
432  == std::string::npos ) // This attribute has changed
433  short_attribute_string += cmp_attribute_string;
434  }
435  else // New attribute
436  short_attribute_string += cmp_attribute_string;
437 
438  aClearPreviousAttributes = clearDict;
439 
440  aLastNetAttributes = full_attribute_string;
441 
442  if( clearDict )
443  aPrintedText = full_attribute_string;
444  else
445  aPrintedText = short_attribute_string;
446  }
447 
448  return true;
449 }
a class to handle special data (items attributes) during plot.
aperture used for etched components
Definition: gbr_metadata.h:60
#define NO_NET_NAME
aperture used for edge connecto pad (outer layers)
Definition: gbr_metadata.h:70
aperture used for heat sink pad (typically for SMDs)
Definition: gbr_metadata.h:72
print info associated to a component (TO.C attribute)
wxString m_Cmpref
the component reference parent of the data
aperture used for through hole component on outer layer
Definition: gbr_metadata.h:65
aperture used for via holes in drill files
Definition: gbr_metadata.h:73
bool FormatNetAttribute(std::string &aPrintedText, std::string &aLastNetAttributes, GBR_NETLIST_METADATA *aData, bool &aClearPreviousAttributes, bool aUseX1StructuredComment)
Generates the string to print to a gerber file, to set a net attribute for a graphic object...
this class handle info which can be added in a gerber file as attribute of an obtect the GBR_INFO_TYP...
std::string formatStringToGerber(const wxString &aString)
This helper function "normalize" aString and convert it to a Gerber std::string Normalisation means c...
aperture used for SMD pad. Excluded BGA pads which have their own type
Definition: gbr_metadata.h:66
aperture used for BGA pad with a solder mask defined by the solder mask
Definition: gbr_metadata.h:69
wxString m_Padname
for a flashed pad: the pad name ((TO.P attribute)
wxString GbrMakeProjectGUIDfromString(wxString &aText)
A helper function to build a project GUID using format RFC4122 Version 1 or 4 from the project name...
#define NO_PAD_NAME
aperture used for pad holes in drill files
Definition: gbr_metadata.h:74
wxString m_Netname
for items associated to a net: the netname
aperture used for mechanical pads (NPTH)
Definition: gbr_metadata.h:71
aperture used for BGA pads with a solder mask defined by the copper shape
Definition: gbr_metadata.h:68
aperture used for connected items like tracks (not vias)
Definition: gbr_metadata.h:61
static std::string FormatAttribute(GBR_APERTURE_ATTRIB aAttribute, bool aUseX1StructuredComment)
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
aperture used for SMD pad with a solder mask defined by the solder mask
Definition: gbr_metadata.h:67
print info associated to a flashed pad (TO.P attribute)
bool m_NotInNet
true if a pad of a footprint cannot be connected (for instance a mechanical NPTH, ot a not named pad)...
wxString FormatStringFromGerber(const wxString &aString)
This helper function make the inverse conversion of formatStringToGerber() It converts a "normalized"...
aperture used for not connected items (texts, outlines on copper)
Definition: gbr_metadata.h:63
print info associated to a net (TO.N attribute)
aperture used for oblong holes in drill files
Definition: gbr_metadata.h:75
int m_NetAttribType
the type of net info (used to define the gerber string to create)