pcb 4.1.1
An interactive printed circuit board layout editor.

ipcd356.c

Go to the documentation of this file.
00001 
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #include <stdio.h>
00040 #include <stdarg.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <time.h>
00044 
00045 #include "data.h"
00046 #include "config.h"
00047 #include "global.h"
00048 #include "rats.h"
00049 #include "error.h"
00050 #include "find.h"
00051 #include "misc.h"
00052 #include "pcb-printf.h"
00053 
00054 #include "hid.h"
00055 #include "hid/common/hidnogui.h"
00056 #include "../hidint.h"
00057 
00058 #ifdef HAVE_LIBDMALLOC
00059 #include <dmalloc.h>
00060 #endif
00061 
00062 static HID_Attribute IPCD356_options[] =
00063 {
00064 /* %start-doc options "95 IPC-D-356 Netlist Export"
00065 @ftable @code
00066 @item --netlist-file <string>
00067 Name of the IPC-D-356 Netlist output file.
00068 Parameter @code{<string>} can include a path.
00069 @end ftable
00070 %end-doc
00071 */
00072   {
00073     "netlistfile",
00074     "Name of the IPC-D-356 Netlist output file",
00075     HID_String,
00076     0, 0, {0, 0, 0}, 0, 0
00077   },
00078 #define HA_IPCD356_filename 0
00079 };
00080 
00081 #define NUM_OPTIONS (sizeof(IPCD356_options)/sizeof(IPCD356_options[0]))
00082 
00083 static HID_Attr_Val IPCD356_values[NUM_OPTIONS];
00084 
00085 const char *IPCD356_filename;
00086 
00087 typedef struct
00088 {
00089   char NName[11];
00090   char NetName[256];
00091 } IPCD356_Alias;
00092 
00093 typedef struct
00094 {
00095   int AliasN; 
00096   IPCD356_Alias *Alias;
00097 } IPCD356_AliasList;
00098 
00099 void IPCD356_WriteNet (FILE *, char *);
00100 void IPCD356_WriteHeader (FILE *);
00101 void IPCD356_End (FILE *);
00102 int IPCD356_Netlist (void);
00103 int IPCD356_WriteAliases (FILE *, IPCD356_AliasList *);
00104 void ResetVisitPinsViasAndPads (void);
00105 void CheckNetLength (char *, IPCD356_AliasList *);
00106 IPCD356_AliasList *CreateAliasList (void);
00107 IPCD356_AliasList *AddAliasToList (IPCD356_AliasList *);
00108 int IPCD356_SanityCheck (void);
00109 
00110 static HID_Attribute *
00111 IPCD356_get_export_options (int *n)
00112 {
00113   static char *last_IPCD356_filename = 0;
00114 
00115   if (PCB)
00116     {
00117       derive_default_filename (PCB->Filename, &IPCD356_options[HA_IPCD356_filename], ".net", &last_IPCD356_filename);
00118     }
00119 
00120   if (n)
00121     *n = NUM_OPTIONS;
00122 
00123   return IPCD356_options;
00124 }
00125 
00134 void
00135 IPCD356_WriteHeader (FILE * fd)
00136 {
00137   time_t currenttime;
00138   char utcTime[64];
00139   const char *fmt = "%c UTC";
00140 
00141   currenttime = time (NULL);
00142   strftime (utcTime, sizeof utcTime, fmt, gmtime (&currenttime));
00143 
00144   fprintf (fd,
00145     "C  IPC-D-356 Netlist generated by gEDA PCB " VERSION "\nC  \n");
00146   fprintf (fd, "C  File created on %s\nC  \n", utcTime);
00147   if (PCB->Name == NULL)
00148     {
00149       fprintf (fd, "P  JOB   %s\n", PCB->Filename); /* Use the file name if the PCB name in not set. */
00150     }
00151   else
00152     {
00153       fprintf (fd, "P  JOB   %s\n", PCB->Name);
00154     }
00155   fprintf (fd, "P  CODE  00\n");
00156   if (strcmp (Settings.grid_unit->suffix,"mil") == 0) /* Use whatever unit is currently in use (mil or mm). */
00157     {
00158       fprintf (fd, "P  UNITS CUST 0\n");
00159     }
00160   else
00161     {
00162       fprintf (fd, "P  UNITS CUST 1\n");
00163     }
00164   fprintf (fd, "P  DIM   N\n");
00165   fprintf (fd, "P  VER   IPC-D-356\n");
00166   fprintf (fd, "P  IMAGE PRIMARY\nC  \n");
00167 }
00168 
00169 
00188 void
00189 IPCD356_WriteNet (FILE * fd, char *net)
00190 {
00191   int padx, pady, tmp;
00192 
00193   ELEMENT_LOOP (PCB->Data);
00194   PAD_LOOP (element);
00195   if (TEST_FLAG (FOUNDFLAG, pad))
00196     {
00197       fprintf (fd, "327%-17.14s", net); /* Net Name. */
00198       fprintf (fd, "%-6.6s", element->Name[1].TextString); /* Refdes. */
00199       fprintf (fd, "-%-4.4s", pad->Number); /* pin number. */
00200       fprintf (fd, " "); 
00201       fprintf (fd, "      "); /* Drilled hole Id (blank for pads). */
00202       if (TEST_FLAG (ONSOLDERFLAG, pad) == true)
00203         {
00204           fprintf (fd, "A02"); 
00205         }
00206       else
00207         {
00208           fprintf (fd, "A01"); /* Top side. */
00209         }
00210       padx = (pad->Point1.X + pad->Point2.X) / 2; /* X location in PCB units. */
00211       pady = (PCB->MaxHeight - ((pad->Point1.Y + pad->Point2.Y) / 2)); /* Y location in PCB units. */
00212 
00213       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00214         {
00215           padx = padx / 2540; /* X location in 0.0001". */
00216           pady = pady / 2540; /* Y location in 0.0001". */
00217         }
00218       else
00219         {
00220           padx = padx / 1000; /* X location in 0.001 mm. */
00221           pady = pady / 1000; /* Y location in 0.001 mm. */
00222         }
00223       fprintf (fd, "X%+6.6d", padx); /* X Pad center. */
00224       fprintf (fd, "Y%+6.6d", pady); /* Y pad center. */
00225 
00226       padx = (pad->Thickness + (pad->Point2.X - pad->Point1.X)); /* Pad dimension X in PCB units. */
00227       pady = (pad->Thickness + (pad->Point2.Y - pad->Point1.Y)); /* Pad dimension Y in PCB units. */
00228 
00229       if (strcmp(Settings.grid_unit->suffix, "mil") == 0)
00230         {
00231           padx = padx / 2540; /* X location in 0.0001". */
00232           pady = pady / 2540; /* Y location in 0.0001". */
00233         }
00234       else
00235         {
00236           padx = padx / 1000;   // X location in 0.001mm
00237           pady = pady / 1000;   // Y location in 0.001mm
00238         }
00239 
00240       fprintf (fd, "X%4.4d", padx);
00241       fprintf (fd, "Y%4.4d", pady);
00242       fprintf (fd, "R000"); /* Rotation (0 degrees). */
00243       fprintf (fd, " "); /* Column 72 should be left blank. */
00244       if (pad->Mask > 0)    
00245         {
00246           if (TEST_FLAG (ONSOLDERFLAG, pad) == true)
00247             {
00248               fprintf(fd, "S2"); /* Soldermask on bottom side. */
00249             }
00250           else
00251             {
00252               fprintf(fd, "S1"); /* SolderMask on top side. */
00253             }
00254         }
00255       else
00256         {
00257           fprintf(fd, "S3"); /* No soldermask. */
00258         }
00259       fprintf (fd, "      "); /* Padding. */
00260       fprintf (fd, "\n");
00261       SET_FLAG (VISITFLAG, pad);
00262     }
00263 
00264   END_LOOP; /* Pad. */
00265   PIN_LOOP (element);
00266   if (TEST_FLAG (FOUNDFLAG, pin))
00267     {
00268       if (TEST_FLAG (HOLEFLAG, pin)) /* Non plated? */
00269         {
00270           fprintf (fd, "367%-17.14s", net); /* Net Name. */
00271         }
00272       else
00273         {
00274           fprintf (fd, "317%-17.14s", net); /* Net Name. */
00275         }
00276       fprintf (fd, "%-6.6s", element->Name[1].TextString); /* Refdes. */
00277       fprintf (fd, "-%-4.4s", pin->Number); /* Pin number. */
00278       fprintf (fd, " "); 
00279       tmp = pin->DrillingHole;
00280       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00281         {
00282           tmp = tmp / 2540; /* 0.0001". */
00283         }
00284       else
00285         {
00286           tmp = tmp / 1000; /* 0.001 mm. */
00287         }
00288 
00289       if (TEST_FLAG (HOLEFLAG, pin))
00290         {
00291           fprintf (fd, "D%-4.4dU", tmp); /* Unplated Drilled hole Id. */
00292         }
00293       else
00294         {
00295           fprintf (fd, "D%-4.4dP", tmp); /* Plated drill hole. */
00296         }
00297       fprintf (fd, "A00"); /* Accessible from both sides. */
00298       padx = pin->X; /* X location in PCB units. */
00299       pady = (PCB->MaxHeight - pin->Y); /* Y location in PCB units.*/
00300 
00301       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00302         {
00303           padx = padx / 2540; /* X location in 0.0001". */
00304           pady = pady / 2540; /* Y location in 0.0001". */
00305         }
00306       else
00307         {
00308           padx = padx / 1000; /* X location in 0.001 mm. */
00309           pady = pady / 1000; /* Y location in 0.001 mm. */
00310         }
00311 
00312       fprintf (fd, "X%+6.6d", padx); /* X Pad center. */
00313       fprintf (fd, "Y%+6.6d", pady); /* Y pad center. */
00314 
00315       padx = pin->Thickness;
00316 
00317       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00318         {
00319           padx = padx / 2540; /* X location in 0.0001". */
00320         }
00321       else
00322         {
00323           padx = padx / 1000; /* X location in 0.001 mm. */
00324         }
00325 
00326       fprintf (fd, "X%4.4d", padx); /* Pad dimension X. */
00327       if (TEST_FLAG (SQUAREFLAG, pin))
00328         {
00329           fprintf (fd, "Y%4.4d", padx); /* Pad dimension Y. */
00330         }
00331       else
00332         {
00333           fprintf (fd, "Y0000"); /*  Y is 0 for round pins. */
00334         }
00335       fprintf (fd, "R000"); /* Rotation (0 degrees). */
00336       fprintf (fd, " "); /* Column 72 should be left blank.*/
00337       if (pin->Mask > 0)    
00338         {
00339           fprintf(fd, "S0"); /* No Soldermask. */
00340         }
00341       else
00342         {
00343           fprintf(fd, "S3"); /* Soldermask on both sides. */
00344         }
00345       fprintf (fd, "      "); /* Padding. */
00346 
00347       fprintf (fd, "\n");
00348 
00349       SET_FLAG (VISITFLAG, pin);
00350 
00351     }
00352 
00353   END_LOOP; /* Pin. */
00354   END_LOOP; /* Element */
00355 
00356   VIA_LOOP (PCB->Data);
00357   if (TEST_FLAG (FOUNDFLAG, via))
00358     {
00359       if (TEST_FLAG (HOLEFLAG, via)) /* Non plated ? */
00360         {
00361           fprintf (fd, "367%-17.14s", net); /* Net Name. */
00362         }
00363       else
00364         {
00365           fprintf (fd, "317%-17.14s", net); /* Net Name. */
00366         }
00367       fprintf (fd, "VIA   "); /* Refdes. */
00368       fprintf (fd, "-    "); /* Pin number. */
00369       fprintf (fd, " "); 
00370       tmp = via->DrillingHole;  
00371       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00372         {
00373           tmp = tmp / 2540; /* 0.0001". */
00374         }
00375       else
00376         {
00377           tmp = tmp / 1000; /* 0.001 mm. */
00378         }
00379 
00380       if (TEST_FLAG (HOLEFLAG, via))
00381         {
00382           fprintf (fd, "D%-4.4dU", tmp); /* Unplated Drilled hole Id. */
00383         }
00384       else
00385         {
00386           fprintf (fd, "D%-4.4dP", tmp); /* Plated drill hole. */
00387         }
00388       fprintf (fd, "A00"); /* Accessible from both sides. */
00389       padx = via->X; /* X location in PCB units. */
00390       pady = (PCB->MaxHeight - via->Y); /* Y location in PCB units. */
00391 
00392       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00393         {
00394           padx = padx / 2540; /* X location in 0.0001". */
00395           pady = pady / 2540; /* Y location in 0.0001". */
00396         }
00397       else
00398         {
00399           padx = padx / 1000; /* X location in 0.001 mm. */
00400           pady = pady / 1000; /* Y location in 0.001 mm. */
00401         }
00402 
00403       fprintf (fd, "X%+6.6d", padx); /* X Pad center. */
00404       fprintf (fd, "Y%+6.6d", pady); /* Y pad center. */
00405 
00406       padx = via->Thickness;
00407       
00408       if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
00409         {
00410           padx = padx / 2540; /* X location in 0.0001". */
00411         }
00412       else
00413         {
00414           padx = padx / 1000; /* X location in 0.001 mm. */
00415         }
00416 
00417       fprintf (fd, "X%4.4d", padx); /* Pad dimension X. */
00418       fprintf (fd, "Y0000"); /* Y is 0 for round pins (vias always round?). */
00419       fprintf (fd, "R000"); /* Rotation (0 degrees). */
00420       fprintf (fd, " "); /* Column 72 should be left blank. */
00421       if (via->Mask > 0)    
00422         {
00423           fprintf(fd, "S0"); /* No Soldermask. */
00424         }
00425       else
00426         {
00427           fprintf(fd, "S3"); /* Soldermask on both sides. */
00428         }
00429       fprintf (fd, "      "); /* Padding. */
00430       fprintf (fd, "\n");
00431       SET_FLAG (VISITFLAG, via);
00432     }
00433 
00434   END_LOOP; /* Via. */
00435 }
00436 
00437 
00443 int
00444 IPCD356_Netlist (void)
00445 {
00446   FILE *fp;
00447   char nodename[256];
00448   char net[256];
00449   LibraryMenuType *netname;
00450   IPCD356_AliasList * aliaslist;
00451 
00452   if (IPCD356_SanityCheck()) /* Check for invalid names + numbers. */
00453     {
00454       Message ("Aborting.\n");
00455       return(1);
00456     }
00457 
00458   sprintf (net, "%s.ipc", PCB->Name);
00459   if (IPCD356_filename == NULL)
00460     return 1;
00461 
00462   fp = fopen (IPCD356_filename, "w+");
00463   if (fp == NULL)
00464     {
00465       Message ("error opening %s\n", IPCD356_filename);
00466       return 1;
00467     }
00468 /*   free (IPCD356_filename); */
00469 
00470 
00471   IPCD356_WriteHeader (fp);
00472 
00473   aliaslist = CreateAliasList ();
00474   if (aliaslist == NULL)
00475     {
00476       Message ("Error Aloccating memory for IPC-D-356 AliasList\n");
00477       return 1;
00478     }
00479 
00480   if (IPCD356_WriteAliases (fp, aliaslist))
00481     {
00482       Message ("Error Writing IPC-D-356 AliasList\n");
00483       return 1;
00484     }
00485 
00486 
00487   ELEMENT_LOOP (PCB->Data);
00488   PIN_LOOP (element);
00489   if (!TEST_FLAG (VISITFLAG, pin))
00490     {
00491       ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
00492       ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
00493       LookupConnectionByPin (PIN_TYPE, pin);
00494       sprintf (nodename, "%s-%s", element->Name[1].TextString, pin->Number);
00495       netname = netnode_to_netname (nodename);
00496 /*      Message("Netname: %s\n", netname->Name +2); */
00497       if (netname)
00498         {
00499           strcpy (net, &netname->Name[2]);
00500           CheckNetLength (net, aliaslist);
00501         }
00502       else
00503         {
00504           strcpy (net, "N/C");
00505         }
00506       IPCD356_WriteNet (fp, net);
00507     }
00508   END_LOOP; /* Pin. */
00509   PAD_LOOP (element);
00510   if (!TEST_FLAG (VISITFLAG, pad))
00511     {
00512       ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
00513       ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
00514       LookupConnectionByPin (PAD_TYPE, pad);
00515       sprintf (nodename, "%s-%s", element->Name[1].TextString, pad->Number);
00516       netname = netnode_to_netname (nodename);
00517 /*      Message("Netname: %s\n", netname->Name +2); */
00518       if (netname)
00519         {
00520           strcpy (net, &netname->Name[2]);
00521           CheckNetLength (net, aliaslist);
00522         }
00523       else
00524         {
00525           strcpy (net, "N/C");
00526         }
00527       IPCD356_WriteNet (fp, net);
00528     }
00529   END_LOOP; /* Pad. */
00530 
00531   END_LOOP; /* Element. */
00532 
00533   VIA_LOOP (PCB->Data);
00534   if (!TEST_FLAG (VISITFLAG, via))
00535     {
00536       ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
00537       ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
00538       LookupConnectionByPin (PIN_TYPE, via);
00539       strcpy (net, "N/C");
00540       IPCD356_WriteNet (fp, net);
00541     }
00542   END_LOOP; /* Via. */
00543 
00544   IPCD356_End (fp);
00545   fclose (fp);
00546   free (aliaslist);
00547   ResetVisitPinsViasAndPads ();
00548   ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
00549   ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
00550   return 0;
00551 }
00552 
00553 void
00554 IPCD356_End (FILE * fd)
00555 {
00556   fprintf (fd, "999\n");
00557 }
00558 
00559 void
00560 ResetVisitPinsViasAndPads ()
00561 {
00562   VIA_LOOP (PCB->Data);
00563     CLEAR_FLAG (VISITFLAG, via);
00564   END_LOOP; /* Via. */
00565   ELEMENT_LOOP (PCB->Data);
00566     PIN_LOOP (element);
00567       CLEAR_FLAG (VISITFLAG, pin);
00568     END_LOOP; /* Pin. */
00569     PAD_LOOP (element);
00570       CLEAR_FLAG (VISITFLAG, pad);
00571     END_LOOP; /* Pad. */
00572   END_LOOP; /* Element. */
00573 }
00574 
00575 int
00576 IPCD356_WriteAliases (FILE * fd, IPCD356_AliasList * aliaslist)
00577 {
00578   int index;
00579   int i;
00580 
00581   index = 1;
00582 
00583   for (i = 0; i < PCB->NetlistLib.MenuN; i++)
00584     {
00585       if (strlen (PCB->NetlistLib.Menu[i].Name + 2) > 14)
00586         {
00587           if (index == 1)
00588             {
00589               fprintf (fd, "C  Netname Aliases Section\n");
00590             }
00591           aliaslist = AddAliasToList (aliaslist);
00592           if (aliaslist == NULL)
00593             {
00594               return 1;
00595             }
00596           sprintf (aliaslist->Alias[index].NName, "NNAME%-5.5d", index);
00597           strcpy (aliaslist->Alias[index].NetName, PCB->NetlistLib.Menu[i].Name + 2);
00598 
00599           fprintf (fd, "P  %s  %-58.58s\n", aliaslist->Alias[index].NName,
00600             aliaslist->Alias[index].NetName);
00601           index++;
00602         }
00603     }
00604   if (index > 1)
00605     {
00606       fprintf (fd, "C  End Netname Aliases Section\nC  \n");
00607     }
00608   return 0;
00609 }
00610 
00611 IPCD356_AliasList *
00612 CreateAliasList ()
00613 {
00614   IPCD356_AliasList * aliaslist;
00615 
00616   aliaslist = malloc (sizeof (IPCD356_AliasList)); /* Create an alias list. */
00617   aliaslist->AliasN = 0; /* Initialize Number of Alias. */
00618   return aliaslist;
00619 }
00620 
00621 IPCD356_AliasList *
00622 AddAliasToList (IPCD356_AliasList * aliaslist)
00623 {
00624   aliaslist->AliasN++;
00625   aliaslist->Alias = realloc (aliaslist->Alias,
00626     sizeof (IPCD356_Alias) * (aliaslist->AliasN + 1));
00627   if (aliaslist->Alias == NULL)
00628     {
00629       return NULL;
00630     }
00631   return aliaslist;
00632 }
00633 
00634 void
00635 CheckNetLength (char *net, IPCD356_AliasList * aliaslist)
00636 {
00637   int i;
00638 
00639   if (strlen (net) > 14)
00640     {
00641       for (i = 1; i <= aliaslist->AliasN; i++)
00642         {
00643           if (strcmp (net, aliaslist->Alias[i].NetName) == 0)
00644             {
00645               strcpy (net, aliaslist->Alias[i].NName);
00646             }
00647         }
00648     }
00649 }
00650 
00651 int
00652 IPCD356_SanityCheck()
00653 {
00654   ELEMENT_LOOP (PCB->Data);
00655     if (element->Name[1].TextString == '\0')
00656       {
00657         Message("Error: Found unnamed element. All elements need to be named to create an IPC-D-356 netlist.\n");
00658         return(1);
00659       }
00660   END_LOOP; /* Element. */
00661   return(0);
00662 }
00663 
00664 static void
00665 IPCD356_do_export (HID_Attr_Val * options)
00666 {
00667   int i;
00668 
00669   if (!options)
00670     {
00671       IPCD356_get_export_options (0);
00672 
00673       for (i = 0; i < NUM_OPTIONS; i++)
00674         IPCD356_values[i] = IPCD356_options[i].default_val;
00675 
00676       options = IPCD356_values;
00677     }
00678 
00679   IPCD356_filename = options[HA_IPCD356_filename].str_value;
00680   if (!IPCD356_filename)
00681     IPCD356_filename = "pcb-out.net";
00682 
00683   IPCD356_Netlist ();
00684 }
00685 
00686 static void
00687 IPCD356_parse_arguments (int *argc, char ***argv)
00688 {
00689   hid_register_attributes (IPCD356_options,
00690     sizeof (IPCD356_options) / sizeof (IPCD356_options[0]));
00691   hid_parse_command_line (argc, argv);
00692 }
00693 
00694 HID IPCD356_hid;
00695 
00696 void
00697 hid_ipcd356_init ()
00698 {
00699   memset (&IPCD356_hid, 0, sizeof (HID));
00700 
00701   common_nogui_init (&IPCD356_hid);
00702 
00703   IPCD356_hid.struct_size         = sizeof (HID);
00704   IPCD356_hid.name                = "IPC-D-356";
00705   IPCD356_hid.description         = "Exports a IPC-D-356 Netlist";
00706   IPCD356_hid.exporter            = 1;
00707 
00708   IPCD356_hid.get_export_options  = IPCD356_get_export_options;
00709   IPCD356_hid.do_export           = IPCD356_do_export;
00710   IPCD356_hid.parse_arguments     = IPCD356_parse_arguments;
00711 
00712   hid_register_hid (&IPCD356_hid);
00713 
00714 }
00715 
00716 /* EOF */