[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: gEDA-user: help with pcb dsn plugin



I just posted this to the related bug tracker, but thought some people
that would be interested wouldn't be following that, so reposting
here:

I wanted try out this freerouting.net thing so went ahead and updated
this patch to work with the latest git head and nanometer awesomeness.

Here's what I did:

-- extensive style changes for my own sanity. There was inconsistent
style throughout (like all of pcb's code), so I chose the one I
personally like best (linux kernel style with indent of 4 instead of
8). :)

-- Brought all the handling of coordinates up to date with the new
Coord type and nm precision. There were a few places where dimensions
were being rounded to the nearest mil, etc. which would've been bad
for metric based boards. This has all been taken care of and appears
to be working in some simple tests. DSN files are now in mm units with
nm precision.

-- Removed the somewhat dubious code for finding the rotation of the
part copied over from bom.c. We don't have the original footprint
anyway, so the rotation was not being used. The code is still there in
bom.c if it is needed in the future.

-- Fixed some minor issues like a small memory leak, etc.

-- Fixed issues registering the action and updated config values to use Coord.

-- New line from the session file weren't clearing polygons.

-- Possibly some other stuff, I forget, I just went through the whole
thing top to bottom and fixed anything I saw weird.

Some things still not quite handled:

-- Existing polygons on the pcb don't make it into the dsn.

-- Parts rotated at non-orthogonal angles probably won't work since
rectangular pads won't be rotated correctly.

-- As noted in the bug report, there is no copyright/license notice
from the original authors.  Maybe some legal issues with the Specctra
file format as well (I doubt it though, the text-based file format
would be trivial to reverse-engineer even without  the spec).

-- Probably some other stuff.

It appears to be working with some early tests, and freerouting.net is
pretty awesome.

Jared

On Sun, Jun 12, 2011 at 12:45 PM, Josh Jordan <outerspaceman81@xxxxxxxxx> wrote:
>    I was able to fix the action problem and create a single patch, if
>    anyone is interested in using freerouting.net.  Turn on only the layers
>    you want routed on before exporting.
>    -Josh Jordan
>    --- On Sun, 6/12/11, Josh Jordan <outerspaceman81@xxxxxxxxx> wrote:
>
>      From: Josh Jordan <outerspaceman81@xxxxxxxxx>
>      Subject: gEDA-user: help with pcb dsn plugin
>      To: geda-user@xxxxxxxxxxxxxx
>      Date: Sunday, June 12, 2011, 12:14 PM
>
>        I made a dsn export/import plugin a few years back that I am trying
>    to
>        merge into latest git pcb version.   It works to export and the dsn
>    can
>        be routed with freerouting.net, and the import function appears in
>    the
>        menu, but the import action does not work.  The function name is
>        ActionLoadDsnFrom() but somehow during compilation it lists a
>        "LoaddsnFrom" in the list of actions.  It says "Unknown Action"
>    when I
>        try to use LoaddsnFrom or ActionLoadDsnFrom, or LoadDsnFrom.  Is
>    there
>        a way to list what actions exist in pcb?
>        I had to make 2 patches, the first one with "git diff" it only
>    shows
>        files that were changed.  The second patch is from "git add -i
>        /src/hid/dsn", "git commit" and "git format-patch -1" and it will
>    only
>        show files that were added.  If anyone knows how to make the patch
>    with
>        1 command that would also help.
>        Thanks,
>        Josh Jordan
>
>      -----Inline Attachment Follows-----
>
>    _______________________________________________
>    geda-user mailing list
>    [1]geda-user@xxxxxxxxxxxxxx
>    [2]http://www.seul.org/cgi-bin/mailman/listinfo/geda-user
>
> References
>
>   1. file://localhost/mc/compose?to=geda-user@xxxxxxxxxxxxxx
>   2. http://www.seul.org/cgi-bin/mailman/listinfo/geda-user
>
>
>
> _______________________________________________
> geda-user mailing list
> geda-user@xxxxxxxxxxxxxx
> http://www.seul.org/cgi-bin/mailman/listinfo/geda-user
>
>
From a0bb98376c96e91876bebdcc6d958c8a9f07d6e4 Mon Sep 17 00:00:00 2001
From: Jared Casper <jaredcasper@xxxxxxxxx>
Date: Thu, 15 Sep 2011 17:12:52 -0700
Subject: [PATCH] Add SPECCTRA dsn export and session file (.ses) import.

Original patch by Josh Jordan and Dan McMahill.
---
 configure.ac         |    2 +-
 src/Makefile.am      |   18 ++-
 src/gpcb-menu.res.in |    1 +
 src/hid/dsn/dsn.c    |  609 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/hid/dsn/dsn.h    |    3 +
 src/hid/dsn/hid.conf |    1 +
 src/pcb-menu.res.in  |    1 +
 7 files changed, 633 insertions(+), 2 deletions(-)
 create mode 100644 src/hid/dsn/dsn.c
 create mode 100644 src/hid/dsn/dsn.h
 create mode 100644 src/hid/dsn/hid.conf

diff --git a/configure.ac b/configure.ac
index a802790..197e325 100644
--- a/configure.ac
+++ b/configure.ac
@@ -436,7 +436,7 @@ esac
 
 AC_MSG_CHECKING([for which exporters to use])
 AC_ARG_WITH([exporters],
-[  --with-exporters=       Enable export devices: bom gerber gcode nelma png ps [[default=bom gerber gcode nelma png ps]]],
+[  --with-exporters=       Enable export devices: bom dsn gerber gcode nelma png ps [[default=bom dsn gerber gcode nelma png ps]]],
 [],[with_exporters=$hid_exporters])
 AC_MSG_RESULT([$with_exporters])
 for e in `echo $with_exporters | sed 's/,/ /g'`; do
diff --git a/src/Makefile.am b/src/Makefile.am
index 7adb424..095d58d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,7 +15,7 @@ HIDLIST = @HIDLIST@
 noinst_LIBRARIES = @HIDLIBS@
 EXTRA_LIBRARIES = \
 	libgtk.a liblesstif.a libbatch.a \
-	liblpr.a libgerber.a libbom.a libpng.a libps.a libnelma.a \
+	liblpr.a libgerber.a libbom.a libdsn.a libpng.a libps.a libnelma.a \
 	libgcode.a
 
 pcblib_DATA= \
@@ -187,6 +187,7 @@ BUILT_SOURCES = \
 	hid/gcode/gcode_lists.h \
 	hid/nelma/nelma_lists.h \
 	hid/ps/ps_lists.h \
+	hid/dsn/dsn_lists.h \
 	parse_y.h \
 	pcb-menu.h \
 	res_parse.h \
@@ -219,6 +220,7 @@ EXTRA_DIST= \
 	default_font \
 	$(srcdir)/hid/batch/hid.conf \
 	$(srcdir)/hid/bom/hid.conf \
+	$(srcdir)/hid/dsn/hid.conf \
 	$(srcdir)/hid/gcode/hid.conf \
 	$(srcdir)/hid/gerber/hid.conf \
 	$(srcdir)/hid/gtk/gui-icons-misc.data \
@@ -378,6 +380,20 @@ hid/batch/batch_lists.h : ${LIBBATCH_SRCS} Makefile
 	(for f in ${LIBBATCH_SRCS} ; do cat $(srcdir)/$$f ; done) | grep "^REGISTER" > $@.tmp
 	mv $@.tmp $@
 
+libdsn_a_CPPFLAGS = -I./hid/dsn
+
+LIBDSN_SRCS = \
+	hid/hidint.h \
+	hid/dsn/dsn.c \
+	hid/dsn/dsn.h
+libdsn_a_SOURCES = ${LIBDSN_SRCS} hid/dsn/dsn_lists.h
+
+hid/dsn/dsn_lists.h : ${LIBDSN_SRCS} Makefile
+	$(MKDIR_P) hid/dsn
+	true > $@
+	(for f in ${LIBDSN_SRCS} ; do cat $(srcdir)/$$f ; done) | grep "^REGISTER" > $@.tmp
+	mv $@.tmp $@
+
 libgerber_a_SOURCES = \
 	hid/hidint.h \
 	hid/gerber/gerber.c
diff --git a/src/gpcb-menu.res.in b/src/gpcb-menu.res.in
index 7e63811..f051f4c 100644
--- a/src/gpcb-menu.res.in
+++ b/src/gpcb-menu.res.in
@@ -57,6 +57,7 @@ MainMenu =
    {"Load layout data to paste-buffer" PasteBuffer(Clear) Load(LayoutTobuffer)}
    {"Load netlist file" Load(Netlist)}
    {"Load vendor resource file" LoadVendorFrom()}
+   {"Load external router session file" LoadDsnFrom()}
    -
    {"Save connection data of"
      {" a single element" GetXY(Click to set the element mark <>) Save(ElementConnections)}
diff --git a/src/hid/dsn/dsn.c b/src/hid/dsn/dsn.c
new file mode 100644
index 0000000..d27e0fb
--- /dev/null
+++ b/src/hid/dsn/dsn.c
@@ -0,0 +1,609 @@
+/*
+This program exports specctra .dsn files from geda .pcb files.
+By Josh Jordan and Dan McMahill, modified from bom.c
+  -- Updated to use Coord and other fixes by Jared Casper 16 Sep 2011
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "global.h"
+#include "data.h"
+#include "error.h"
+#include "misc.h"
+#include "gts.h"
+#include "rats.h"
+#include "buffer.h"
+#include "parse_l.h"
+#include "change.h"
+#include "draw.h"
+#include "resource.h"
+#include "set.h"
+#include "undo.h"
+#include "pcb-printf.h"
+#include "create.h"
+#include "polygon.h"
+
+#include "hid.h"
+#include "../hidint.h"
+
+#include "hid/common/draw_helpers.h"
+#include "hid/common/hidnogui.h"
+#include "hid/common/actions.h"
+#include "hid/common/hidinit.h"
+
+#include "dsn.h"
+
+#ifdef HAVE_LIBDMALLOC
+#include <dmalloc.h>
+#endif
+
+Coord trackwidth = 8; //user options defined in export dialog
+Coord clearance = 8;
+Coord viawidth = 45;
+Coord viadrill = 25;
+
+static HID_Attribute dsn_options[] = {
+  {"dsnfile", "SPECCTRA output file",
+   HID_String, 0, 0, {0, 0, 0}, 0, 0},
+#define HA_dsnfile 0
+  {"trackwidth", "track width in mils",
+   HID_Coord, MIL_TO_COORD(0), MIL_TO_COORD(100), {0, 0, 0, MIL_TO_COORD(8)}, 0, 0},
+#define HA_trackwidth 1
+  {"clearance", "clearance in mils",
+   HID_Coord, MIL_TO_COORD(0), MIL_TO_COORD(100), {0, 0, 0, MIL_TO_COORD(8)}, 0, 0},
+#define HA_clearance 2
+  {"viawidth", "via width in mils",
+   HID_Coord, MIL_TO_COORD(0), MIL_TO_COORD(100), {0, 0, 0, MIL_TO_COORD(27)}, 0, 0},
+#define HA_viawidth 3
+  {"viadrill", "via drill diameter in mils",
+   HID_Coord, MIL_TO_COORD(0), MIL_TO_COORD(100), {0, 0, 0, MIL_TO_COORD(15)}, 0, 0},
+#define HA_viadrill 4
+};
+
+#define NUM_OPTIONS (sizeof(dsn_options)/sizeof(dsn_options[0]))
+REGISTER_ATTRIBUTES (dsn_options)
+  static HID_Attr_Val dsn_values[NUM_OPTIONS];
+
+static const char *dsn_filename;
+
+static HID_Attribute *
+dsn_get_export_options (int *n)
+{
+    static char *last_dsn_filename = 0;
+    if (PCB) {
+        derive_default_filename(PCB->Filename, &dsn_options[HA_dsnfile], ".dsn", &last_dsn_filename);
+    }
+    if (n)
+        *n = NUM_OPTIONS;
+    return dsn_options;
+}
+
+
+/* this function is mostly ripped from bom.c */
+static PointType
+get_centroid(ElementType *element)
+{
+    PointType centroid;
+    double sumx = 0.0, sumy = 0.0;
+    int pin_cnt = 0;
+
+    PIN_LOOP (element); {
+        sumx += (double)pin->X;
+        sumy += (double)pin->Y;
+        pin_cnt++;
+    } END_LOOP;
+
+    PAD_LOOP (element); {
+        sumx += (pad->Point1.X + pad->Point2.X) / 2.0;
+        sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0;
+        pin_cnt++;
+    } END_LOOP;
+
+    if (pin_cnt > 0) {
+        centroid.X = sumx / (double) pin_cnt;
+        centroid.Y = PCB->MaxHeight - (sumy / (double) pin_cnt);
+    } else {
+        centroid.X = 0;
+        centroid.Y = 0;
+    }
+    return centroid;
+}
+
+bool is_layer_group_active[MAX_LAYER];
+GList *layerlist = NULL; //contain routing layers
+int layersN; //global var holding how many layers are found
+
+static void
+print_structure(FILE *fp)
+{
+    /* check which layers are active first */
+    int i;
+    int group;
+    fprintf(fp, "  (structure\n");
+    layersN = 0;
+    for (group = 0; group < max_group; group++) {
+        for (i = 0; i < PCB->LayerGroups.Number[group]; i++) {
+            /* layer must be 1) not silk (ie, < max_group) and 2) on */
+            if ((PCB->LayerGroups.Entries[group][i] < max_group) &&
+                PCB->Data->Layer[PCB->LayerGroups.Entries[group][i]].On)
+            {
+                layersN++;
+                is_layer_group_active[group] = true;
+                GROUP_LOOP(PCB->Data, group); {
+                    layerlist = g_list_insert(layerlist, layer, group);
+                    break;
+                } END_LOOP;
+                break;
+            } else {
+                is_layer_group_active[group] = false;
+            }
+        }
+    }
+
+    for(i = 0; i < max_group; i++) {
+        if(is_layer_group_active[i]) {
+            int ni;
+            char *layeropts;
+            LayerTypePtr layer;
+            layeropts = g_strdup_printf("(type signal)");
+            layer = g_list_nth_data(layerlist, i);
+            /* see if layer has same name as a net and make it a power layer */
+            //loop thru all nets
+            for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) {
+                char *nname;
+                nname = PCB->NetlistLib.Menu[ni].Name + 2;
+                if (!strcmp(layer->Name, nname)) {
+                    g_free(layeropts);
+                    layeropts = g_strdup_printf("(type power) (use_net %s)", layer->Name);
+                }
+            }
+            fprintf(fp, "    (layer %s\n", layer->Name);
+            fprintf(fp, "      %s\n", layeropts);
+            fprintf(fp, "      (property\n");
+            fprintf(fp, "        (index %d)\n", i);
+            fprintf(fp, "      )\n");fprintf(fp, "    )\n");
+            g_free(layeropts);
+        }
+    }
+
+    /* PCB outline */
+    pcb_fprintf(fp, "    (boundary\n");
+    pcb_fprintf(fp, "      (rect pcb 0.0 0.0 %.6mm %.6mm)\n", PCB->MaxWidth, PCB->MaxHeight);
+    pcb_fprintf(fp, "    )\n");
+
+    pcb_fprintf(fp, "    (via via_%ld_%ld)\n", viawidth, viadrill);
+
+    /* DRC rules */
+    pcb_fprintf(fp, "    (rule\n");
+    pcb_fprintf(fp, "      (width %mm)\n", trackwidth);
+    pcb_fprintf(fp, "      (clear %mm)\n", clearance);
+    pcb_fprintf(fp, "      (clear %mm (type wire_area))\n", clearance);
+    pcb_fprintf(fp, "      (clear %mm (type via_smd via_pin))\n", clearance);
+    pcb_fprintf(fp, "      (clear %mm (type smd_smd))\n", clearance);
+    pcb_fprintf(fp, "      (clear %mm (type default_smd))\n", clearance);
+    pcb_fprintf(fp, "    )\n  )\n");
+}
+
+static void
+print_placement(FILE *fp)
+{
+  fprintf(fp, "  (placement\n");
+  ELEMENT_LOOP (PCB->Data); {
+      char *ename;
+      PointType ecentroid = get_centroid(element);
+      char* side = TEST_FLAG(ONSOLDERFLAG, element) ? "back" : "front";
+      ename = g_strdup(NAMEONPCB_NAME(element));
+      if(!ename)
+          ename = g_strdup_printf("null");
+      pcb_fprintf(fp, "    (component %d\n", element->ID);
+      pcb_fprintf(fp, "      (place %s %.6mm %.6mm %s 0 (PN 0))\n", ename, ecentroid.X, ecentroid.Y, side);
+      pcb_fprintf(fp, "    )\n");
+      g_free(ename);
+  } END_LOOP;
+  VIA_LOOP (PCB->Data); { //add mounting holes
+      pcb_fprintf(fp, "    (component %d\n", via->ID);
+      pcb_fprintf(fp, "      (place %d %.6mm %.6mm %s 0 (PN 0))\n", via->ID, via->X, (PCB->MaxHeight - via->Y), "front");
+      pcb_fprintf(fp, "    )\n");
+  } END_LOOP;
+  fprintf(fp, "  )\n");
+}
+
+static void
+print_library(FILE *fp)
+{
+    GList *pads = NULL, *iter; //contain unique pad names
+    gchar *padstack;
+    fprintf(fp, "  (library\n");
+    ELEMENT_LOOP (PCB->Data); {
+        int partside = TEST_FLAG(ONSOLDERFLAG, element) ? layersN-1 : 0; //0 for component side, highest for solder side
+        int partsidesign = TEST_FLAG(ONSOLDERFLAG, element) ? -1 : 1;
+        PointType centroid = get_centroid(element);
+        fprintf(fp, "    (image %ld\n", element->ID); //map every element by ID
+        /* loop thru pins and pads to add to image */
+        PIN_LOOP (element); {
+            Coord ty;
+            Coord pinthickness;
+            Coord lx, ly; //hold local pin coordinates
+            ty = PCB->MaxHeight - pin->Y;
+            pinthickness = pin->Thickness;
+            if (TEST_FLAG(SQUAREFLAG, pin))
+                padstack = g_strdup_printf("Th_square_%ld", pinthickness);
+            else
+                padstack = g_strdup_printf("Th_round_%ld", pinthickness);
+            lx = (pin->X - centroid.X) * partsidesign;
+            ly = (centroid.Y - ty) * -1;
+
+            if (!pin->Number) { //if pin is null just make it a keepout
+                for(GList *iter = layerlist; iter; iter = g_list_next(iter)) {
+                    LayerTypePtr lay = iter->data;
+                    pcb_fprintf(fp, "      (keepout \"\" (circle %s %.6mm %.6mm %.6mm))\n",
+                                lay->Name, pinthickness, lx, ly);
+                }
+            }
+            else {
+                pcb_fprintf(fp, "      (pin %s %s %.6mm %.6mm)\n", padstack, pin->Number, lx, ly);
+            }
+
+            if (!g_list_find_custom(pads, padstack, (GCompareFunc)strcmp))
+                pads = g_list_append(pads, padstack);
+            else
+                g_free(padstack);
+        } END_LOOP;
+
+        PAD_LOOP (element); {
+            Coord xlen, ylen, xc, yc, p1y, p2y;
+            Coord lx, ly; //store local coordinates for pins
+            p1y = PCB->MaxHeight - pad->Point1.Y;
+            p2y = PCB->MaxHeight - pad->Point2.Y;
+            /* pad dimensions are unusual-
+               the width is thickness and length is point difference plus thickness */
+            xlen = ABS(pad->Point1.X - pad->Point2.X);
+            if (xlen == 0)
+            {
+                xlen = pad->Thickness;
+                ylen = ABS(p1y - p2y) + pad->Thickness;
+            } else {
+                ylen = pad->Thickness;
+                xlen += pad->Thickness;
+            }
+            xc = (pad->Point1.X + pad->Point2.X)/2;
+            yc = (p1y + p2y)/2;
+            lx = (xc - centroid.X) * partsidesign;
+            ly = (centroid.Y - yc) * -1;
+            padstack = g_strdup_printf("Smd_rect_%ldx%ld", xlen, ylen);
+            gui->log("%s <- %ld, %ld\n", padstack, xlen, ylen);
+
+            if (!pad->Number) { //if pad is null just make it a keepout
+                LayerTypePtr lay;
+                lay = g_list_nth_data(layerlist, partside);
+                pcb_fprintf(fp, "      (keepout \"\" (rect %s %.6mm %.6mm %.6mm %.6mm))\n",
+                            lay->Name, lx-xlen/2, ly-ylen/2, lx+xlen/2, ly+ylen/2);
+            } else {
+                pcb_fprintf(fp, "      (pin %s %s %.6mm %.6mm)\n",
+                            padstack, pad->Number, lx, ly);
+            }
+            if (!g_list_find_custom(pads, padstack, (GCompareFunc)strcmp))
+                pads = g_list_append(pads, padstack);
+            else
+                g_free(padstack);
+        } END_LOOP;
+        fprintf(fp, "    )\n");
+    }  END_LOOP;
+
+    VIA_LOOP (PCB->Data); { //add mounting holes and vias
+        fprintf(fp, "    (image %ld\n", via->ID); //map every via by ID
+        /* for mounting holes, clearance is added to thickness for higher total clearance */
+        padstack = g_strdup_printf("Th_round_%ld", via->Thickness + via->Clearance);
+        fprintf(fp, "      (pin %s 1 0 0)\n", padstack); //only 1 pin, 0,0 puts it right on component placement spot
+        fprintf(fp, "    )\n");
+        if (!g_list_find_custom(pads, padstack, (GCompareFunc)strcmp))
+            pads = g_list_append(pads, padstack);
+        else
+            g_free(padstack);
+    } END_LOOP;
+
+    /* loop thru padstacks and define them all */
+    for(iter = pads; iter; iter = g_list_next(iter)) {
+        Coord dim1, dim2;
+        padstack = iter->data;
+        fprintf(fp, "    (padstack %s\n", padstack);
+
+        /* print info about pad here */
+        if (sscanf(padstack, "Smd_rect_%ldx%ld", &dim1, &dim2) == 2) { //then pad is smd
+            gui->log("%s -> %ld, %ld\n", padstack, dim1, dim2);
+            pcb_fprintf(fp, "      (shape (rect component %.6mm %.6mm %.6mm %.6mm))\n",
+                     dim1/-2, dim2/-2, dim1/2, dim2/2);
+        } else if (sscanf (padstack, "Th_square_%ld", &dim1) == 1) {
+            pcb_fprintf(fp, "      (shape (rect signal % %.6mm %.6mm %.6mm))\n",
+                     dim1/-2, dim1/-2, dim1/2, dim1/2);
+        } else {
+            sscanf(padstack, "Th_round_%ld", &dim1);
+            pcb_fprintf(fp, "      (shape (circle signal %.6mm))\n", dim1);
+        }
+        fprintf(fp, "      (attach off)\n");
+        fprintf(fp, "    )\n");
+    }
+
+    /* add padstack for via */
+    pcb_fprintf(fp, "    (padstack via_%ld_%ld\n", viawidth, viadrill);
+    pcb_fprintf(fp, "      (shape (circle signal %.6mm))\n", viawidth);
+    pcb_fprintf(fp, "      (attach off)\n    )\n");
+    pcb_fprintf(fp, "  )\n");
+    g_list_foreach(pads, (GFunc)g_free, NULL);
+    g_list_free(pads);
+}
+
+static void
+print_network(FILE *fp)
+{
+    int ni, nei;
+    fprintf(fp, "  (network\n");
+    for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) {
+        fprintf(fp, "    (net %s\n      (pins", PCB->NetlistLib.Menu[ni].Name + 2);
+        for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) {
+            fprintf(fp, " %s", PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry);
+        }
+        fprintf(fp, ")\n    )\n");
+    }
+
+    fprintf(fp, "    (class geda_default");
+    for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) {
+        fprintf(fp, " %s", PCB->NetlistLib.Menu[ni].Name + 2);
+    }
+    pcb_fprintf(fp, "\n      (circuit\n        (use_via via_%ld_%ld)\n      )\n",
+                viawidth, viadrill);
+    pcb_fprintf(fp, "      (rule (width %.6mm))\n    )\n  )\n", trackwidth);
+}
+
+static void
+print_wires (FILE *fp)
+{
+    GList* iter;
+    LayerTypePtr lay;
+    fprintf(fp, "    (wiring\n");
+
+    for (iter = layerlist; iter; iter = g_list_next(iter)) {
+        lay = iter->data;
+        LINE_LOOP(lay); {
+            pcb_fprintf(fp, "        (wire (path %s %.6mm %.6mm %.6mm %.6mm %.6mm)\n",
+                        lay->Name, line->Thickness, line->Point1.X,
+                        (PCB->MaxHeight - line->Point1.Y), line->Point2.X,
+                        (PCB->MaxHeight - line->Point2.Y));
+            fprintf(fp, "            (type protect))\n");
+        } END_LOOP;
+    }
+    fprintf(fp, "\n    )\n)\n"); //close all braces
+}
+
+static int
+PrintSPECCTRA (void)
+{
+  FILE *fp;
+  /* Print out the dsn .dsn file. */
+  fp = fopen(dsn_filename, "w");
+  if (!fp) {
+      gui->log ("Cannot open file %s for writing\n", dsn_filename);
+      return 1;
+  }
+
+  /* pcb [required] */
+  fprintf(fp, "(pcb %s\n", ((PCB->Name) && *(PCB->Name) ? (PCB->Name) : "notnamed"));
+
+  /* parser descriptor [optional] */
+  fprintf(fp, "  (parser\n");
+  fprintf(fp, "    (string_quote \")\n");
+  fprintf(fp, "    (space_in_quoted_tokens on)\n");
+  fprintf(fp, "    (host_cad \"gEDA PCB\")\n");
+  fprintf(fp, "    (host_version \"%s\")\n", VERSION);
+  fprintf(fp, "  )\n");
+
+  /* capacitance resolution descriptor [optional] */
+
+  /* conductance resolution descriptor [optional] */
+
+  /* current resolution descriptor [optional] */
+
+  /* inductance resolution descriptor [optional] */
+
+  /* resistance resolution descriptor [optional] */
+
+  /* resolution descriptor [optional] */
+  fprintf(fp, "  (resolution mm 1000000)\n");
+
+  /* time resolution descriptor [optional] */
+
+  /* voltage resolution descriptor [optional] */
+
+  /* unit descriptor [optional] */
+
+  /* structure descriptor [required] */
+  print_structure(fp);
+
+  /* placement descriptor [optional] */
+  print_placement(fp);
+
+  /* library descriptor [required] */
+  print_library(fp);
+
+  /* floor plan descriptor [optional] */
+
+  /* part library descriptor [optional] */
+
+  /* network descriptor [required] */
+  print_network(fp);
+
+  /* wiring descriptor [optional] */
+  print_wires(fp);
+
+  /* color descriptor [optional] */
+
+  fclose (fp);
+
+  return (0);
+}
+
+
+static void
+dsn_do_export(HID_Attr_Val *options)
+{
+  int i;
+  if (!options) {
+      dsn_get_export_options (0);
+      for (i = 0; i < NUM_OPTIONS; i++)
+          dsn_values[i] = dsn_options[i].default_val;
+      options = dsn_values;
+  }
+  dsn_filename = options[HA_dsnfile].str_value;
+  if (!dsn_filename)
+      dsn_filename = "pcb-out.dsn";
+
+  trackwidth = options[HA_trackwidth].coord_value;
+  clearance = options[HA_clearance].coord_value;
+  viawidth = options[HA_viawidth].coord_value;
+  viadrill = options[HA_viadrill].coord_value;
+  PrintSPECCTRA();
+}
+
+static void
+dsn_parse_arguments(int *argc, char ***argv)
+{
+    hid_register_attributes(dsn_options,
+                             sizeof(dsn_options) / sizeof(dsn_options[0]));
+    hid_parse_command_line(argc, argv);
+}
+
+/* dsn import section below */
+/* dsn name */
+#define FREE(x) if((x) != NULL) { free (x); (x) = NULL; }
+
+static const char load_dsn_syntax[] = "LoadDsnFrom(filename)";
+
+static const char load_dsn_help[] =
+    "Loads the specified dsn resource file.";
+
+/* %start-doc actions LoaddsnFrom
+
+@cindex Specctra routed import
+@findex LoadDsnFrom()
+
+@table @var
+@item filename
+Name of the dsn resource file.  If not specified, the user will
+be prompted to enter one.
+@end table
+
+%end-doc */
+
+int
+ActionLoadDsnFrom(int argc, char **argv, Coord x, Coord y)
+{
+    char *fname = NULL;
+    static char *default_file = NULL;
+    char str[200];
+    FILE *fp;
+    int ret;
+    Coord dim1, dim2, x0 = 0, y0 = 0, x1, y1;
+    Coord linethick = 0, lineclear, viadiam, viadrill;
+    char lname[200];
+    LayerType *rlayer = NULL;
+    LineTypePtr line = NULL;
+
+    fname = argc ? argv[0] : 0;
+
+    if (!fname || !*fname) {
+        fname = gui->fileselect (_("Load dsn routing session Resource File..."),
+                                 _("Picks a dsn session resource file to load.\n"
+                                   "This file could be generated by freeroute.net\n"),
+                                 default_file, ".ses", "ses",
+                                 HID_FILESELECT_READ);
+        if (fname == NULL)
+            AFAIL (load_dsn);
+        if (default_file != NULL) {
+            free (default_file);
+            default_file = NULL;
+        }
+
+        if (fname && *fname)
+            default_file = strdup(fname);
+    }
+
+    lineclear = PCB->RouteStyle[0].Keepaway * 2;
+    fp = fopen(fname, "r");
+    if(!fp) return 1; // bail out if file not found
+    while(fgets(str, sizeof(str), fp) != NULL) {
+        // strip trailing '\n' if it exists
+        int len = strlen(str)-1;
+        if (str[len] == '\n')
+            str[len] = 0;
+        ret = sscanf(str, "          (path %s %ld", lname, &dim1);
+        if (ret == 2) {
+            rlayer = 0;
+            LAYER_LOOP(PCB->Data, max_group) {
+                if (!strcmp(layer->Name, lname))
+                    rlayer = layer;
+            } END_LOOP;
+            linethick = dim1;
+            x0 = 0;
+            y0 = 0;
+        }
+        ret = sscanf(str, "            %ld %ld", &dim1, &dim2);
+        if (ret == 2) {
+            x1 = dim1;
+            y1 = dim2;
+            if (x0 != 0 || y0 != 0) {
+                line = CreateDrawnLineOnLayer(rlayer, x0, PCB->MaxHeight - y0,
+                                              x1, PCB->MaxHeight - y1,
+                                              linethick, lineclear,
+                                              MakeFlags(AUTOFLAG | CLEARLINEFLAG));
+                ClearFromPolygon(PCB->Data, LINE_TYPE, rlayer, line);
+            }
+            x0 = x1;
+            y0 = y1;
+        }
+        ret = sscanf(str, "        (via via_%ld_%ld %ld %ld",
+                     &viadiam, &viadrill, &dim1, &dim2);
+        if (ret == 4) {
+            CreateNewVia(PCB->Data, dim1, PCB->MaxHeight - dim2, viadiam,
+                         lineclear, 0, viadrill, 0, MakeFlags(AUTOFLAG));
+        }
+    }
+    fclose(fp);
+    return 0;
+}
+
+HID_Action dsn_action_list[] = {
+    {"LoadDsnFrom", 0, ActionLoadDsnFrom, load_dsn_help, load_dsn_syntax}
+};
+
+REGISTER_ACTIONS(dsn_action_list)
+
+#include "dolists.h"
+
+HID dsn_hid;
+
+void
+hid_dsn_init()
+{
+    memset(&dsn_hid, 0, sizeof(HID));
+    common_nogui_init(&dsn_hid);
+
+    dsn_hid.struct_size = sizeof(HID);
+    dsn_hid.name = "dsn";
+    dsn_hid.description = "Exports DSN format";
+    dsn_hid.exporter = 1;
+    dsn_hid.get_export_options = dsn_get_export_options;
+    dsn_hid.do_export = dsn_do_export;
+    dsn_hid.parse_arguments = dsn_parse_arguments;
+    hid_register_hid(&dsn_hid);
+#include "dsn_lists.h"
+}
+
+
diff --git a/src/hid/dsn/dsn.h b/src/hid/dsn/dsn.h
new file mode 100644
index 0000000..860631a
--- /dev/null
+++ b/src/hid/dsn/dsn.h
@@ -0,0 +1,3 @@
+/* $Id$ */
+
+extern HID dsn_hid;
diff --git a/src/hid/dsn/hid.conf b/src/hid/dsn/hid.conf
new file mode 100644
index 0000000..7be6c4c
--- /dev/null
+++ b/src/hid/dsn/hid.conf
@@ -0,0 +1 @@
+type=export
diff --git a/src/pcb-menu.res.in b/src/pcb-menu.res.in
index 7e6e8bd..de603af 100644
--- a/src/pcb-menu.res.in
+++ b/src/pcb-menu.res.in
@@ -38,6 +38,7 @@ MainMenu =
    {"Load layout data to paste-buffer" PasteBuffer(Clear) Load(LayoutTobuffer)}
    {"Load netlist file" Load(Netlist)}
    {"Load vendor resource file" LoadVendor()}
+   {"Load external router session file" LoadDsnFrom()}
    {"Print layout..." Print()}
    {"Export layout..." Export()}
    {"Calibrate Printer..." PrintCalibrate()}
-- 
1.7.6.1


_______________________________________________
geda-user mailing list
geda-user@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-user