/* Copyright 2008 Ronald S. Burkey This file is part of yaAGC. yaAGC 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. yaAGC 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 yaAGC; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Filename: EagleJoinNetlists.c Purpose: To join netlists from individual schematic pages created by the Eagle Lite freeware version into a single netlist for the complete set of pages. Mod history: 2008-01-10 RSB Created. 2008-01-13 RSB Force DOS end-of-line style. Nets with names like N?something are assumed to have been auto-created by Eagle, and are distinct on different sheets even if the "something" is the same. All others nets are assumed to have been named by the designer, and connected across pages if the names are the same. Actually, this "page joining" capability turns out to have been kind of useless for the Block I designs (for which the program was created), but I won't bother to remove it. A more useful way of thinking of this utility is that rather than being an Eagle "page joiner" it is a converter from an Eagle wirelist to a Protel TraxEdit netlist. */ #include #include #include #define MAX_NETNAME_SIZE 65 #define MAX_NODENAME_SIZE 33 #define MAX_NODES 32768 typedef struct { int AlreadyOutput; char NetName[MAX_NETNAME_SIZE]; char NodeName[MAX_NODENAME_SIZE]; } Node_t; static Node_t Nodes[MAX_NODES]; static int NumNodes = 0; static char s[257]; // This function matches the reference designator to a pattern, and // translates pin numbers. For example, for capacitors ("C*") we might // want pin number '+' to translate to pin '1' and pin number '-' to // translate to pin '2'. typedef struct { char *RefdPrefix; int RefdPrefixSize; char *OldPadNumber; char *NewPadNumber; } Translate_t; static Translate_t Translations[] = { { "C", 1, "+", "1" }, { "C", 1, "-", "2" }, { "D", 1, "K", "1" }, { "D", 1, "A", "2" }, { "LED", 3, "K", "1" }, { "LED", 3, "A", "2" } }; static NumTranslations = sizeof (Translations) / sizeof (Translate_t); static void TranslatePadNumber (char *Refd, char *PadNumber) { int i; for (i = 0; i < NumTranslations; i++) if (!strncmp (Refd, Translations[i].RefdPrefix, Translations[i].RefdPrefixSize)) if (isdigit (Refd[Translations[i].RefdPrefixSize])) if (!strcmp (PadNumber, Translations[i].OldPadNumber)) { strcpy (PadNumber, Translations[i].NewPadNumber); break; } } static int ProcessSheet (FILE *fin, int SheetNum, char *Filename) { int i, Line = 1; char NetName[MAX_NETNAME_SIZE], Refd[MAX_NODENAME_SIZE], PadNum[MAX_NODENAME_SIZE], PinName[MAX_NODENAME_SIZE], SheetDummy[MAX_NODENAME_SIZE]; // Skip past the file header. s[sizeof (s) - 1] = 0; while (1) { if (NULL == fgets (s, sizeof (s) - 1, fin)) { printf ("%s, %d: No header\r\n", Filename, Line); return (1); } Line++; if (!strncmp (s, "Net ", 4)) break; } if (NULL == fgets (s, sizeof (s) - 1, fin)) { printf ("%s, %d: No data\r\n", Filename, Line); return (1); } Line++; // Loop on the nets while (1) { // Yes, that's right, there's no error checking on the // input string sizes. // First line of the net differs from the others, in that // it contains the net name. if (NULL == fgets (s, sizeof (s) - 1, fin)) break; // blank line at end of file. Line++; i = sscanf (s, "%s%s%s%s%s", NetName, Refd, PadNum, PinName, SheetDummy); if (i <= 0) break; if (i != 5) { printf ("\"%s\" (%d)\r\n", s, i); printf ("%s, %d: Corrupted file.\r\n", Filename, Line); return (1); } TranslatePadNumber (Refd, PadNum); if (!strncmp (NetName, "N$", 2)) { sprintf (s, "%s-%d", NetName, SheetNum); strcpy (NetName, s); } if (NumNodes >= MAX_NODES) { printf ("%s, %d: Too many nodes\r\n", Filename, Line); return (1); } Nodes[NumNodes].AlreadyOutput = 0; strcpy (Nodes[NumNodes].NetName, NetName); sprintf (Nodes[NumNodes].NodeName, "%s-%s", Refd, PadNum); NumNodes++; // Now fetch all the remaining lines of the net. while (1) { if (NULL == fgets (s, sizeof (s) - 1, fin)) break; // Blank line at end of net. Line++; i = sscanf (s, "%s%s%s%s", Refd, PadNum, PinName, SheetDummy); if (i <= 0) break; if (i != 4) { printf ("\"%s\" (%d)\r\n", s, i); printf ("%s, %d: Corrupted file.\r\n", Filename, Line); return (1); } TranslatePadNumber (Refd, PadNum); if (NumNodes >= MAX_NODES) { printf ("%s, %d: Too many nodes\r\n", Filename, Line); return (1); } Nodes[NumNodes].AlreadyOutput = 0; strcpy (Nodes[NumNodes].NetName, NetName); sprintf (Nodes[NumNodes].NodeName, "%s-%s", Refd, PadNum); NumNodes++; } } return (0); } int main (int argc, char *argv[]) { int i, j; FILE *fin; if (argc < 2) { printf ("USAGE:\r\n"); printf ("\tEagleJoinNetlists Sheet1 [Sheet2 [Sheet3 ...]] >Netlist\r\n"); return (1); } // Process all of the netlist data. for (i = 1; i < argc; i++) { fin = fopen (argv[i], "r"); if (fin == NULL) { printf ("File \"%s\" does not exist.\r\n", argv[i]); return (1); } if (ProcessSheet (fin, i, argv[i])) return (1); fclose (fin); } // Output the merged netlist. for (i = 0; i < NumNodes; i++) { // Find next node that hasn't already been output. for (; i < NumNodes; i++) { if (!Nodes[i].AlreadyOutput) break; } if (i >= NumNodes) break; printf ("(\r\n"); printf ("%s\r\n", Nodes[i].NetName); // Now find all of the nodes that match this netname, // output them, and mark them. for (j = i; j < NumNodes; j++) { if (!Nodes[j].AlreadyOutput && !strcmp (Nodes[i].NetName, Nodes[j].NetName)) { printf ("%s\r\n", Nodes[j].NodeName); Nodes[j].AlreadyOutput = 1; } } printf (")\r\n"); } return (0); }