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.

766 lines
28 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2019 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 <wx/string.h>
  30. #include <wx/datetime.h>
  31. #include <gbr_metadata.h>
  32. #include <utf8.h>
  33. wxString GbrMakeCreationDateAttributeString( GBR_NC_STRING_FORMAT aFormat )
  34. {
  35. // creates the CreationDate attribute:
  36. // The attribute value must conform to the full version of the ISO 8601
  37. // date and time format, including time and time zone. Note that this is
  38. // the date the Gerber file was effectively created,
  39. // not the time the project of PCB was started
  40. wxDateTime date( wxDateTime::GetTimeNow() );
  41. // Date format: see http://www.cplusplus.com/reference/ctime/strftime
  42. wxString timezone_offset; // ISO 8601 offset from UTC in timezone
  43. timezone_offset = date.Format( "%z" ); // Extract the time zone offset
  44. // The time zone offset format is +mm or +hhmm (or -mm or -hhmm)
  45. // (mm = number of minutes, hh = number of hours. 1h00mn is returned as +0100)
  46. // we want +(or -) hh:mm
  47. if( timezone_offset.Len() > 3 ) // format +hhmm or -hhmm found
  48. // Add separator between hours and minutes
  49. timezone_offset.insert( 3, ":", 1 );
  50. wxString msg;
  51. switch( aFormat )
  52. {
  53. case GBR_NC_STRING_FORMAT_X2:
  54. msg.Printf( "%%TF.CreationDate,%s%s*%%", date.FormatISOCombined(), timezone_offset );
  55. break;
  56. case GBR_NC_STRING_FORMAT_X1:
  57. msg.Printf( "G04 #@! TF.CreationDate,%s%s*", date.FormatISOCombined(), timezone_offset );
  58. break;
  59. case GBR_NC_STRING_FORMAT_GBRJOB:
  60. msg.Printf( "%s%s", date.FormatISOCombined(), timezone_offset );
  61. break;
  62. case GBR_NC_STRING_FORMAT_NCDRILL:
  63. msg.Printf( "; #@! TF.CreationDate,%s%s", date.FormatISOCombined(), timezone_offset );
  64. break;
  65. }
  66. return msg;
  67. }
  68. wxString GbrMakeProjectGUIDfromString( const wxString& aText )
  69. {
  70. /* Gerber GUID format should be RFC4122 Version 1 or 4.
  71. * See en.wikipedia.org/wiki/Universally_unique_identifier
  72. * The format is:
  73. * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
  74. * with
  75. * x = hexDigit lower/upper case
  76. * and
  77. * M = '1' or '4' (UUID version: 1 (basic) or 4 (random)) (we use 4: UUID random)
  78. * and
  79. * N = '8' or '9' or 'A|a' or 'B|b' : UUID variant 1: 2 MSB bits have meaning) (we use N = 9)
  80. * N = 1000 or 1001 or 1010 or 1011 : 10xx means Variant 1 (Variant2: 110x and 111x are reserved)
  81. */
  82. wxString guid;
  83. // Build a 32 digits GUID from the board name:
  84. // guid has 32 digits, so add chars in name to be sure we can build a 32 digits guid
  85. // (i.e. from a 16 char string name)
  86. // In fact only 30 digits are used, and 2 UID id
  87. wxString bname = aText;
  88. int cnt = 16 - bname.Len();
  89. if( cnt > 0 )
  90. bname.Append( 'X', cnt );
  91. int chr_idx = 0;
  92. // Output the 8 first hex digits:
  93. for( unsigned ii = 0; ii < 4; ii++ )
  94. {
  95. int cc = int( bname[chr_idx++] ) & 0xFF;
  96. guid << wxString::Format( "%2.2x", cc );
  97. }
  98. // Output the 4 next hex digits:
  99. guid << '-';
  100. for( unsigned ii = 0; ii < 2; ii++ )
  101. {
  102. int cc = int( bname[chr_idx++] ) & 0xFF;
  103. guid << wxString::Format( "%2.2x", cc );
  104. }
  105. // Output the 4 next hex digits (UUID version and 3 digits):
  106. guid << "-4"; // first digit: UUID version 4 (M = 4)
  107. {
  108. int cc = int( bname[chr_idx++] ) << 4 & 0xFF0;
  109. cc += int( bname[chr_idx] ) >> 4 & 0x0F;
  110. guid << wxString::Format( "%3.3x", cc );
  111. }
  112. // Output the 4 next hex digits (UUID variant and 3 digits):
  113. guid << "-9"; // first digit: UUID variant 1 (N = 9)
  114. {
  115. int cc = (int( bname[chr_idx++] ) & 0x0F) << 8;
  116. cc += int( bname[chr_idx++] ) & 0xFF;
  117. guid << wxString::Format( "%3.3x", cc );
  118. }
  119. // Output the 12 last hex digits:
  120. guid << '-';
  121. for( unsigned ii = 0; ii < 6; ii++ )
  122. {
  123. int cc = int( bname[chr_idx++] ) & 0xFF;
  124. guid << wxString::Format( "%2.2x", cc );
  125. }
  126. return guid;
  127. }
  128. std::string GBR_APERTURE_METADATA::FormatAttribute( GBR_APERTURE_ATTRIB aAttribute,
  129. bool aUseX1StructuredComment )
  130. {
  131. std::string attribute_string; // the specific aperture attribute (TA.xxx)
  132. std::string comment_string; // a optional G04 comment line to write before the TA. line
  133. // generate a string to print a Gerber Aperture attribute
  134. switch( aAttribute )
  135. {
  136. case GBR_APERTURE_ATTRIB_END: // Dummy value (aAttribute must be < GBR_APERTURE_ATTRIB_END)
  137. case GBR_APERTURE_ATTRIB_NONE: // idle command: do nothing
  138. break;
  139. case GBR_APERTURE_ATTRIB_ETCHEDCMP: // print info associated to an item
  140. // which connects 2 different nets
  141. // (Net tees, microwave component)
  142. attribute_string = "TA.AperFunction,EtchedComponent";
  143. break;
  144. case GBR_APERTURE_ATTRIB_CONDUCTOR: // print info associated to a track
  145. attribute_string = "TA.AperFunction,Conductor";
  146. break;
  147. case GBR_APERTURE_ATTRIB_EDGECUT: // print info associated to a board outline
  148. attribute_string = "TA.AperFunction,Profile";
  149. break;
  150. case GBR_APERTURE_ATTRIB_VIAPAD: // print info associated to a flashed via
  151. attribute_string = "TA.AperFunction,ViaPad";
  152. break;
  153. case GBR_APERTURE_ATTRIB_NONCONDUCTOR: // print info associated to a item on a copper layer
  154. // which is not a track (for instance a text)
  155. attribute_string = "TA.AperFunction,NonConductor";
  156. break;
  157. case GBR_APERTURE_ATTRIB_COMPONENTPAD: // print info associated to a flashed
  158. // through hole component on outer layer
  159. attribute_string = "TA.AperFunction,ComponentPad";
  160. break;
  161. case GBR_APERTURE_ATTRIB_SMDPAD_SMDEF: // print info associated to a flashed for SMD pad.
  162. // with solder mask defined from the copper shape
  163. // Excluded BGA pads which have their own type
  164. attribute_string = "TA.AperFunction,SMDPad,SMDef";
  165. break;
  166. case GBR_APERTURE_ATTRIB_SMDPAD_CUDEF: // print info associated to a flashed SMD pad with
  167. // a solder mask defined by the solder mask
  168. attribute_string = "TA.AperFunction,SMDPad,CuDef";
  169. break;
  170. case GBR_APERTURE_ATTRIB_BGAPAD_SMDEF: // print info associated to flashed BGA pads with
  171. // a solder mask defined by the copper shape
  172. attribute_string = "TA.AperFunction,BGAPad,SMDef";
  173. break;
  174. case GBR_APERTURE_ATTRIB_BGAPAD_CUDEF: // print info associated to a flashed BGA pad with
  175. // a solder mask defined by the solder mask
  176. attribute_string = "TA.AperFunction,BGAPad,CuDef";
  177. break;
  178. case GBR_APERTURE_ATTRIB_CONNECTORPAD: // print info associated to a flashed edge connector pad (outer layers)
  179. attribute_string = "TA.AperFunction,ConnectorPad";
  180. break;
  181. case GBR_APERTURE_ATTRIB_WASHERPAD: // print info associated to flashed mechanical pads (NPTH)
  182. attribute_string = "TA.AperFunction,WasherPad";
  183. break;
  184. case GBR_APERTURE_ATTRIB_HEATSINKPAD: // print info associated to a flashed heat sink pad
  185. // (typically for SMDs)
  186. attribute_string = "TA.AperFunction,HeatsinkPad";
  187. break;
  188. case GBR_APERTURE_ATTRIB_TESTPOINT: // print info associated to a flashed test point pad
  189. // (typically for SMDs)
  190. attribute_string = "TA.AperFunction,TestPad";
  191. break;
  192. case GBR_APERTURE_ATTRIB_FIDUCIAL_GLBL: // print info associated to a flashed fiducial pad
  193. // (typically for SMDs)
  194. attribute_string = "TA.AperFunction,FiducialPad,Global";
  195. break;
  196. case GBR_APERTURE_ATTRIB_FIDUCIAL_LOCAL: // print info associated to a flashed fiducial pad
  197. // (typically for SMDs)
  198. attribute_string = "TA.AperFunction,FiducialPad,Local";
  199. break;
  200. case GBR_APERTURE_ATTRIB_CASTELLATEDPAD: // print info associated to a flashed castellated pad
  201. // (typically for SMDs)
  202. attribute_string = "TA.AperFunction,CastellatedPad";
  203. break;
  204. case GBR_APERTURE_ATTRIB_CASTELLATEDDRILL: // print info associated to a flashed castellated pad
  205. // in drill files
  206. attribute_string = "TA.AperFunction,CastellatedDrill";
  207. break;
  208. case GBR_APERTURE_ATTRIB_VIADRILL: // print info associated to a via hole in drill files
  209. attribute_string = "TA.AperFunction,ViaDrill";
  210. break;
  211. case GBR_APERTURE_ATTRIB_CMP_DRILL: // print info associated to a component
  212. // round pad hole in drill files
  213. attribute_string = "TA.AperFunction,ComponentDrill";
  214. break;
  215. // print info associated to a component oblong pad hole in drill files
  216. // Same as a round pad hole, but is a specific aperture in drill file and
  217. // a G04 comment is added to the aperture function
  218. case GBR_APERTURE_ATTRIB_CMP_OBLONG_DRILL:
  219. comment_string = "aperture for slot hole";
  220. attribute_string = "TA.AperFunction,ComponentDrill";
  221. break;
  222. case GBR_APERTURE_ATTRIB_CMP_POSITION: // print info associated to a component
  223. // flashed shape at the component position
  224. // in placement files
  225. attribute_string = "TA.AperFunction,ComponentMain";
  226. break;
  227. case GBR_APERTURE_ATTRIB_PAD1_POSITION: // print info associated to a component
  228. // flashed shape at pad 1 position
  229. // (pad 1 is also pad A1 or pad AA1)
  230. // in placement files
  231. attribute_string = "TA.AperFunction,ComponentPin";
  232. break;
  233. case GBR_APERTURE_ATTRIB_PADOTHER_POSITION: // print info associated to a component
  234. // flashed shape at pads position (all but pad 1)
  235. // in placement files
  236. // Currently: (could be changed later) same as
  237. // GBR_APERTURE_ATTRIB_PADOTHER_POSITION
  238. attribute_string = "TA.AperFunction,ComponentPin";
  239. break;
  240. case GBR_APERTURE_ATTRIB_CMP_BODY: // print info associated to a component
  241. // print the component physical body
  242. // polygon in placement files
  243. attribute_string = "TA.AperFunction,ComponentOutline,Body";
  244. break;
  245. case GBR_APERTURE_ATTRIB_CMP_LEAD2LEAD: // print info associated to a component
  246. // print the component physical lead to lead
  247. // polygon in placement files
  248. attribute_string = "TA.AperFunction,ComponentOutline,Lead2Lead";
  249. break;
  250. case GBR_APERTURE_ATTRIB_CMP_FOOTPRINT: // print info associated to a component
  251. // print the component footprint bounding box
  252. // polygon in placement files
  253. attribute_string = "TA.AperFunction,ComponentOutline,Footprint";
  254. break;
  255. case GBR_APERTURE_ATTRIB_CMP_COURTYARD: // print info associated to a component
  256. // print the component courtyard
  257. // polygon in placement files
  258. attribute_string = "TA.AperFunction,ComponentOutline,Courtyard";
  259. break;
  260. break;
  261. }
  262. std::string full_attribute_string;
  263. wxString eol_string;
  264. if( !attribute_string.empty() )
  265. {
  266. if( !comment_string.empty() )
  267. {
  268. full_attribute_string = "G04 " + comment_string + "*\n";
  269. }
  270. if( aUseX1StructuredComment )
  271. {
  272. full_attribute_string += "G04 #@! ";
  273. eol_string = "*\n";
  274. }
  275. else
  276. {
  277. full_attribute_string += "%";
  278. eol_string = "*%\n";
  279. }
  280. }
  281. full_attribute_string += attribute_string + eol_string;
  282. return full_attribute_string;
  283. }
  284. // Helper function to convert a ascii hex char to its integer value
  285. // If the char is not a hexa char, return -1
  286. int char2Hex( unsigned aCode )
  287. {
  288. if( aCode >= '0' && aCode <= '9' )
  289. return aCode - '0';
  290. if( aCode >= 'A' && aCode <= 'F' )
  291. return aCode - 'A' + 10;
  292. if( aCode >= 'a' && aCode <= 'f' )
  293. return aCode - 'a' + 10;
  294. return -1;
  295. }
  296. wxString FormatStringFromGerber( const wxString& aString )
  297. {
  298. // make the inverse conversion of FormatStringToGerber()
  299. // It converts a "normalized" gerber string containing escape sequences
  300. // and convert it to a 16 bits unicode char
  301. // and return a wxString (unicode 16) from the gerber string
  302. // Note the initial gerber string can already contain unicode chars.
  303. wxString txt; // The string converted from Gerber string
  304. unsigned count = aString.Length();
  305. for( unsigned ii = 0; ii < count; ++ii )
  306. {
  307. unsigned code = aString[ii];
  308. if( code == '\\' && ii < count-5 && aString[ii+1] == 'u' )
  309. {
  310. // Note the latest Gerber X2 spec (2019 06) uses \uXXXX to encode
  311. // the unicode XXXX hexadecimal value
  312. // If 4 chars next to 'u' are hexadecimal chars,
  313. // Convert these 4 hexadecimal digits to a 16 bit unicode
  314. // (Gerber allows only 4 hexadecimal digits)
  315. // If an error occurs, the escape sequence is not translated,
  316. // and used "as this"
  317. long value = 0;
  318. bool error = false;
  319. for( int jj = 0; jj < 4; jj++ )
  320. {
  321. value <<= 4;
  322. code = aString[ii+jj+2];
  323. int hexa = char2Hex( code );
  324. if( hexa >= 0 )
  325. value += hexa;
  326. else
  327. {
  328. error = true;
  329. break;
  330. }
  331. }
  332. if( !error )
  333. {
  334. if( value >= ' ' ) // Is a valid wxChar ?
  335. txt.Append( wxChar( value ) );
  336. ii += 5;
  337. }
  338. else
  339. {
  340. txt.Append( aString[ii] );
  341. continue;
  342. }
  343. }
  344. else
  345. txt.Append( aString[ii] );
  346. }
  347. return txt;
  348. }
  349. wxString ConvertNotAllowedCharsInGerber( const wxString& aString, bool aAllowUtf8Chars, bool aQuoteString )
  350. {
  351. /* format string means convert any code > 0x7E and unautorized codes to a hexadecimal
  352. * 16 bits sequence unicode
  353. * However if aAllowUtf8Chars is true only unautorized codes will be escaped, because some
  354. * Gerber files accept UTF8 chars.
  355. * unautorized codes are ',' '*' '%' '\' '"' and are used as separators in Gerber files
  356. */
  357. wxString txt;
  358. if( aQuoteString )
  359. txt << "\"";
  360. for( unsigned ii = 0; ii < aString.Length(); ++ii )
  361. {
  362. wxChar code = aString[ii];
  363. bool convert = false;
  364. switch( code )
  365. {
  366. case '\\':
  367. case '%':
  368. case '*':
  369. case ',':
  370. convert = true;
  371. break;
  372. case '"':
  373. if( aQuoteString )
  374. convert = true;
  375. break;
  376. default:
  377. break;
  378. }
  379. if( !aAllowUtf8Chars && code > 0x7F )
  380. convert = true;
  381. if( convert )
  382. {
  383. // Convert code to 4 hexadecimal digit
  384. // (Gerber allows only 4 hexadecimal digit) in escape seq:
  385. // "\uXXXX", XXXX is the unicode 16 bits hexa value
  386. char hexa[32];
  387. sprintf( hexa,"\\u%4.4X", code & 0xFFFF);
  388. txt += hexa;
  389. }
  390. else
  391. txt += code;
  392. }
  393. if( aQuoteString )
  394. txt << "\"";
  395. return txt;
  396. }
  397. std::string GBR_DATA_FIELD::GetGerberString() const
  398. {
  399. wxString converted;
  400. if( !m_field.IsEmpty() )
  401. converted = ConvertNotAllowedCharsInGerber( m_field, m_useUTF8, m_escapeString );
  402. // Convert the char string to std::string. Be carefull when converting a wxString to
  403. // a std::string: using static_cast<const char*> is mandatory
  404. std::string txt = static_cast<const char*>( converted.utf8_str() );
  405. return txt;
  406. }
  407. std::string FormatStringToGerber( const wxString& aString )
  408. {
  409. wxString converted;
  410. /* format string means convert any code > 0x7E and unautorized codes to a hexadecimal
  411. * 16 bits sequence unicode
  412. * unautorized codes are ',' '*' '%' '\'
  413. * This conversion is not made for quoted strings, because if the string is
  414. * quoted, the conversion is expected to be already made, and the returned string must use
  415. * UTF8 encoding
  416. */
  417. if( !aString.IsEmpty() && ( aString[0] != '\"' || aString[aString.Len()-1] != '\"' ) )
  418. converted = ConvertNotAllowedCharsInGerber( aString, false, false );
  419. else
  420. converted = aString;
  421. // Convert the char string to std::string. Be carefull when converting awxString to
  422. // a std::string: using static_cast<const char*> is mandatory
  423. std::string txt = static_cast<const char*>( converted.utf8_str() );
  424. return txt;
  425. }
  426. // Netname and Pan num fields cannot be empty in Gerber files
  427. // Normalized names must be used, if any
  428. #define NO_NET_NAME wxT( "N/C" ) // net name of not connected pads (one pad net) (normalized)
  429. #define NO_PAD_NAME wxT( "" ) // pad name of pads without pad name/number (not normalized)
  430. bool FormatNetAttribute( std::string& aPrintedText, std::string& aLastNetAttributes,
  431. const GBR_NETLIST_METADATA* aData, bool& aClearPreviousAttributes,
  432. bool aUseX1StructuredComment )
  433. {
  434. aClearPreviousAttributes = false;
  435. wxString prepend_string;
  436. wxString eol_string;
  437. if( aUseX1StructuredComment )
  438. {
  439. prepend_string = "G04 #@! ";
  440. eol_string = "*\n";
  441. }
  442. else
  443. {
  444. prepend_string = "%";
  445. eol_string = "*%\n";
  446. }
  447. // print a Gerber net attribute record.
  448. // it is added to the object attributes dictionary
  449. // On file, only modified or new attributes are printed.
  450. if( aData == NULL )
  451. return false;
  452. std::string pad_attribute_string;
  453. std::string net_attribute_string;
  454. std::string cmp_attribute_string;
  455. if( aData->m_NetAttribType == GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED )
  456. return false; // idle command: do nothing
  457. if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) )
  458. {
  459. // print info associated to a flashed pad (cmpref, pad name, and optionally pin function)
  460. // example1: %TO.P,R5,3*%
  461. // example2: %TO.P,R5,3,reset*%
  462. pad_attribute_string = prepend_string + "TO.P,";
  463. pad_attribute_string += FormatStringToGerber( aData->m_Cmpref ) + ",";
  464. if( aData->m_Padname.IsEmpty() )
  465. // Happens for "mechanical" or never connected pads
  466. pad_attribute_string += FormatStringToGerber( NO_PAD_NAME );
  467. else
  468. {
  469. pad_attribute_string += aData->m_Padname.GetGerberString();
  470. // In Pcbnew, the pin function comes from the schematic.
  471. // so it exists only for named pads
  472. if( !aData->m_PadPinFunction.IsEmpty() )
  473. {
  474. pad_attribute_string += ',';
  475. pad_attribute_string += aData->m_PadPinFunction.GetGerberString();
  476. }
  477. }
  478. pad_attribute_string += eol_string;
  479. }
  480. if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_NET ) )
  481. {
  482. // print info associated to a net
  483. // example: %TO.N,Clk3*%
  484. net_attribute_string = prepend_string + "TO.N,";
  485. if( aData->m_Netname.IsEmpty() )
  486. {
  487. if( aData->m_NotInNet )
  488. {
  489. // Happens for not connectable pads: mechanical pads
  490. // and pads with no padname/num
  491. // In this case the net name must be left empty
  492. }
  493. else
  494. {
  495. // Happens for not connected pads: use a normalized
  496. // dummy name
  497. net_attribute_string += FormatStringToGerber( NO_NET_NAME );
  498. }
  499. }
  500. else
  501. net_attribute_string += FormatStringToGerber( aData->m_Netname );
  502. net_attribute_string += eol_string;
  503. }
  504. if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) &&
  505. !( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) )
  506. {
  507. // print info associated to a footprint
  508. // example: %TO.C,R2*%
  509. // Because GBR_NETINFO_PAD option already contains this info, it is not
  510. // created here for a GBR_NETINFO_PAD attribute
  511. cmp_attribute_string = prepend_string + "TO.C,";
  512. cmp_attribute_string += FormatStringToGerber( aData->m_Cmpref ) + eol_string;
  513. }
  514. // the full list of requested attributes:
  515. std::string full_attribute_string = pad_attribute_string + net_attribute_string
  516. + cmp_attribute_string;
  517. // the short list of requested attributes
  518. // (only modified or new attributes are stored here):
  519. std::string short_attribute_string;
  520. // Attributes have changed: update attribute string, and see if the previous attribute
  521. // list (dictionary in Gerber language) must be cleared
  522. if( aLastNetAttributes != full_attribute_string )
  523. {
  524. // first, remove no longer existing attributes.
  525. // Because in Kicad the full attribute list is evaluated for each object,
  526. // the entire dictionary is cleared
  527. // If m_TryKeepPreviousAttributes is true, only the no longer existing attribute
  528. // is cleared.
  529. // Note: to avoid interaction beteween clear attributes and set attributes
  530. // the clear attribute is inserted first.
  531. bool clearDict = false;
  532. if( aLastNetAttributes.find( "TO.P," ) != std::string::npos )
  533. {
  534. if( pad_attribute_string.empty() ) // No more this attribute
  535. {
  536. if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
  537. short_attribute_string.insert( 0, prepend_string + "TO.P" + eol_string );
  538. else
  539. clearDict = true;
  540. }
  541. else if( aLastNetAttributes.find( pad_attribute_string )
  542. == std::string::npos ) // This attribute has changed
  543. short_attribute_string += pad_attribute_string;
  544. }
  545. else // New attribute
  546. short_attribute_string += pad_attribute_string;
  547. if( aLastNetAttributes.find( "TO.N," ) != std::string::npos )
  548. {
  549. if( net_attribute_string.empty() ) // No more this attribute
  550. {
  551. if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
  552. short_attribute_string.insert( 0, prepend_string + "TO.N" + eol_string );
  553. else
  554. clearDict = true;
  555. }
  556. else if( aLastNetAttributes.find( net_attribute_string )
  557. == std::string::npos ) // This attribute has changed
  558. short_attribute_string += net_attribute_string;
  559. }
  560. else // New attribute
  561. short_attribute_string += net_attribute_string;
  562. if( aLastNetAttributes.find( "TO.C," ) != std::string::npos )
  563. {
  564. if( cmp_attribute_string.empty() ) // No more this attribute
  565. {
  566. if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
  567. {
  568. // Refinement:
  569. // the attribute will be cleared only if there is no pad attribute.
  570. // If a pad attribute exists, the component name exists so the old
  571. // TO.C value will be updated, therefore no need to clear it before updating
  572. if( pad_attribute_string.empty() )
  573. short_attribute_string.insert( 0, prepend_string + "TO.C" + eol_string );
  574. }
  575. else
  576. clearDict = true;
  577. }
  578. else if( aLastNetAttributes.find( cmp_attribute_string )
  579. == std::string::npos ) // This attribute has changed
  580. short_attribute_string += cmp_attribute_string;
  581. }
  582. else // New attribute
  583. short_attribute_string += cmp_attribute_string;
  584. aClearPreviousAttributes = clearDict;
  585. aLastNetAttributes = full_attribute_string;
  586. if( clearDict )
  587. aPrintedText = full_attribute_string;
  588. else
  589. aPrintedText = short_attribute_string;
  590. }
  591. return true;
  592. }
  593. /************ class GBR_CMP_PNP_METADATA *************/
  594. void GBR_CMP_PNP_METADATA::ClearData()
  595. {
  596. // Clear all strings
  597. m_Orientation = 0.0;
  598. m_Manufacturer.Clear();
  599. m_MPN.Clear();
  600. m_Package.Clear();
  601. m_Value.Clear();
  602. m_MountType = MOUNT_TYPE_UNSPECIFIED;
  603. }
  604. /**
  605. * @return a string containing the formated metadata in X2 syntax.
  606. * one line by non empty data
  607. * the orientation (.CRot) and mount type (.CMnt) are always generated
  608. */
  609. wxString GBR_CMP_PNP_METADATA::FormatCmpPnPMetadata()
  610. {
  611. wxString text;
  612. wxString start_of_line( "%TO.");
  613. wxString end_of_line( "*%\n" );
  614. wxString mounType[] =
  615. {
  616. "Other", "SMD", "TH"
  617. };
  618. if( !m_Manufacturer.IsEmpty() )
  619. text << start_of_line << "CMfr," << m_Manufacturer << end_of_line;
  620. if( !m_MPN.IsEmpty() )
  621. text << start_of_line << "CMPN," << m_MPN << end_of_line;
  622. if( !m_Package.IsEmpty() )
  623. text << start_of_line << "Cpkg," << m_Package << end_of_line;
  624. if( !m_Footprint.IsEmpty() )
  625. text << start_of_line << "CFtp," << m_Footprint << end_of_line;
  626. if( !m_Value.IsEmpty() )
  627. text << start_of_line << "CVal," << m_Value << end_of_line;
  628. if( !m_LibraryName.IsEmpty() )
  629. text << start_of_line << "CLbN," << m_LibraryName << end_of_line;
  630. if( !m_LibraryDescr.IsEmpty() )
  631. text << start_of_line << "CLbD," << m_LibraryDescr << end_of_line;
  632. text << start_of_line << "CMnt," << mounType[m_MountType] << end_of_line;
  633. text << start_of_line << "CRot," << m_Orientation << end_of_line;
  634. return text;
  635. }