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.

531 lines
18 KiB

18 years ago
18 years ago
18 years ago
  1. /**********************************************************************/
  2. /* Import functions to import footprints from a gpcb (Newlib) library */
  3. /**********************************************************************/
  4. #include "fctsys.h"
  5. #include "wxstruct.h"
  6. #include "kicad_string.h"
  7. #include "pcbnew.h"
  8. #include "trigo.h"
  9. /* read parameters from a line, and return all params in a wxArrayString
  10. * each param is in one wxString, and double quotes removed if exists
  11. */
  12. static void Extract_Parameters( wxArrayString& param_list, char* text );
  13. static bool TestFlags( const wxString& flg_string, long flg_mask, const wxChar* flg_name );
  14. /**************************************************************/
  15. bool MODULE::Read_GPCB_Descr( const wxString& CmpFullFileName )
  16. /**************************************************************/
  17. /**
  18. * Function Read_GPCB_Descr
  19. * Read a footprint description in GPCB (Newlib) format
  20. * @param CmpFullFileName = Full file name (there is one footprint per file.
  21. * this is also the footprint name
  22. * @return bool - true if success reading else false.
  23. */
  24. /* a sample is
  25. *
  26. * Element["" "" "" "" 29000 44000 0 0 0 100 ""]
  27. * (
  28. * Pad[-5000 0 -4000 0 4999 0 4999 "" "1" "square"]
  29. * Pad[4000 0 5000 0 4999 0 4999 "" "2" "square,edge2"]
  30. * ElementLine [8000 3000 1000 3000 199]
  31. * ElementLine [8000 -3000 8000 3000 199]
  32. * ElementLine [-8000 3000 -1000 3000 199]
  33. * ElementLine [-8000 -3000 -1000 -3000 199]
  34. * ElementLine [8000 -3000 1000 -3000 199]
  35. * ElementLine [-8000 -3000 -8000 3000 199]
  36. * )
  37. *
  38. * Format
  39. * Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags]
  40. * Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags)
  41. * Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags)
  42. * Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags)
  43. * Element ("Desc" "Name" TX TY TDir TScale TNFlags)
  44. * (
  45. * . . . contents . . . *
  46. * )
  47. * With:
  48. * SFlags Symbolic or numeric flags, for the element as a whole.
  49. * NFlags Numeric flags, for the element as a whole.
  50. * Desc The description of the element. This is one of the three strings which can be
  51. * displayed on the screen.
  52. * Name The name of the element, usually the reference designator.
  53. * Value The value of the element.
  54. * MX MY The location of the elements mark. This is the reference point for placing the element and its pins and pads.
  55. * TX TY The upper left corner of the text (one of the three strings).
  56. * TDir The relative direction of the text. 0 means left to right for an unrotated element, 1 means up, 2 left, 3 down.
  57. * TScale Size of the text, as a percentage of the default size of of the font (the default font is about 40 mils high). Default is 100 (40 mils).
  58. * TSFlags Symbolic or numeric flags, for the text.
  59. * TNFlags Numeric flags, for the text.
  60. *
  61. * Elements may contain pins, pads, element
  62. *
  63. * ElementLine [X1 Y1 X2 Y2 Thickness]
  64. * ElementLine (X1 Y1 X2 Y2 Thickness)
  65. *
  66. * ElementArc [X Y Width Height StartAngle DeltaAngle Thickness]
  67. * ElementArc (X Y Width Height StartAngle DeltaAngle Thickness)
  68. * (rotation in clockwise)
  69. * Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags]
  70. * Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags)
  71. * Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags)
  72. * Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags)
  73. *
  74. * Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags]
  75. * Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags)
  76. * Pin (aX aY Thickness Drill "Name" "Number" NFlags)
  77. * Pin (aX aY Thickness Drill "Name" NFlags)
  78. * Pin (aX aY Thickness "Name" NFlags)
  79. *
  80. * Object Flags :
  81. *
  82. * Note that object flags can be given numerically (like 0x0147) or symbolically (like
  83. * "found,showname,square". Some numeric values are reused for different object types.
  84. * The table below lists the numeric value followed by the symbolic name.
  85. * 0x0001 pin
  86. * If set, this object is a pin. This flag is for internal use only.
  87. * 0x0002 via
  88. * Likewise, for vias.
  89. * 0x0004 found
  90. * If set, this object has been found by FindConnection().
  91. * 0x0008 hole
  92. * For pins and vias, this flag means that the pin or via is a hole without a copper
  93. * annulus.
  94. * 0x0010 rat
  95. * If set for a line, indicates that this line is a rat line instead of a copper trace.
  96. * 0x0010 pininpoly
  97. * For pins and pads, this flag is used internally to indicate that the pin or pad
  98. * overlaps a polygon on some layer.
  99. * 0x0010 clearpoly
  100. * For polygons, this flag means that pins and vias will normally clear these polygons
  101. * (thus, thermals are required for electrical connection). When clear, polygons
  102. * will solidly connect to pins and vias.
  103. * 0x0010 hidename
  104. * For elements, when set the name of the element is hidden.
  105. * 0x0020 showname
  106. * For elements, when set the names of pins are shown.
  107. * 0x0020 clearline
  108. * For lines and arcs, the line/arc will clear polygons instead of connecting to
  109. * them.
  110. * 0x0020 fullpoly
  111. * For polygons, the full polygon is drawn (i.e. all parts instead of only the biggest
  112. * one).
  113. * 0x0040 selected
  114. * Set when the object is selected.
  115. * 0x0080 onsolder
  116. * For elements and pads, indicates that they are on the solder side
  117. * 0x0080 auto
  118. * For lines and vias, indicates that these were created by the autorouter.
  119. * 0x0100 square
  120. * For pins and pads, indicates a square (vs round) pin/pad.
  121. * 0x0200 rubberend
  122. * For lines, used internally for rubber band moves.
  123. * 0x0200 warn
  124. * For pins, vias, and pads, set to indicate a warning.
  125. * 0x0400 usetherm
  126. * Obsolete, indicates that pins/vias should be drawn with thermal fingers.
  127. * 0x0400 Obsolete, old files used this to indicate lines drawn on silk.
  128. * 0x0800 octagon
  129. * Draw pins and vias as octagons.
  130. * 0x1000 drc
  131. * Set for objects that fail DRC.
  132. * 0x2000 lock
  133. * Set for locked objects.
  134. * 0x4000 edge2
  135. * For pads, indicates that the second point is closer to the edge. For pins, indicates
  136. * that the pin is closer to a horizontal edge and thus pinout text should be vertical.
  137. * 0x8000 marker
  138. * Marker used internally to avoid revisiting an object.
  139. * 0x10000 nopaste
  140. * For pads, set to prevent a solderpaste stencil opening for the pad. Primarily
  141. * used for pads used as fiducials.
  142. */
  143. {
  144. #define TEXT_DEFAULT_SIZE 400
  145. #define OLD_GPCB_UNIT_CONV 10
  146. #define NEW_GPCB_UNIT_CONV 0.1
  147. FILE* cmpfile;
  148. double conv_unit = NEW_GPCB_UNIT_CONV; // GPCB unit = 0.01 mils and pcbnew 0.1
  149. // Old version unit = 1 mil, so conv_unit is 10 or 0.1
  150. bool success = true;
  151. char Line[1024];
  152. int NbLine = 0;
  153. long ibuf[100];
  154. EDGE_MODULE* DrawSegm;
  155. D_PAD* Pad;
  156. wxArrayString params;
  157. int iprmcnt, icnt_max, iflgidx;
  158. if( ( cmpfile = wxFopen( CmpFullFileName, wxT( "rt" ) ) ) == NULL )
  159. return false;
  160. GetLine( cmpfile, Line, &NbLine );
  161. params.Clear();
  162. Extract_Parameters( params, Line );
  163. iprmcnt = 0;
  164. icnt_max = params.GetCount();
  165. if( params[iprmcnt].CmpNoCase( wxT( "Element" ) ) != 0 )
  166. {
  167. fclose( cmpfile );
  168. return false;
  169. }
  170. // Test symbol after "Element": if [ units = 0.01 mils, and if ( units = 1 mil
  171. iprmcnt++;
  172. if( params[iprmcnt] == wxT( "(" ) )
  173. conv_unit = OLD_GPCB_UNIT_CONV;
  174. /* Analyse first line :
  175. * Element [element_flags, description, pcb-name, value, mark_x, mark_y, text_x, text_y,
  176. * text_direction, text_scale, text_flags]
  177. */
  178. // Read flags (unused)
  179. iprmcnt++;
  180. // Read description
  181. iprmcnt++;
  182. m_Doc = params[iprmcnt];
  183. // Read pcb-name (reference )
  184. iprmcnt++;
  185. m_Reference->m_Text = params[iprmcnt];
  186. // Read value
  187. iprmcnt++;
  188. m_Value->m_Text = params[iprmcnt];
  189. // Read other infos
  190. iprmcnt++;
  191. for( int ii = 0; ii < 6; ii++ )
  192. {
  193. if( iprmcnt < icnt_max )
  194. {
  195. success = false;
  196. ibuf[ii] = 0;
  197. }
  198. else
  199. params[iprmcnt].ToLong( &ibuf[ii] );
  200. iprmcnt++;
  201. }
  202. m_Reference->m_Pos.x = wxRound( ibuf[2] * conv_unit );
  203. m_Reference->m_Pos.y = wxRound( ibuf[3] * conv_unit );;
  204. m_Reference->m_Orient = ibuf[4] * 900;
  205. // Calculate size: default is 40 mils (400 pcb units)
  206. // real size is: default * ibuf[5] / 100 (size in gpcb is given in percent of defalut size
  207. ibuf[5] *= TEXT_DEFAULT_SIZE; ibuf[5] /= 100;
  208. m_Reference->m_Size.x = m_Reference->m_Size.y = MAX( 20, ibuf[5] );
  209. m_Reference->m_Width = m_Reference->m_Size.x / 10;
  210. m_Value->m_Orient = m_Reference->m_Orient;
  211. m_Value->m_Size = m_Reference->m_Size;
  212. m_Value->m_Width = m_Reference->m_Width;
  213. while( GetLine( cmpfile, Line, &NbLine, sizeof(Line) - 1 ) != NULL )
  214. {
  215. params.Clear();
  216. Extract_Parameters( params, Line );
  217. if( params.GetCount() > 3 ) // Test units value for a string line param (more than 3 params : ident [ xx ] )
  218. {
  219. if( params[1] == wxT( "(" ) )
  220. conv_unit = OLD_GPCB_UNIT_CONV;
  221. else
  222. conv_unit = NEW_GPCB_UNIT_CONV;
  223. }
  224. if( params[0].CmpNoCase( wxT( "ElementLine" ) ) == 0 ) // line descr
  225. { // Format: ElementLine [X1 Y1 X2 Y2 Thickness]
  226. DrawSegm = new EDGE_MODULE( this );
  227. DrawSegm->SetLayer( SILKSCREEN_N_FRONT );
  228. DrawSegm->m_Shape = S_SEGMENT;
  229. m_Drawings.PushBack( DrawSegm );
  230. int* list[5] = {
  231. &DrawSegm->m_Start0.x, &DrawSegm->m_Start0.y,
  232. &DrawSegm->m_End0.x, &DrawSegm->m_End0.y,
  233. &DrawSegm->m_Width
  234. };
  235. for( unsigned ii = 0; ii < 5; ii++ )
  236. {
  237. long dim;
  238. if( ii < (params.GetCount() - 2) )
  239. {
  240. if( params[ii + 2].ToLong( &dim ) )
  241. *list[ii] = wxRound( dim * conv_unit );
  242. }
  243. }
  244. DrawSegm->SetDrawCoord();
  245. continue;
  246. }
  247. if( params[0].CmpNoCase( wxT( "ElementArc" ) ) == 0 ) // Arc descr
  248. { // format: ElementArc [X Y Width Height StartAngle DeltaAngle Thickness]
  249. // pcbnew does know ellipse so we must have Width = Height
  250. DrawSegm = new EDGE_MODULE( this );
  251. DrawSegm->SetLayer( SILKSCREEN_N_FRONT );
  252. DrawSegm->m_Shape = S_ARC;
  253. m_Drawings.PushBack( DrawSegm );
  254. for( unsigned ii = 0; ii < 7; ii++ )
  255. {
  256. long dim;
  257. if( ii < (params.GetCount() - 2) )
  258. {
  259. if( params[ii + 2].ToLong( &dim ) )
  260. ibuf[ii] = dim;
  261. else
  262. ibuf[ii] = 0;
  263. }
  264. else
  265. ibuf[ii] = 0;
  266. }
  267. int rayon = (ibuf[2] + ibuf[3]) / 4; // for and arc: ibuf[3] = ibuf[4]. pcbnew does not know ellipses
  268. wxPoint centre;
  269. centre.x = wxRound( ibuf[0] * conv_unit );
  270. centre.y = wxRound( ibuf[1] * conv_unit );
  271. DrawSegm->m_Start0 = centre;
  272. int start_angle = ibuf[4] * 10; // Pcbnew uses 0.1 degrees as units
  273. start_angle -= 1800; // Use normal X axis as reference
  274. DrawSegm->m_Angle = ibuf[5] * 10; // Angle value is clockwise in gpcb and pcbnew
  275. DrawSegm->m_End0.x = wxRound( rayon * conv_unit );
  276. DrawSegm->m_End0.y = 0;
  277. RotatePoint( &DrawSegm->m_End0, -start_angle ); // Calculate start point coordinate of arc
  278. DrawSegm->m_End0 += centre;
  279. DrawSegm->m_Width = wxRound( ibuf[6] * conv_unit );
  280. DrawSegm->SetDrawCoord();
  281. continue;
  282. }
  283. if( params[0].CmpNoCase( wxT( "Pad" ) ) == 0 ) // Pad with no hole (smd pad)
  284. { // format: Pad [x1 y1 x2 y2 thickness clearance mask "name" "pad_number" flags]
  285. Pad = new D_PAD( this );
  286. Pad->m_PadShape = PAD_RECT;
  287. Pad->m_Masque_Layer = LAYER_FRONT | SOLDERMASK_LAYER_FRONT | SOLDERPASTE_LAYER_FRONT;
  288. // Set shape from flags
  289. iflgidx = params.GetCount() - 2;
  290. if( TestFlags( params[iflgidx], 0x0080, wxT( "onsolder" ) ) )
  291. Pad->m_Masque_Layer = LAYER_BACK | SOLDERMASK_LAYER_BACK | SOLDERPASTE_LAYER_BACK;
  292. for( unsigned ii = 0; ii < 5; ii++ )
  293. {
  294. if( ii < params.GetCount() - 2 )
  295. {
  296. long dim;
  297. if( params[ii + 2].ToLong( &dim ) )
  298. ibuf[ii] = wxRound( dim * conv_unit );
  299. }
  300. else
  301. ibuf[ii] = 0;
  302. }
  303. // Read name:
  304. // Currently unused
  305. // Read pad number:
  306. if( params.GetCount() > 10 )
  307. {
  308. strncpy( Pad->m_Padname, CONV_TO_UTF8( params[10] ), 4 );
  309. }
  310. Pad->m_Pos.x = (ibuf[0] + ibuf[2]) / 2;
  311. Pad->m_Pos.y = (ibuf[1] + ibuf[3]) / 2;
  312. Pad->m_Size.x = ibuf[4] + abs( ibuf[0] - ibuf[2] );
  313. Pad->m_Size.y = ibuf[4] + abs( ibuf[1] - ibuf[3] );
  314. Pad->m_Pos.x += m_Pos.x;
  315. Pad->m_Pos.y += m_Pos.y;
  316. if( !TestFlags( params[iflgidx], 0x0100, wxT( "square" ) ) )
  317. {
  318. if( Pad->m_Size.x == Pad->m_Size.y )
  319. Pad->m_PadShape = PAD_ROUND;
  320. else
  321. Pad->m_PadShape = PAD_OVAL;
  322. }
  323. m_Pads.PushBack( Pad );
  324. continue;
  325. }
  326. if( params[0].CmpNoCase( wxT( "Pin" ) ) == 0 ) // Pad with hole (trough pad)
  327. { // format: Pin[x y Thickness Clearance Mask DrillHole Name Number Flags]
  328. Pad = new D_PAD( this );
  329. Pad->m_PadShape = PAD_ROUND;
  330. Pad->m_Masque_Layer = ALL_CU_LAYERS |
  331. SILKSCREEN_LAYER_FRONT |
  332. SOLDERMASK_LAYER_FRONT |
  333. SOLDERMASK_LAYER_BACK;
  334. iflgidx = params.GetCount() - 2;
  335. if( TestFlags( params[iflgidx], 0x0100, wxT( "square" ) ) )
  336. Pad->m_PadShape = PAD_RECT;
  337. for( unsigned ii = 0; ii < 6; ii++ )
  338. {
  339. if( ii < params.GetCount() - 2 )
  340. {
  341. long dim;
  342. if( params[ii + 2].ToLong( &dim ) )
  343. ibuf[ii] = wxRound( dim * conv_unit );
  344. }
  345. else
  346. ibuf[ii] = 0;
  347. }
  348. // Read name:
  349. // Currently unused
  350. // Read pad number:
  351. if( params.GetCount() > 9 )
  352. {
  353. strncpy( Pad->m_Padname, CONV_TO_UTF8( params[9] ), 4 );
  354. }
  355. Pad->m_Pos.x = ibuf[0];
  356. Pad->m_Pos.y = ibuf[1];
  357. Pad->m_Drill.x = Pad->m_Drill.y = ibuf[5];
  358. Pad->m_Size.x = Pad->m_Size.y = ibuf[3] + Pad->m_Drill.x;
  359. Pad->m_Pos.x += m_Pos.x;
  360. Pad->m_Pos.y += m_Pos.y;
  361. if( (Pad->m_PadShape == PAD_ROUND) && (Pad->m_Size.x != Pad->m_Size.y) )
  362. Pad->m_PadShape = PAD_OVAL;
  363. m_Pads.PushBack( Pad );
  364. continue;
  365. }
  366. }
  367. fclose( cmpfile );
  368. if( m_Value->m_Text.IsEmpty() )
  369. m_Value->m_Text = wxT( "Val**" );
  370. if( m_Reference->m_Text.IsEmpty() )
  371. {
  372. wxFileName filename( CmpFullFileName );
  373. m_Reference->m_Text = filename.GetName();
  374. }
  375. /* Recalculate the bounding box */
  376. Set_Rectangle_Encadrement();
  377. return success;
  378. }
  379. /***********************************************************************/
  380. static void Extract_Parameters( wxArrayString& param_list, char* text )
  381. /***********************************************************************/
  382. /* Read a text line and extract params and tokens.
  383. * special chars are:
  384. * [ ] ( ) Begin and end of parameter list and units indicator
  385. * " is a string delimiter
  386. * space is the param separator
  387. * The first word is the keyword
  388. * the second item is one of ( ot [
  389. * other are parameters (number or delimited string)
  390. * last parameter is ) or ]
  391. */
  392. {
  393. char key;
  394. wxString tmp;
  395. while( *text != 0 )
  396. {
  397. key = *text;
  398. text++;
  399. switch( key )
  400. {
  401. case '[':
  402. case ']':
  403. case '(':
  404. case ')':
  405. if( !tmp.IsEmpty() )
  406. {
  407. param_list.Add( tmp );
  408. tmp.Clear();
  409. }
  410. tmp.Append( key );
  411. param_list.Add( tmp );
  412. tmp.Clear();
  413. break;
  414. case '\n':
  415. case '\r':
  416. case '\t':
  417. case ' ':
  418. if( !tmp.IsEmpty() )
  419. {
  420. param_list.Add( tmp );
  421. tmp.Clear();
  422. }
  423. break;
  424. case '"':
  425. while( *text != 0 )
  426. {
  427. key = *text;
  428. text++;
  429. if( key == '"' )
  430. {
  431. param_list.Add( tmp );
  432. tmp.Clear();
  433. break;
  434. }
  435. else
  436. tmp.Append( key );
  437. }
  438. break;
  439. default:
  440. tmp.Append( key );
  441. break;
  442. }
  443. }
  444. }
  445. /***********************************************************************************/
  446. bool TestFlags( const wxString& flg_string, long flg_mask, const wxChar* flg_name )
  447. /***********************************************************************************/
  448. /** Function TestFlags
  449. * Test flag flg_mask or flg_name.
  450. * @param flg_string = flsg list to test: can be a bit field flag or a list name flsg
  451. * a bit field flag is an hexadecimal value: Ox00020000
  452. * a list name flsg is a string list of flags, comma separated like square,option1
  453. * @param flg_mask = flsg list to test
  454. * @param flg_mask = flsg list to test
  455. * @return true if found
  456. */
  457. {
  458. wxString strnumber;
  459. if( flg_string.StartsWith( wxT( "0x" ),
  460. &strnumber ) || flg_string.StartsWith( wxT( "0X" ), &strnumber ) )
  461. {
  462. long lflags;
  463. if( strnumber.ToLong( &lflags, 16 ) )
  464. if( lflags & flg_mask )
  465. return true;
  466. }
  467. else if( flg_string.Contains( flg_name ) )
  468. return true;
  469. return false;
  470. }