You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
13 KiB

  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. /**
  25. * @file gbr_metadata.cpp
  26. * @brief helper functions to handle the gerber metadata in files,
  27. * related to the netlist info and aperture attribute.
  28. */
  29. #include <fctsys.h>
  30. #include <gbr_metadata.h>
  31. std::string GBR_APERTURE_METADATA::FormatAttribute( GBR_APERTURE_ATTRIB aAttribute,
  32. bool aUseX1StructuredComment )
  33. {
  34. std::string attribute_string;
  35. // generate a string to print a Gerber Aperture attribute
  36. switch( aAttribute )
  37. {
  38. case GBR_APERTURE_ATTRIB_END: // Dummy value (aAttribute must be < GBR_APERTURE_ATTRIB_END)
  39. case GBR_APERTURE_ATTRIB_NONE: // idle command: do nothing
  40. break;
  41. case GBR_APERTURE_ATTRIB_ETCHEDCMP: // print info associated to an item
  42. // which connects 2 different nets
  43. // (Net tees, microwave component)
  44. attribute_string = "TA.AperFunction,EtchedComponent";
  45. break;
  46. case GBR_APERTURE_ATTRIB_CONDUCTOR: // print info associated to a track
  47. attribute_string = "TA.AperFunction,Conductor";
  48. break;
  49. case GBR_APERTURE_ATTRIB_CUTOUT: // print info associated to a outline
  50. attribute_string = "TA.AperFunction,CutOut";
  51. break;
  52. case GBR_APERTURE_ATTRIB_VIAPAD: // print info associated to a flashed via
  53. attribute_string = "TA.AperFunction,ViaPad";
  54. break;
  55. case GBR_APERTURE_ATTRIB_NONCONDUCTOR: // print info associated to a item on a copper layer
  56. // which is not a track (for instance a text)
  57. attribute_string = "TA.AperFunction,NonConductor";
  58. break;
  59. case GBR_APERTURE_ATTRIB_COMPONENTPAD: // print info associated to a flashed
  60. // through hole component on outer layer
  61. attribute_string = "TA.AperFunction,ComponentPad";
  62. break;
  63. case GBR_APERTURE_ATTRIB_SMDPAD_SMDEF: // print info associated to a flashed for SMD pad.
  64. // with solder mask defined from the copper shape
  65. // Excluded BGA pads which have their own type
  66. attribute_string = "TA.AperFunction,SMDPad,SMDef";
  67. break;
  68. case GBR_APERTURE_ATTRIB_SMDPAD_CUDEF: // print info associated to a flashed SMD pad with
  69. // a solder mask defined by the solder mask
  70. attribute_string = "TA.AperFunction,SMDPad,CuDef";
  71. break;
  72. case GBR_APERTURE_ATTRIB_BGAPAD_SMDEF: // print info associated to flashed BGA pads with
  73. // a solder mask defined by the copper shape
  74. attribute_string = "TA.AperFunction,BGAPad,SMDef";
  75. break;
  76. case GBR_APERTURE_ATTRIB_BGAPAD_CUDEF: // print info associated to a flashed BGA pad with
  77. // a solder mask defined by the solder mask
  78. attribute_string = "TA.AperFunction,BGAPad,CuDef";
  79. break;
  80. case GBR_APERTURE_ATTRIB_CONNECTORPAD: // print info associated to a flashed edge connector pad (outer layers)
  81. attribute_string = "TA.AperFunction,ConnectorPad";
  82. break;
  83. case GBR_APERTURE_ATTRIB_WASHERPAD: // print info associated to flashed mechanical pads (NPTH)
  84. attribute_string = "TA.AperFunction,WasherPad";
  85. break;
  86. case GBR_APERTURE_ATTRIB_HEATSINKPAD: // print info associated to a flashed heat sink pad
  87. // (typically for SMDs)
  88. attribute_string = "TA.AperFunction,HeatsinkPad";
  89. break;
  90. case GBR_APERTURE_ATTRIB_VIADRILL: // print info associated to a via hole in drill files
  91. attribute_string = "TA.AperFunction,ViaDrill";
  92. break;
  93. case GBR_APERTURE_ATTRIB_COMPONENTDRILL: // print info associated to a component
  94. // round hole in drill files
  95. attribute_string = "TA.AperFunction,ComponentDrill";
  96. break;
  97. case GBR_APERTURE_ATTRIB_SLOTDRILL: // print info associated to a oblong hole in drill files
  98. attribute_string = "TA.AperFunction,Slot";
  99. break;
  100. }
  101. std::string full_attribute_string;
  102. wxString eol_string;
  103. if( !attribute_string.empty() )
  104. {
  105. if( aUseX1StructuredComment )
  106. {
  107. full_attribute_string = "G04 #@! ";
  108. eol_string = "*\n";
  109. }
  110. else
  111. {
  112. full_attribute_string = "%";
  113. eol_string = "*%\n";
  114. }
  115. }
  116. full_attribute_string += attribute_string + eol_string;
  117. return full_attribute_string;
  118. }
  119. wxString FormatStringFromGerber( const wxString& aString )
  120. {
  121. // make the inverse conversion of formatStringToGerber()
  122. // It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode
  123. // and return a wxString (unicode 16) from the gerber string
  124. wxString txt;
  125. for( unsigned ii = 0; ii < aString.Length(); ++ii )
  126. {
  127. unsigned code = aString[ii];
  128. if( code == '\\' )
  129. {
  130. // Convert 4 hexadecimal digits to a 16 bit unicode
  131. // (Gerber allows only 4 hexadecimal digits)
  132. long value = 0;
  133. for( int jj = 0; jj < 4; jj++ )
  134. {
  135. value <<= 4;
  136. code = aString[++ii];
  137. // Very basic conversion, but it expects a valid gerber file
  138. int hexa = (code <= '9' ? code - '0' : code - 'A' + 10) & 0xF;
  139. value += hexa;
  140. }
  141. txt.Append( wxChar( value ) );
  142. }
  143. else
  144. txt.Append( aString[ii] );
  145. }
  146. return txt;
  147. }
  148. std::string formatStringToGerber( const wxString& aString )
  149. {
  150. /* format string means convert any code > 0x7F and unautorized code to a hexadecimal
  151. * 16 bits sequence unicode
  152. * unautorized codes are ',' '*' '%' '\'
  153. */
  154. std::string txt;
  155. txt.reserve( aString.Length() );
  156. for( unsigned ii = 0; ii < aString.Length(); ++ii )
  157. {
  158. unsigned code = aString[ii];
  159. bool convert = false;
  160. switch( code )
  161. {
  162. case '\\':
  163. case '%':
  164. case '*':
  165. case ',':
  166. convert = true;
  167. break;
  168. default:
  169. break;
  170. }
  171. if( convert || code > 0x7F )
  172. {
  173. txt += '\\';
  174. // Convert code to 4 hexadecimal digit
  175. // (Gerber allows only 4 hexadecimal digit)
  176. char hexa[32];
  177. sprintf( hexa,"%4.4X", code & 0xFFFF);
  178. txt += hexa;
  179. }
  180. else
  181. txt += char( code );
  182. }
  183. return txt;
  184. }
  185. // Netname and Pan num fields cannot be empty in Gerber files
  186. // Normalized names must be used, if any
  187. #define NO_NET_NAME wxT( "N/C" ) // net name of not connected pads (one pad net) (normalized)
  188. #define NO_PAD_NAME wxT( "" ) // pad name of pads without pad name/number (not normalized)
  189. bool FormatNetAttribute( std::string& aPrintedText, std::string& aLastNetAttributes,
  190. GBR_NETLIST_METADATA* aData, bool& aClearPreviousAttributes,
  191. bool aUseX1StructuredComment )
  192. {
  193. aClearPreviousAttributes = false;
  194. wxString prepend_string;
  195. wxString eol_string;
  196. if( aUseX1StructuredComment )
  197. {
  198. prepend_string = "G04 #@! ";
  199. eol_string = "*\n";
  200. }
  201. else
  202. {
  203. prepend_string = "%";
  204. eol_string = "*%\n";
  205. }
  206. // print a Gerber net attribute record.
  207. // it is added to the object attributes dictionnary
  208. // On file, only modified or new attributes are printed.
  209. if( aData == NULL )
  210. return false;
  211. std::string pad_attribute_string;
  212. std::string net_attribute_string;
  213. std::string cmp_attribute_string;
  214. if( aData->m_NetAttribType == GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED )
  215. return false; // idle command: do nothing
  216. if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) )
  217. {
  218. // print info associated to a flashed pad (cmpref, pad name)
  219. // example: %TO.P,R5,3*%
  220. pad_attribute_string = prepend_string + "TO.P,";
  221. pad_attribute_string += formatStringToGerber( aData->m_Cmpref ) + ",";
  222. if( aData->m_Padname.IsEmpty() )
  223. // Happens for "mechanical" or never connected pads
  224. pad_attribute_string += formatStringToGerber( NO_PAD_NAME );
  225. else
  226. pad_attribute_string += formatStringToGerber( aData->m_Padname );
  227. pad_attribute_string += eol_string;
  228. }
  229. if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_NET ) )
  230. {
  231. // print info associated to a net
  232. // example: %TO.N,Clk3*%
  233. net_attribute_string = prepend_string + "TO.N,";
  234. if( aData->m_Netname.IsEmpty() )
  235. {
  236. if( aData->m_NotInNet )
  237. {
  238. // Happens for not connectable pads: mechanical pads
  239. // and pads with no padname/num
  240. // In this case the net name must be left empty
  241. }
  242. else
  243. {
  244. // Happens for not connected pads: use a normalized
  245. // dummy name
  246. net_attribute_string += formatStringToGerber( NO_NET_NAME );
  247. }
  248. }
  249. else
  250. net_attribute_string += formatStringToGerber( aData->m_Netname );
  251. net_attribute_string += eol_string;
  252. }
  253. if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) &&
  254. !( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) )
  255. {
  256. // print info associated to a footprint
  257. // example: %TO.C,R2*%
  258. // Because GBR_NETINFO_PAD option already contains this info, it is not
  259. // created here for a GBR_NETINFO_PAD attribute
  260. cmp_attribute_string = prepend_string + "TO.C,";
  261. cmp_attribute_string += formatStringToGerber( aData->m_Cmpref ) + eol_string;
  262. }
  263. // the full list of requested attributes:
  264. std::string full_attribute_string = pad_attribute_string + net_attribute_string
  265. + cmp_attribute_string;
  266. // the short list of requested attributes
  267. // (only modified or new attributes are stored here):
  268. std::string short_attribute_string;
  269. if( aLastNetAttributes != full_attribute_string )
  270. {
  271. // first, remove no more existing attributes.
  272. // Because in Kicad the full attribute list is evaluated for each object,
  273. // the entire dictionnary is cleared
  274. bool clearDict = false;
  275. if( aLastNetAttributes.find( "TO.P," ) != std::string::npos )
  276. {
  277. if( pad_attribute_string.empty() ) // No more this attribute
  278. clearDict = true;
  279. else if( aLastNetAttributes.find( pad_attribute_string )
  280. == std::string::npos ) // This attribute has changed
  281. short_attribute_string += pad_attribute_string;
  282. }
  283. else // New attribute
  284. short_attribute_string += pad_attribute_string;
  285. if( aLastNetAttributes.find( "TO.N," ) != std::string::npos )
  286. {
  287. if( net_attribute_string.empty() ) // No more this attribute
  288. clearDict = true;
  289. else if( aLastNetAttributes.find( net_attribute_string )
  290. == std::string::npos ) // This attribute has changed
  291. short_attribute_string += net_attribute_string;
  292. }
  293. else // New attribute
  294. short_attribute_string += net_attribute_string;
  295. if( aLastNetAttributes.find( "TO.C," ) != std::string::npos )
  296. {
  297. if( cmp_attribute_string.empty() ) // No more this attribute
  298. clearDict = true;
  299. else if( aLastNetAttributes.find( cmp_attribute_string )
  300. == std::string::npos ) // This attribute has changed
  301. short_attribute_string += cmp_attribute_string;
  302. }
  303. else // New attribute
  304. short_attribute_string += cmp_attribute_string;
  305. aClearPreviousAttributes = clearDict;
  306. aLastNetAttributes = full_attribute_string;
  307. if( clearDict )
  308. aPrintedText = full_attribute_string;
  309. else
  310. aPrintedText = short_attribute_string;
  311. }
  312. return true;
  313. }