Index: pcb-exporters/ipcd356/ipcd356.c
===================================================================
--- pcb-exporters/ipcd356/ipcd356.c (nonexistent)
+++ pcb-exporters/ipcd356/ipcd356.c (revision 4094)
@@ -0,0 +1,715 @@
+/*!
+ * \file src/hid/ipcd356/ipcd356.c
+ *
+ * \brief IPC-D-356 Netlist export.
+ *
+ * \author Copyright (C) 2012 Jerome Marchand (Jerome.Marchand@gmail.com)
+ *
+ *
+ *
+ * Copyright.
\n
+ *
+ * PCB, interactive printed circuit board design
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Contact addresses for paper mail and Email:
+ *
+ * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
+ *
+ * Thomas.Nau@rz.uni-ulm.de
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#include "data.h"
+#include "config.h"
+#include "global.h"
+#include "rats.h"
+#include "error.h"
+#include "find.h"
+#include "misc.h"
+#include "pcb-printf.h"
+
+#include "hid.h"
+#include "hid/common/hidnogui.h"
+#include "../hidint.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include
+#endif
+
+static HID_Attribute IPCD356_options[] =
+{
+/* %start-doc options "8 IPC-D-356 Netlist Export"
+@ftable @code
+@item --netlist-file
+Name of the IPC-D-356 Netlist output file.
+@end ftable
+%end-doc
+*/
+ {
+ "netlistfile",
+ "Name of the IPC-D-356 Netlist output file",
+ HID_String,
+ 0, 0, {0, 0, 0}, 0, 0
+ },
+#define HA_IPCD356_filename 0
+};
+
+#define NUM_OPTIONS (sizeof(IPCD356_options)/sizeof(IPCD356_options[0]))
+
+static HID_Attr_Val IPCD356_values[NUM_OPTIONS];
+
+const char *IPCD356_filename;
+
+typedef struct
+{
+ char NName[11];
+ char NetName[256];
+} IPCD356_Alias;
+
+typedef struct
+{
+ int AliasN; /*!< Number of entries. */
+ IPCD356_Alias *Alias;
+} IPCD356_AliasList;
+
+void IPCD356_WriteNet (FILE *, char *);
+void IPCD356_WriteHeader (FILE *);
+void IPCD356_End (FILE *);
+int IPCD356_Netlist (void);
+int IPCD356_WriteAliases (FILE *, IPCD356_AliasList *);
+void ResetVisitPinsViasAndPads (void);
+void CheckNetLength (char *, IPCD356_AliasList *);
+IPCD356_AliasList *CreateAliasList (void);
+IPCD356_AliasList *AddAliasToList (IPCD356_AliasList *);
+int IPCD356_SanityCheck (void);
+
+static HID_Attribute *
+IPCD356_get_export_options (int *n)
+{
+ static char *last_IPCD356_filename = 0;
+
+ if (PCB)
+ {
+ derive_default_filename (PCB->Filename, &IPCD356_options[HA_IPCD356_filename], ".net", &last_IPCD356_filename);
+ }
+
+ if (n)
+ *n = NUM_OPTIONS;
+
+ return IPCD356_options;
+}
+
+/*!
+ * \brief Writes the IPC-D-356 Header to the file provided.
+ *
+ * The JOB name is the PCB Name (if set), otherwise the filename
+ * (including the path) is used.
+ *
+ * The units used for the netlist depends on what is set (mils or mm).
+ */
+void
+IPCD356_WriteHeader (FILE * fd)
+{
+ time_t currenttime;
+ char utcTime[64];
+ const char *fmt = "%c UTC";
+
+ currenttime = time (NULL);
+ strftime (utcTime, sizeof utcTime, fmt, gmtime (¤ttime));
+
+ fprintf (fd,
+ "C IPC-D-356 Netlist generated by gEDA PCB " VERSION "\nC \n");
+ fprintf (fd, "C File created on %s\nC \n", utcTime);
+ if (PCB->Name == NULL)
+ {
+ fprintf (fd, "P JOB %s\n", PCB->Filename); /* Use the file name if the PCB name in not set. */
+ }
+ else
+ {
+ fprintf (fd, "P JOB %s\n", PCB->Name);
+ }
+ fprintf (fd, "P CODE 00\n");
+ if (strcmp (Settings.grid_unit->suffix,"mil") == 0) /* Use whatever unit is currently in use (mil or mm). */
+ {
+ fprintf (fd, "P UNITS CUST 0\n");
+ }
+ else
+ {
+ fprintf (fd, "P UNITS CUST 1\n");
+ }
+ fprintf (fd, "P DIM N\n");
+ fprintf (fd, "P VER IPC-D-356\n");
+ fprintf (fd, "P IMAGE PRIMARY\nC \n");
+}
+
+
+/*!
+ * \brief Writes a net to the file provided.
+ *
+ * The net name is passed through the "net" and should be 14 characters
+ * max.\n
+ * The function scans through pads, pins and vias and looks for the
+ * \c FOUNDFLAG.\n
+ * Once the object has been added to the net list the \c VISITFLAG is
+ * set on that object.
+ *
+ * \todo 1) The bottom layer is always written as layer #2 (A02).\n
+ * It could output the actual layer number (example: A06 on a
+ * 6 layer board).\n
+ * But I could not find an easy way to do this...
+ *
+ * \todo 2) Objects with mutiple connections could have the "M"
+ * (column 32) field written to indicate a Mid Net Point.
+ */
+void
+IPCD356_WriteNet (FILE * fd, char *net)
+{
+ int padx, pady, tmp;
+
+ ELEMENT_LOOP (PCB->Data);
+ PAD_LOOP (element);
+ if (TEST_FLAG (FOUNDFLAG, pad))
+ {
+ fprintf (fd, "327%-17.14s", net); /* Net Name. */
+ fprintf (fd, "%-6.6s", element->Name[1].TextString); /* Refdes. */
+ fprintf (fd, "-%-4.4s", pad->Number); /* pin number. */
+ fprintf (fd, " "); /*! \todo Midpoint indicator (M). */
+ fprintf (fd, " "); /* Drilled hole Id (blank for pads). */
+ if (TEST_FLAG (ONSOLDERFLAG, pad) == true)
+ {
+ fprintf (fd, "A02"); /*! \todo Put actual layer # for bottom side. */
+ }
+ else
+ {
+ fprintf (fd, "A01"); /* Top side. */
+ }
+ padx = (pad->Point1.X + pad->Point2.X) / 2; /* X location in PCB units. */
+ pady = (PCB->MaxHeight - ((pad->Point1.Y + pad->Point2.Y) / 2)); /* Y location in PCB units. */
+
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ padx = padx / 2540; /* X location in 0.0001". */
+ pady = pady / 2540; /* Y location in 0.0001". */
+ }
+ else
+ {
+ padx = padx / 1000; /* X location in 0.001 mm. */
+ pady = pady / 1000; /* Y location in 0.001 mm. */
+ }
+ fprintf (fd, "X%+6.6d", padx); /* X Pad center. */
+ fprintf (fd, "Y%+6.6d", pady); /* Y pad center. */
+
+ padx = (pad->Thickness + (pad->Point2.X - pad->Point1.X)); /* Pad dimension X in PCB units. */
+ pady = (pad->Thickness + (pad->Point2.Y - pad->Point1.Y)); /* Pad dimension Y in PCB units. */
+
+ if (strcmp(Settings.grid_unit->suffix, "mil") == 0)
+ {
+ padx = padx / 2540; /* X location in 0.0001". */
+ pady = pady / 2540; /* Y location in 0.0001". */
+ }
+ else
+ {
+ padx = padx / 1000; // X location in 0.001mm
+ pady = pady / 1000; // Y location in 0.001mm
+ }
+
+ fprintf (fd, "X%4.4d", padx);
+ fprintf (fd, "Y%4.4d", pady);
+ fprintf (fd, "R000"); /* Rotation (0 degrees). */
+ fprintf (fd, " "); /* Column 72 should be left blank. */
+ if (pad->Mask > 0)
+ {
+ if (TEST_FLAG (ONSOLDERFLAG, pad) == true)
+ {
+ fprintf(fd, "S2"); /* Soldermask on bottom side. */
+ }
+ else
+ {
+ fprintf(fd, "S1"); /* SolderMask on top side. */
+ }
+ }
+ else
+ {
+ fprintf(fd, "S3"); /* No soldermask. */
+ }
+ fprintf (fd, " "); /* Padding. */
+ fprintf (fd, "\n");
+ SET_FLAG (VISITFLAG, pad);
+ }
+
+ END_LOOP; /* Pad. */
+ PIN_LOOP (element);
+ if (TEST_FLAG (FOUNDFLAG, pin))
+ {
+ if (TEST_FLAG (HOLEFLAG, pin)) /* Non plated? */
+ {
+ fprintf (fd, "367%-17.14s", net); /* Net Name. */
+ }
+ else
+ {
+ fprintf (fd, "317%-17.14s", net); /* Net Name. */
+ }
+ fprintf (fd, "%-6.6s", element->Name[1].TextString); /* Refdes. */
+ fprintf (fd, "-%-4.4s", pin->Number); /* Pin number. */
+ fprintf (fd, " "); /*! \todo Midpoint indicator (M). */
+ tmp = pin->DrillingHole;
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ tmp = tmp / 2540; /* 0.0001". */
+ }
+ else
+ {
+ tmp = tmp / 1000; /* 0.001 mm. */
+ }
+
+ if (TEST_FLAG (HOLEFLAG, pin))
+ {
+ fprintf (fd, "D%-4.4dU", tmp); /* Unplated Drilled hole Id. */
+ }
+ else
+ {
+ fprintf (fd, "D%-4.4dP", tmp); /* Plated drill hole. */
+ }
+ fprintf (fd, "A00"); /* Accessible from both sides. */
+ padx = pin->X; /* X location in PCB units. */
+ pady = (PCB->MaxHeight - pin->Y); /* Y location in PCB units.*/
+
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ padx = padx / 2540; /* X location in 0.0001". */
+ pady = pady / 2540; /* Y location in 0.0001". */
+ }
+ else
+ {
+ padx = padx / 1000; /* X location in 0.001 mm. */
+ pady = pady / 1000; /* Y location in 0.001 mm. */
+ }
+
+ fprintf (fd, "X%+6.6d", padx); /* X Pad center. */
+ fprintf (fd, "Y%+6.6d", pady); /* Y pad center. */
+
+ padx = pin->Thickness;
+
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ padx = padx / 2540; /* X location in 0.0001". */
+ }
+ else
+ {
+ padx = padx / 1000; /* X location in 0.001 mm. */
+ }
+
+ fprintf (fd, "X%4.4d", padx); /* Pad dimension X. */
+ if (TEST_FLAG (SQUAREFLAG, pin))
+ {
+ fprintf (fd, "Y%4.4d", padx); /* Pad dimension Y. */
+ }
+ else
+ {
+ fprintf (fd, "Y0000"); /* Y is 0 for round pins. */
+ }
+ fprintf (fd, "R000"); /* Rotation (0 degrees). */
+ fprintf (fd, " "); /* Column 72 should be left blank.*/
+ if (pin->Mask > 0)
+ {
+ fprintf(fd, "S0"); /* No Soldermask. */
+ }
+ else
+ {
+ fprintf(fd, "S3"); /* Soldermask on both sides. */
+ }
+ fprintf (fd, " "); /* Padding. */
+
+ fprintf (fd, "\n");
+
+ SET_FLAG (VISITFLAG, pin);
+
+ }
+
+ END_LOOP; /* Pin. */
+ END_LOOP; /* Element */
+
+ VIA_LOOP (PCB->Data);
+ if (TEST_FLAG (FOUNDFLAG, via))
+ {
+ if (TEST_FLAG (HOLEFLAG, via)) /* Non plated ? */
+ {
+ fprintf (fd, "367%-17.14s", net); /* Net Name. */
+ }
+ else
+ {
+ fprintf (fd, "317%-17.14s", net); /* Net Name. */
+ }
+ fprintf (fd, "VIA "); /* Refdes. */
+ fprintf (fd, "- "); /* Pin number. */
+ fprintf (fd, " "); /*! \todo Midpoint indicator (M). */
+ tmp = via->DrillingHole;
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ tmp = tmp / 2540; /* 0.0001". */
+ }
+ else
+ {
+ tmp = tmp / 1000; /* 0.001 mm. */
+ }
+
+ if (TEST_FLAG (HOLEFLAG, via))
+ {
+ fprintf (fd, "D%-4.4dU", tmp); /* Unplated Drilled hole Id. */
+ }
+ else
+ {
+ fprintf (fd, "D%-4.4dP", tmp); /* Plated drill hole. */
+ }
+ fprintf (fd, "A00"); /* Accessible from both sides. */
+ padx = via->X; /* X location in PCB units. */
+ pady = (PCB->MaxHeight - via->Y); /* Y location in PCB units. */
+
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ padx = padx / 2540; /* X location in 0.0001". */
+ pady = pady / 2540; /* Y location in 0.0001". */
+ }
+ else
+ {
+ padx = padx / 1000; /* X location in 0.001 mm. */
+ pady = pady / 1000; /* Y location in 0.001 mm. */
+ }
+
+ fprintf (fd, "X%+6.6d", padx); /* X Pad center. */
+ fprintf (fd, "Y%+6.6d", pady); /* Y pad center. */
+
+ padx = via->Thickness;
+
+ if (strcmp (Settings.grid_unit->suffix, "mil") == 0)
+ {
+ padx = padx / 2540; /* X location in 0.0001". */
+ }
+ else
+ {
+ padx = padx / 1000; /* X location in 0.001 mm. */
+ }
+
+ fprintf (fd, "X%4.4d", padx); /* Pad dimension X. */
+ fprintf (fd, "Y0000"); /* Y is 0 for round pins (vias always round?). */
+ fprintf (fd, "R000"); /* Rotation (0 degrees). */
+ fprintf (fd, " "); /* Column 72 should be left blank. */
+ if (via->Mask > 0)
+ {
+ fprintf(fd, "S0"); /* No Soldermask. */
+ }
+ else
+ {
+ fprintf(fd, "S3"); /* Soldermask on both sides. */
+ }
+ fprintf (fd, " "); /* Padding. */
+ fprintf (fd, "\n");
+ SET_FLAG (VISITFLAG, via);
+ }
+
+ END_LOOP; /* Via. */
+}
+
+
+/*!
+ * \brief The main IPC-D-356 function.
+ *
+ * Gets the filename for the netlist from the dialog.
+ */
+int
+IPCD356_Netlist (void)
+{
+ FILE *fp;
+ char nodename[256];
+ char net[256];
+ LibraryMenuType *netname;
+ IPCD356_AliasList * aliaslist;
+
+ if (IPCD356_SanityCheck()) /* Check for invalid names + numbers. */
+ {
+ Message ("Aborting.\n");
+ return(1);
+ }
+
+ sprintf (net, "%s.ipc", PCB->Name);
+ if (IPCD356_filename == NULL)
+ return 1;
+
+ fp = fopen (IPCD356_filename, "w+");
+ if (fp == NULL)
+ {
+ Message ("error opening %s\n", IPCD356_filename);
+ return 1;
+ }
+/* free (IPCD356_filename); */
+
+
+ IPCD356_WriteHeader (fp);
+
+ aliaslist = CreateAliasList ();
+ if (aliaslist == NULL)
+ {
+ Message ("Error Aloccating memory for IPC-D-356 AliasList\n");
+ return 1;
+ }
+
+ if (IPCD356_WriteAliases (fp, aliaslist))
+ {
+ Message ("Error Writing IPC-D-356 AliasList\n");
+ return 1;
+ }
+
+
+ ELEMENT_LOOP (PCB->Data);
+ PIN_LOOP (element);
+ if (!TEST_FLAG (VISITFLAG, pin))
+ {
+ ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
+ ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
+ LookupConnectionByPin (PIN_TYPE, pin);
+ sprintf (nodename, "%s-%s", element->Name[1].TextString, pin->Number);
+ netname = netnode_to_netname (nodename);
+/* Message("Netname: %s\n", netname->Name +2); */
+ if (netname)
+ {
+ strcpy (net, &netname->Name[2]);
+ CheckNetLength (net, aliaslist);
+ }
+ else
+ {
+ strcpy (net, "N/C");
+ }
+ IPCD356_WriteNet (fp, net);
+ }
+ END_LOOP; /* Pin. */
+ PAD_LOOP (element);
+ if (!TEST_FLAG (VISITFLAG, pad))
+ {
+ ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
+ ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
+ LookupConnectionByPin (PAD_TYPE, pad);
+ sprintf (nodename, "%s-%s", element->Name[1].TextString, pad->Number);
+ netname = netnode_to_netname (nodename);
+/* Message("Netname: %s\n", netname->Name +2); */
+ if (netname)
+ {
+ strcpy (net, &netname->Name[2]);
+ CheckNetLength (net, aliaslist);
+ }
+ else
+ {
+ strcpy (net, "N/C");
+ }
+ IPCD356_WriteNet (fp, net);
+ }
+ END_LOOP; /* Pad. */
+
+ END_LOOP; /* Element. */
+
+ VIA_LOOP (PCB->Data);
+ if (!TEST_FLAG (VISITFLAG, via))
+ {
+ ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
+ ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
+ LookupConnectionByPin (PIN_TYPE, via);
+ strcpy (net, "N/C");
+ IPCD356_WriteNet (fp, net);
+ }
+ END_LOOP; /* Via. */
+
+ IPCD356_End (fp);
+ fclose (fp);
+ free (aliaslist);
+ ResetVisitPinsViasAndPads ();
+ ClearFlagOnLinesAndPolygons (true, FOUNDFLAG);
+ ClearFlagOnPinsViasAndPads (true, FOUNDFLAG);
+ return 0;
+}
+
+void
+IPCD356_End (FILE * fd)
+{
+ fprintf (fd, "999\n");
+}
+
+void
+ResetVisitPinsViasAndPads ()
+{
+ VIA_LOOP (PCB->Data);
+ CLEAR_FLAG (VISITFLAG, via);
+ END_LOOP; /* Via. */
+ ELEMENT_LOOP (PCB->Data);
+ PIN_LOOP (element);
+ CLEAR_FLAG (VISITFLAG, pin);
+ END_LOOP; /* Pin. */
+ PAD_LOOP (element);
+ CLEAR_FLAG (VISITFLAG, pad);
+ END_LOOP; /* Pad. */
+ END_LOOP; /* Element. */
+}
+
+int
+IPCD356_WriteAliases (FILE * fd, IPCD356_AliasList * aliaslist)
+{
+ int index;
+ int i;
+
+ index = 1;
+
+ for (i = 0; i < PCB->NetlistLib.MenuN; i++)
+ {
+ if (strlen (PCB->NetlistLib.Menu[i].Name + 2) > 14)
+ {
+ if (index == 1)
+ {
+ fprintf (fd, "C Netname Aliases Section\n");
+ }
+ aliaslist = AddAliasToList (aliaslist);
+ if (aliaslist == NULL)
+ {
+ return 1;
+ }
+ sprintf (aliaslist->Alias[index].NName, "NNAME%-5.5d", index);
+ strcpy (aliaslist->Alias[index].NetName, PCB->NetlistLib.Menu[i].Name + 2);
+
+ fprintf (fd, "P %s %-58.58s\n", aliaslist->Alias[index].NName,
+ aliaslist->Alias[index].NetName);
+ index++;
+ }
+ }
+ if (index > 1)
+ {
+ fprintf (fd, "C End Netname Aliases Section\nC \n");
+ }
+ return 0;
+}
+
+IPCD356_AliasList *
+CreateAliasList ()
+{
+ IPCD356_AliasList * aliaslist;
+
+ aliaslist = malloc (sizeof (IPCD356_AliasList)); /* Create an alias list. */
+ aliaslist->AliasN = 0; /* Initialize Number of Alias. */
+ return aliaslist;
+}
+
+IPCD356_AliasList *
+AddAliasToList (IPCD356_AliasList * aliaslist)
+{
+ aliaslist->AliasN++;
+ aliaslist->Alias = realloc (aliaslist->Alias,
+ sizeof (IPCD356_Alias) * (aliaslist->AliasN + 1));
+ if (aliaslist->Alias == NULL)
+ {
+ return NULL;
+ }
+ return aliaslist;
+}
+
+void
+CheckNetLength (char *net, IPCD356_AliasList * aliaslist)
+{
+ int i;
+
+ if (strlen (net) > 14)
+ {
+ for (i = 1; i <= aliaslist->AliasN; i++)
+ {
+ if (strcmp (net, aliaslist->Alias[i].NetName) == 0)
+ {
+ strcpy (net, aliaslist->Alias[i].NName);
+ }
+ }
+ }
+}
+
+int
+IPCD356_SanityCheck()
+{
+ ELEMENT_LOOP (PCB->Data);
+ if (element->Name[1].TextString == '\0')
+ {
+ Message("Error: Found unnamed element. All elements need to be named to create an IPC-D-356 netlist.\n");
+ return(1);
+ }
+ END_LOOP; /* Element. */
+ return(0);
+}
+
+static void
+IPCD356_do_export (HID_Attr_Val * options)
+{
+ int i;
+
+ if (!options)
+ {
+ IPCD356_get_export_options (0);
+
+ for (i = 0; i < NUM_OPTIONS; i++)
+ IPCD356_values[i] = IPCD356_options[i].default_val;
+
+ options = IPCD356_values;
+ }
+
+ IPCD356_filename = options[HA_IPCD356_filename].str_value;
+ if (!IPCD356_filename)
+ IPCD356_filename = "pcb-out.net";
+
+ IPCD356_Netlist ();
+}
+
+static void
+IPCD356_parse_arguments (int *argc, char ***argv)
+{
+ hid_register_attributes (IPCD356_options,
+ sizeof (IPCD356_options) / sizeof (IPCD356_options[0]));
+ hid_parse_command_line (argc, argv);
+}
+
+HID IPCD356_hid;
+
+void
+hid_ipcd356_init ()
+{
+ memset (&IPCD356_hid, 0, sizeof (HID));
+
+ common_nogui_init (&IPCD356_hid);
+
+ IPCD356_hid.struct_size = sizeof (HID);
+ IPCD356_hid.name = "IPC-D-356";
+ IPCD356_hid.description = "Exports a IPC-D-356 Netlist";
+ IPCD356_hid.exporter = 1;
+
+ IPCD356_hid.get_export_options = IPCD356_get_export_options;
+ IPCD356_hid.do_export = IPCD356_do_export;
+ IPCD356_hid.parse_arguments = IPCD356_parse_arguments;
+
+ hid_register_hid (&IPCD356_hid);
+
+}
+
+/* EOF */