[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
gEDA-user: dsn exporter
This exporter outputs a .dsn file for opening with freeroute.net. It
only works on 2 layer designs so far.
I did not start writing an importer for it yet, if anyone has
suggestions on the architecture of this I will listen. (.cmd file?)
I will be out of town for the next 10 days and then I will work on the
importer.
To install it, make a specctra directory in the hid directory, put
this file in it, a copy of hid.conf, make a change to makefile.am in
/src, and make install again.
/*
This program exports specctra .dsn files from geda .pcb files.
By Josh Jordan
*/
#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 "hid.h"
#include "../hidint.h"
#ifdef HAVE_LIBDMALLOC
#include <dmalloc.h>
#endif
static HID_Attribute specctra_options[] = {
{"specctrafile", "SPECCTRA output file",
HID_String, 0, 0, {0, 0, 0}, 0, 0},
#define HA_specctrafile 0
{"trackwidth", "default track width in mils",
HID_Integer, 0, 0, {0, 0, 0}, 0, 0},
#define HA_trackwidth 1
};
#define NUM_OPTIONS (sizeof(specctra_options)/sizeof(specctra_options[0]))
static HID_Attr_Val specctra_values[NUM_OPTIONS];
static char *specctra_filename;
typedef struct _StringList
{
char *str;
struct _StringList *next;
} StringList;
typedef struct _SpecctraList
{
char *descr;
char *value;
int num;
StringList *refdes;
struct _SpecctraList *next;
} SpecctraList;
static HID_Attribute *
specctra_get_export_options (int *n)
{
static char *last_specctra_filename = 0;
if (PCB) {
derive_default_filename(PCB->Filename, &specctra_options[HA_specctrafile], ".dsn", &last_specctra_filename);
}
if (n)
*n = NUM_OPTIONS;
return specctra_options;
}
static char *
CleanSPECCTRAString (char *in)
{
char *out;
int i;
if ((out = malloc ((strlen (in) + 1) * sizeof (char))) == NULL)
{
fprintf (stderr, "Error: CleanSPECCTRAString() malloc() failed\n");
exit (1);
}
/*
* copy over in to out with some character conversions.
* Go all the way to then end to get the terminating \0
*/
for (i = 0; i <= strlen (in); i++)
{
switch (in[i])
{
case '"':
out[i] = '\'';
break;
default:
out[i] = in[i];
}
}
return out;
}
static double
xyToAngle (double x, double y)
{
double theta;
if ((x > 0.0) && (y >= 0.0))
theta = 180.0;
else if ((x <= 0.0) && (y > 0.0))
theta = 90.0;
else if ((x < 0.0) && (y <= 0.0))
theta = 0.0;
else if ((x >= 0.0) && (y < 0.0))
theta = 270.0;
else
{
theta = 0.0;
Message ("xyToAngle(): unable to figure out angle of element\n"
" because the pin is at the centroid of the part.\n"
" This is a BUG!!!\n"
" Setting to %g degrees\n", theta);
}
return (theta);
}
typedef struct {
double centx;
double centy;
int rot;
} CentroidRotation;
/* this function is mostly ripped from bom.c
it gives only absolute rotation, it must be
compared to the absolute rotation of the library part*/
static CentroidRotation
get_rotation_and_centroid (ElementType *element){
CentroidRotation centrot;
int found_pin1;
int found_pin2;
int pin_cnt;
double x, y, theta = 0.0, user_x, user_y;
double pin1x = 0.0, pin1y = 0.0, pin1angle = 0.0;
double pin2x = 0.0, pin2y = 0.0, pin2angle;
double sumx, sumy;
/* initialize our pin count and our totals for finding the centriod */
pin_cnt = 0;
sumx = 0.0;
sumy = 0.0;
found_pin1 = 0;
found_pin2 = 0;
/*
* iterate over the pins and pads keeping a running count of how
* many pins/pads total and the sum of x and y coordinates
*
* While we're at it, store the location of pin/pad #1 and #2 if
* we can find them
*/
PIN_LOOP (element);
{
sumx += (double) pin->X;
sumy += (double) pin->Y;
pin_cnt++;
if (NSTRCMP (pin->Number, "1") == 0)
{
pin1x = (double) pin->X;
pin1y = (double) pin->Y;
pin1angle = 0.0; /* pins have no notion of angle */
found_pin1 = 1;
}
else if (NSTRCMP (pin->Number, "2") == 0)
{
pin2x = (double) pin->X;
pin2y = (double) pin->Y;
pin2angle = 0.0; /* pins have no notion of angle */
found_pin2 = 1;
}
}
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++;
if (NSTRCMP (pad->Number, "1") == 0)
{
pin1x = (double) (pad->Point1.X + pad->Point2.X) / 2.0;
pin1y = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0;
/*
* NOTE: We swap the Y points because in PCB, the Y-axis
* is inverted. Increasing Y moves down. We want to deal
* in the usual increasing Y moves up coordinates though.
*/
pin1angle = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y,
pad->Point2.X - pad->Point1.X);
found_pin1 = 1;
}
else if (NSTRCMP (pad->Number, "2") == 0)
{
pin2x = (double) (pad->Point1.X + pad->Point2.X) / 2.0;
pin2y = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0;
pin2angle = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y,
pad->Point2.X - pad->Point1.X);
found_pin2 = 1;
}
}
END_LOOP;
if (pin_cnt > 0)
{
x = sumx / (double) pin_cnt;
y = sumy / (double) pin_cnt;
if (found_pin1)
{
/* recenter pin #1 onto the axis which cross at the part
centroid */
pin1x -= x;
pin1y -= y;
pin1y = -1.0 * pin1y;
/* if only 1 pin, use pin 1's angle */
if (pin_cnt == 1)
theta = pin1angle;
else
{
/* if pin #1 is at (0,0) use pin #2 for rotation */
if ((pin1x == 0.0) && (pin1y == 0.0))
{
if (found_pin2)
theta = xyToAngle (pin2x, pin2y);
else
{
Message
("SPECCTRA EXPORTER: unable to figure out angle of element\n"
" %s because pin #1 is at the centroid of the part.\n"
" and I could not find pin #2's location\n"
" Setting to %g degrees\n",
UNKNOWN (NAMEONPCB_NAME (element)), theta);
}
}
else
theta = xyToAngle (pin1x, pin1y);
}
}
/* we did not find pin #1 */
else
{
theta = 0.0;
Message
("SPECCTRA EXPORTER: unable to figure out angle because I could\n"
" not find pin #1 of element %s\n"
" Setting to %g degrees\n",
UNKNOWN (NAMEONPCB_NAME (element)), theta);
}
y = PCB->MaxHeight - y;
/* dimensions in mils */
user_x = 0.01 * x;
user_y = 0.01 * y;
centrot.centx = user_x;
centrot.centy = user_y;
centrot.rot = theta;
return centrot;
}
}
static StringList *
string_insert (char *str, StringList * list)
{
StringList *new, *cur;
if ((new = (StringList *) malloc (sizeof (StringList))) == NULL)
{
fprintf (stderr, "malloc() failed in string_insert()\n");
exit (1);
}
new->next = NULL;
new->str = strdup (str);
if (list == NULL)
return (new);
cur = list;
while (cur->next != NULL)
cur = cur->next;
cur->next = new;
return (list);
}
static SpecctraList *
specctra_insert (char *refdes, char *descr, char *value, SpecctraList * specctra)
{
SpecctraList *new, *cur, *prev = NULL;
if (specctra == NULL)
{
/* this is the first element so automatically create an entry */
if ((new = (SpecctraList *) malloc (sizeof (SpecctraList))) == NULL)
{
fprintf (stderr, "malloc() failed in specctra_insert()\n");
exit (1);
}
new->next = NULL;
new->descr = strdup (descr);
new->value = strdup (value);
new->num = 1;
new->refdes = string_insert (refdes, NULL);
return (new);
}
/* search and see if we already have used one of these
components */
cur = specctra;
while (cur != NULL)
{
if ((NSTRCMP (descr, cur->descr) == 0) &&
(NSTRCMP (value, cur->value) == 0))
{
cur->num++;
cur->refdes = string_insert (refdes, cur->refdes);
break;
}
prev = cur;
cur = cur->next;
}
if (cur == NULL)
{
if ((new = (SpecctraList *) malloc (sizeof (SpecctraList))) == NULL)
{
fprintf (stderr, "malloc() failed in specctra_insert()\n");
exit (1);
}
prev->next = new;
new->next = NULL;
new->descr = strdup (descr);
new->value = strdup (value);
new->num = 1;
new->refdes = string_insert (refdes, NULL);
}
return (specctra);
}
/*
* If fp is not NULL then print out the bill of materials contained in
* specctra. Either way, free all memory which has been allocated for specctra.
*/
static void
print_and_free (FILE *fp, SpecctraList *specctra)
{
SpecctraList *lastb;
StringList *lasts;
char *descr, *value;
while (specctra != NULL)
{
if (fp)
{
descr = CleanSPECCTRAString (specctra->descr);
value = CleanSPECCTRAString (specctra->value);
fprintf (fp, "%d,\"%s\",\"%s\",", specctra->num, descr, value);
free (descr);
free (value);
}
while (specctra->refdes != NULL)
{
if (fp)
{
fprintf (fp, "%s ", specctra->refdes->str);
}
free (specctra->refdes->str);
lasts = specctra->refdes;
specctra->refdes = specctra->refdes->next;
free (lasts);
}
if (fp)
{
fprintf (fp, "\n");
}
lastb = specctra;
specctra = specctra->next;
free (lastb);
}
}
static void
print_structure (FILE *fp)
{
fprintf (fp, " (structure\n");
/* define layers */
fprintf (fp, " (layer Component\n");
fprintf (fp, " (type signal)\n");
fprintf (fp, " (property\n");
fprintf (fp, " (index 0)\n )\n )\n");
fprintf (fp, " (layer Copper\n");
fprintf (fp, " (type signal)\n");
fprintf (fp, " (property\n");
fprintf (fp, " (index 1)\n )\n )\n");
/* PCB outline */
fprintf (fp, " (boundary\n");
fprintf (fp, " (rect pcb 0.0 0.0 %.2f %.2f)\n", PCB->MaxWidth*0.01, PCB->MaxHeight*0.01);
fprintf (fp, " )\n");
fprintf (fp, " (via \"via_45_25_mil\")\n");
/* DRC rules */
fprintf (fp, " (rule\n");
fprintf (fp, " (width 8)\n");
fprintf (fp, " (clear 10)\n");
fprintf (fp, " (clear 10 (type wire_area))\n");
fprintf (fp, " (clear 10 (type via_smd via_pin))\n");
fprintf (fp, " (clear 10 (type smd_smd))\n");
fprintf (fp, " (clear 10 (type default_smd))\n");
fprintf (fp, " )\n )\n");
}
static void
print_placement (FILE *fp)
/* gather all footprint names in a list
gather list of refdes for each footprint in list */
{
int i;
GList *footprints; //contain unique footprint names
fprintf (fp, " (placement\n");
ELEMENT_LOOP (PCB->Data);
{
gconstpointer descript = DESCRIPTION_NAME (element);
if( !g_list_find_custom( footprints, descript, strcmp ) ){
footprints = g_list_append( footprints, descript );
}
}
END_LOOP;
for(i=0; i < g_list_length( footprints ); i++){
int firstrot = -1; //change to the degree of the first element found
fprintf (fp, " (component %s\n", g_list_nth_data( footprints, i ));
ELEMENT_LOOP (PCB->Data);
{
if(!strcmp(DESCRIPTION_NAME (element), g_list_nth_data( footprints, i ) )){
CentroidRotation crot = get_rotation_and_centroid(element);
if (firstrot == -1)
{
firstrot = crot.rot;
}
char* side = TEST_FLAG (ONSOLDERFLAG, element) ? "back" : "front";
fprintf (fp, " (place %s %.2f %.2f %s %d (PN %s))\n", NAMEONPCB_NAME (element), crot.centx, crot.centy, side, firstrot-crot.rot, VALUE_NAME (element) );
}
}
END_LOOP;
fprintf (fp, " )\n");
}
fprintf (fp, " )\n");
g_list_free( footprints );
}
static void
print_library (FILE *fp)
/* gather all footprint names in a list
print info on each footprint */
{
int i;
GList *footprints; //contain unique footprint names
GList *pads; //contain unique pad names
fprintf (fp, " (library\n");
ELEMENT_LOOP (PCB->Data);
{
if( !g_list_find_custom( footprints, DESCRIPTION_NAME (element), strcmp ) ){
char *padstack;
int rotation;
int whichside = TEST_FLAG (ONSOLDERFLAG, element) ? -1 : 1;
CentroidRotation crot = get_rotation_and_centroid(element);
footprints = g_list_append( footprints, g_strdup( DESCRIPTION_NAME (element) ) );
fprintf (fp, " (image %s\n", DESCRIPTION_NAME (element) );
/* loop thru pins and pads here */
PIN_LOOP (element);
{
int ty;
float pinthickness;
float lx, ly; //hold local pin coordinates
ty = PCB->MaxHeight - pin->Y;
pinthickness = pin->Thickness*0.01;
padstack = g_strdup_printf ("Th_round_%.0f_mil", pinthickness);
lx = (pin->X*0.01-crot.centx)*whichside;
ly = (crot.centy - ty*0.01)*(-1);
if( !g_list_find_custom( pads, padstack, strcmp ) )
{
pads = g_list_append( pads, padstack );
}
if (!pin->Number) //if pin is null just make it a keepout
{
fprintf (fp, " (keepout \"\" (circle Component %.0f %.2f %.2f))\n", pinthickness, lx, ly);
fprintf (fp, " (keepout \"\" (circle Copper %.0f %.2f %.2f))\n", pinthickness, lx, ly);
}
else
{
fprintf (fp, " (pin %s %s %.2f %.2f)\n", padstack, pin->Number, lx, ly);
}
}
END_LOOP;
PAD_LOOP (element);
{
int xlen, ylen, xc, yc, p1y, p2y;
float lx, ly; //store local coordinates for pins
p1y = PCB->MaxHeight - pad->Point1.Y;
p2y = PCB->MaxHeight - pad->Point2.Y;
/* pad dimensions are thickness and point difference plus thickness */
xlen = (ABS(pad->Point1.X - pad->Point2.X)+50)/100; //round to mil
if (xlen == 0)
{
xlen = (pad->Thickness+50)/100; //round to mil
ylen = (ABS(p1y - p2y)+50)/100 + xlen; //round to mil
}
else
{
ylen = (pad->Thickness+50)/100;
xlen += ylen;
}
xc = (pad->Point1.X + pad->Point2.X)/2;
yc = (p1y + p2y)/2;
lx = (xc*0.01-crot.centx)*whichside;
ly = (crot.centy - yc*0.01)*(-1);
padstack = g_strdup_printf ("Smd_rect_%dx%d_mil", xlen, ylen);
if( !g_list_find_custom( pads, padstack, strcmp ) )
{
pads = g_list_append( pads, padstack );
}
if (!pad->Number) //if pad is null just make it a keepout
{
fprintf (fp, " (keepout \"\" (rect %s %.2f %.2f %.2f %.2f))\n", (whichside == 1) ? "Component" : "Copper", lx-xlen/2, ly-ylen/2, lx+xlen/2, ly+ylen/2);
}
else
{
fprintf (fp, " (pin %s %s %.2f %.2f)\n", padstack, pad->Number, lx, ly);
}
}
END_LOOP;
fprintf (fp, " )\n");
}
}
END_LOOP;
/* loop thru padstacks and define them all */
for(i=0; i < g_list_length( pads ); i++)
{
int retargs, dim1, dim2;
char * padstring = g_list_nth_data( pads, i );
fprintf (fp, " (padstack %s\n", padstring);
/* print info about pad here */
retargs = sscanf (padstring, "Smd_rect_%dx%d_mil", &dim1, &dim2);
if (retargs == 2) //then pad is smd
{
fprintf (fp, " (shape (rect Component %.1f %.1f %.1f %.1f))\n", dim1/(-2.0), dim2/(-2.0), dim1/2.0, dim2/2.0);
}
else ///then pad is th
{
retargs = sscanf (padstring, "Th_round_%d_mil", &dim1);
fprintf (fp, " (shape (circle Component %d))\n", dim1);
fprintf (fp, " (shape (circle Copper %d))\n", dim1);
}
fprintf (fp, " (attach off)\n");
fprintf (fp, " )\n");
}
/* add padstack for via */
fprintf (fp, " (padstack \"via_45_25_mil\"\n (shape (circle Component 45))\n (shape (circle Copper 45))\n (attach off)\n )\n");
fprintf (fp, " )\n");
g_list_foreach( footprints, (GFunc)g_free, NULL );
g_list_free( footprints );
g_list_foreach( pads, (GFunc)g_free, NULL );
g_list_free( pads );
}
static void
print_network (FILE *fp)
{
GList *netlistnames; //contain unique strings of netlist names
int i, firstcon;
NetListListType Nets;
Nets = CollectSubnets (False);
fprintf (fp, " (network\n");
NETLIST_LOOP (&Nets);
{
firstcon = 1; //clear flag after net name is found
NET_LOOP (netlist);
{
CONNECTION_LOOP (net);
{
int ni, nei;
char *ename;
char *pname;
char *n;
char *netname;
/* looking for pins and pads */
if (connection->type == PIN_TYPE || connection->type == PAD_TYPE)
{
PinTypePtr thispin;
PadTypePtr thispad;
ElementTypePtr thiselem;
if (connection->type == PIN_TYPE)
{
thispin = connection->ptr2;
thiselem = thispin->Element;
pname = thispin->Number;
}
else
{
thispad = connection->ptr2;
thiselem = thispad->Element;
pname = thispad->Number;
}
ename = NAMEONPCB_NAME(thiselem);
n = g_strconcat (ename, "-", pname, NULL);
for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) //loop thru all nets
for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) //loop thru all entries in all nets
{
if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0) //find the entry that matches this pin or pad
{
netname = g_strdup (PCB->NetlistLib.Menu[ni].Name + 2); //find the net name of this entry
//if( !g_list_find_custom( netlistnames, netname, strcmp ) ) //see if netlist was written down already
if(firstcon == 1)
{
firstcon = 0;
netlistnames = g_list_append( netlistnames, netname );
fprintf (fp, " (net %s\n (pins", netname);
}
}
}
fprintf (fp, " %s", n);
g_free(n);
}
}
END_LOOP;
}
END_LOOP;
fprintf (fp, ")\n )\n");
}
END_LOOP;
fprintf (fp, " (class geda_default");
for(i=0; i < g_list_length( netlistnames ); i++)
{
fprintf (fp, " %s", g_list_nth_data( netlistnames, i ) );
}
fprintf (fp, "\n (circuit\n (use_via via_45_25_mil)\n )\n");
fprintf (fp, " (rule (width 8))\n )\n )\n");
fprintf (fp, " (wiring\n )\n)\n");
g_list_foreach( netlistnames, (GFunc)g_free, NULL );
g_list_free( netlistnames );
}
static int
PrintSPECCTRA (void)
{
char utcTime[64];
double x, y, theta = 0.0, user_x, user_y;
double sumx, sumy;
double pin1x = 0.0, pin1y = 0.0, pin1angle = 0.0;
double pin2x = 0.0, pin2y = 0.0, pin2angle;
int found_pin1;
int found_pin2;
int pin_cnt;
time_t currenttime;
FILE *fp;
SpecctraList *specctra = NULL;
char *name, *descr, *value;
/* Print out the specctra .dsn file. */
fp = fopen (specctra_filename, "w");
if (!fp)
{
gui->log ("Cannot open file %s for writing\n", specctra_filename);
print_and_free (NULL, specctra);
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 \"(i dunno?)\")\n");
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 mil 10)\n");
/* time resolution descriptor [optional] */
/* voltage resolution descriptor [optional] */
/* unit descriptor [optional] */
fprintf (fp, " (unit mil)\n");
/* 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] */
/* color descriptor [optional] */
print_and_free (fp, specctra);
fclose (fp);
return (0);
}
static void
specctra_do_export (HID_Attr_Val * options)
{
int i;
if (!options)
{
specctra_get_export_options (0);
for (i = 0; i < NUM_OPTIONS; i++)
specctra_values[i] = specctra_options[i].default_val;
options = specctra_values;
}
specctra_filename = options[HA_specctrafile].str_value;
if (!specctra_filename)
specctra_filename = "pcb-out.dsn";
PrintSPECCTRA ();
}
static void
specctra_parse_arguments (int *argc, char ***argv)
{
hid_register_attributes (specctra_options,
sizeof (specctra_options) / sizeof (specctra_options[0]));
hid_parse_command_line (argc, argv);
}
HID specctra_hid = {
sizeof (HID),
"specctra",
"Exports a SPECCTRA .dsn file",
0, 0, 1, 0, 0, 0,
specctra_get_export_options,
specctra_do_export,
specctra_parse_arguments,
0, /* specctra_invalidate_wh */
0, /* specctra_invalidate_lr */
0, /* specctra_invalidate_all */
0, /* specctra_set_layer */
0, /* specctra_make_gc */
0, /* specctra_destroy_gc */
0, /* specctra_use_mask */
0, /* specctra_set_color */
0, /* specctra_set_line_cap */
0, /* specctra_set_line_width */
0, /* specctra_set_draw_xor */
0, /* specctra_set_draw_faded */
0, /* specctra_set_line_cap_angle */
0, /* specctra_draw_line */
0, /* specctra_draw_arc */
0, /* specctra_draw_rect */
0, /* specctra_fill_circle */
0, /* specctra_fill_polygon */
0, /* specctra_fill_rect */
0, /* specctra_calibrate */
0, /* specctra_shift_is_pressed */
0, /* specctra_control_is_pressed */
0, /* specctra_get_coords */
0, /* specctra_set_crosshair */
0, /* specctra_add_timer */
0, /* specctra_stop_timer */
0, /* specctra_log */
0, /* specctra_logv */
0, /* specctra_confirm_dialog */
0, /* specctra_close_confirm_dialog */
0, /* specctra_report_dialog */
0, /* specctra_prompt_for */
0, /* specctra_fileselect */
0, /* specctra_attribute_dialog */
0, /* specctra_show_item */
0, /* specctra_beep */
0, /* specctra_progress */
};
void
hid_specctra_init ()
{
apply_default_hid (&specctra_hid, 0);
hid_register_hid (&specctra_hid);
}
_______________________________________________
geda-user mailing list
geda-user@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-user