/* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 2002 DJ Delorie * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Contact addresses for paper mail and Email: * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA * dj@delorie.com * */ #include #include #include #include #include "global.h" #include "data.h" #include "dialog.h" #include "create.h" #if 0 #include "action.h" #include "buffer.h" #include "control.h" #include "crosshair.h" #include "draw.h" #include "error.h" #include "file.h" #include "library.h" #include "menu.h" #include "misc.h" #include "mymem.h" #include "remove.h" #include "set.h" #endif #include #include #include #include #include #include #include #include #include #define LLTYPE(foo) struct foo *next, *prev static char *bias_texts[4] = {"n/a", "-", "|", "*"}; static int solder_layer, component_layer; static struct { Widget label; Widget toggles[4]; } layer_bias[MAX_LAYER]; typedef struct list_s { LLTYPE(list_s); } list_s; typedef struct pin_s { LLTYPE(pin_s); list_s ll; int id, rn; int x, y; int diam; } pin_s; typedef struct line_s { LLTYPE(line_s); int id, rn; int x1, y1, x2, y2; int layer; int width; } line_s; typedef struct route_s { LLTYPE(route_s); int id; int npins, nlines; pin_s *pins; line_s *pads; line_s *lines; } route_s; struct { route_s *routes; } mucs; static void _list_add(list_s **root, list_s *entry) #define list_add(r,e) _list_add((list_s **)r, (list_s *)e) { entry->next = *root; entry->prev = 0; *root = entry; if (entry->next) entry->next->prev = entry; } static void _list_remove(list_s **root, list_s *entry) #define list_remove(r,e) _list_remove((list_s **)r, (list_s *)e) { if (entry->next) entry->next->prev = entry->prev; if (entry->prev) entry->prev->next = entry->next; else *root = entry->next; } static void _list_merge(list_s **root, list_s **root2) #define list_merge(r,r2) _list_merge((list_s **)r, (list_s **)r2) { list_s *e; if (*root2 == 0) return; if (*root == 0) { *root = *root2; *root2 = 0; return; } for (e=*root; e->next; e=e->next); e->next = *root2; e->next->prev = e->prev; *root2 = 0; } static void _list_free(list_s *r) #define list_free(r) _list_free((list_s *)r) { list_s *e, *n; for (e=r; e; e = n) { n = e->next; free(e); } } static void free_mucs() { route_s *r; for (r=mucs.routes; r; r=r->next) { list_free(r->pins); list_free(r->pads); list_free(r->lines); } list_free(mucs.routes); mucs.routes = 0; } static Widget popup=0, gridText; static int grid = 25; static int ReturnCode; static route_s * find_route(int x, int y, int layer) { route_s *r; for (r=mucs.routes; r; r=r->next) { pin_s *p; line_s *l; for (l=r->lines; l; l=l->next) { if (((l->x1 == x && l->y1 == y) || (l->x2 == x && l->y2 == y)) && layer == l->layer) return r; } for (l=r->pads; l; l=l->next) { if (((l->x1 == x && l->y1 == y) || (l->x2 == x && l->y2 == y)) && layer == l->layer) return r; } for (p=r->pins; p; p=p->next) { if (p->x == x && p->y == y) return r; } } return 0; } static int pin_count(route_s *r) { int c=0; pin_s *p; line_s *l; for (p=r->pins; p; p=p->next) c++; for (l=r->pads; l; l=l->next) c++; return c; } static void emit_pin(FILE *out, char type, pin_s *p, int routeno) { fprintf(out, "%c %d %d %d 1 %d %d 1 %d 1 0 0 0 0\n", type, routeno, p->x, p->y, MAX_LAYER, p->rn, p->id); fprintf(out, "q c 0 %d 0 0 0\n", p->diam); } static void emit_pad(FILE *out, char type, line_s *l, int routeno) { int x = (l->x1 + l->x2) / 2; int y = (l->y1 + l->y2) / 2; fprintf(out, "%c %d %d %d %d %d %d 1 %d 1 0 0 0 0\n", type, routeno, x, y, l->layer+1, l->layer+1, l->rn, l->id); if (l->x1 == l->x2) fprintf(out, "q r 90 %d %d", abs(l->y1-l->y2), l->width); else fprintf(out, "q r 0 %d %d", abs(l->x1-l->x2), l->width); fprintf(out, " %d %d\n", l->layer+1, l->layer+1); } static void merge_rn2(route_s *r, int orn, int nrn) { pin_s *p; line_s *l; for (p=r->pins; p; p=p->next) if (p->rn == orn) p->rn = nrn; for (l=r->pads; l; l=l->next) if (l->rn == orn) l->rn = nrn; for (l=r->lines; l; l=l->next) if (l->rn == orn) l->rn = nrn; } static void merge_rn(route_s *r, int x, int y, int layer, int rn) { pin_s *p; line_s *l; for (p=r->pins; p; p=p->next) if (p->x == x && p->y == y && p->rn != rn) merge_rn2(r, p->rn, rn); for (l=r->pads; l; l=l->next) { if (l->x1 == x && l->y1 == y && l->layer == layer && l->rn != rn) merge_rn2(r, l->rn, rn); if (l->x2 == x && l->y2 == y && l->layer == layer && l->rn != rn) merge_rn2(r, l->rn, rn); } for (l=r->lines; l; l=l->next) if (l->width > 0) { if (l->x1 == x && l->y1 == y && l->layer == layer && l->rn != rn) merge_rn2(r, l->rn, rn); if (l->x2 == x && l->y2 == y && l->layer == layer && l->rn != rn) merge_rn2(r, l->rn, rn); } } static void resequence_route(route_s *r) { int pi, li, rn=0; pin_s *p; line_s *l; for (p=r->pins; p; p=p->next) p->rn = rn++; for (l=r->pads; l; l=l->next) l->rn = rn++; for (l=r->lines; l; l=l->next) l->rn = rn++; for (l=r->lines; l; l=l->next) if (l->width > 0) { merge_rn(r, l->x1, l->y1, l->layer, l->rn); merge_rn(r, l->x2, l->y2, l->layer, l->rn); } } static void CB_CancelOrOK(Widget W, XtPointer ClientData, XtPointer CallData) { char *txt; Arg args[1]; int layerno, ei; int pi; ReturnCode = (int) ClientData; if (ReturnCode == CANCEL_BUTTON) return; XtSetArg(args[0], XtNstring, &txt); XtGetValues(gridText, args, 1); grid = atoi(txt); if (grid < 1) { MessageDialog("Grid must be at least 1"); return; } /* PCB->Data->Layer[n]->Line[n]; */ mucs.routes = 0; for (ei=0; eiData->ElementN; ei++) { ElementType *e = &(PCB->Data->Element[ei]); for (pi=0; piPinN; pi++) { route_s *r; pin_s *p = (pin_s *)malloc(sizeof(pin_s)); p->x = e->Pin[pi].X; p->y = e->Pin[pi].Y; p->diam = e->Pin[pi].Thickness; r = (route_s *)malloc(sizeof(route_s)); r->pins = 0; r->pads = 0; r->lines = 0; list_add(&(mucs.routes), r); list_add(&(r->pins), p); } for (pi=0; piPadN; pi++) { route_s *r; line_s *p = (line_s *)malloc(sizeof(line_s)); p->x1 = e->Pad[pi].Point1.X; p->y1 = e->Pad[pi].Point1.Y; p->x2 = e->Pad[pi].Point2.X; p->y2 = e->Pad[pi].Point2.Y; p->width = e->Pad[pi].Thickness; p->layer = e->Flags & ONSOLDERFLAG ? solder_layer : component_layer; r = (route_s *)malloc(sizeof(route_s)); r->pins = 0; r->pads = 0; r->lines = 0; list_add(&(mucs.routes), r); list_add(&(r->pads), p); } } for (pi=0; piData->ViaN; pi++) { route_s *r; pin_s *p = (pin_s *)malloc(sizeof(pin_s)); p->x = PCB->Data->Via[pi].X; p->y = PCB->Data->Via[pi].Y; p->diam = PCB->Data->Via[pi].Thickness; r = (route_s *)malloc(sizeof(route_s)); r->pins = 0; r->pads = 0; r->lines = 0; list_add(&(mucs.routes), r); list_add(&(r->pins), p); } for (layerno=0; layernoData->Layer[layerno]); int lineno; for (lineno = 0; lineno < layer->LineN; lineno++) { line_s *mline; LineType *line = &(layer->Line[lineno]); route_s *sr = find_route(line->Point1.X, line->Point1.Y, layerno); route_s *er = find_route(line->Point2.X, line->Point2.Y, layerno); if (sr && er) { list_merge(&(sr->pins), &(er->pins)); list_merge(&(sr->pads), &(er->pads)); list_merge(&(sr->lines), &(er->lines)); list_remove(&(mucs.routes), er); } else if (sr) ; else if (er) sr = er; else { sr = (route_s *)malloc(sizeof(route_s)); sr->pins = 0; sr->pads = 0; sr->lines = 0; list_add(&(mucs.routes), sr); } mline = (line_s *)malloc(sizeof(line_s)); mline->x1 = line->Point1.X; mline->y1 = line->Point1.Y; mline->x2 = line->Point2.X; mline->y2 = line->Point2.Y; if (line->Flags & RATFLAG) mline->width = 0; else mline->width = line->Thickness; mline->layer = layerno; list_add(&(sr->lines), mline); } } { int num_routes, i, routeno; route_s *r; line_s *l; pin_s *p; FILE *out; out = fopen("mucs.in", "w"); for (r=mucs.routes, num_routes=0; r; r=r->next) { line_s *line; r->npins = pin_count(r); for (line=r->lines, r->nlines=0; line; line=line->next) if (line->width > 0) r->nlines++; if (r->npins > 1) num_routes++; resequence_route(r); } fprintf(out, "j 0 0 %d %d 1 %d %d %d %d %d %d 0 %d n 0 %d 0 0 0 0\n", PCB->MaxWidth, PCB->MaxHeight, MAX_LAYER, num_routes, grid, Settings.Bloat * 2 + 2, Settings.Bloat * 2 + 2, Settings.Bloat * 2 + 2, Settings.ViaThickness, Settings.LineThickness); fprintf(out, "k 0 0 0 0 0 0 0 0 0 0\n"); /* spare */ fprintf(out, "m 0 0 0 0 0 0 0 0 0 0\n"); /* cost */ for (i=0; inext) if (r->npins < 2) { int pc = 0; for (p=r->pins; p; p=p->next) { p->id = 0; emit_pin(out, 'u', p, 0); } for (l=r->pads; l; l=l->next) { l->id = 0; emit_pad(out, 'u', l, 0); } } routeno = 0; for (r=mucs.routes; r; r=r->next) { int pc = 0; if (r->npins < 2) continue; r->id = ++routeno; fprintf(out, "r %d %d 0 %d 0 %d 0 0\n", r->id, r->npins, r->nlines, Settings.LineThickness); for (p=r->pins; p; p=p->next) { p->id = pc++; emit_pin(out, 'p', p, routeno); } for (l=r->pads; l; l=l->next) { l->id = pc++; emit_pad(out, 'p', l, routeno); } for (l=r->lines; l; l=l->next) if (l->width) fprintf(out, "t 0 %d %d %d %d %d %d 0\n", l->width, l->x1, l->y1, l->x2, l->y2, l->layer+1); } fclose(out); } system("anneal_tracker < mucs.in > mucs.out"); { int x, y, l, x0, y0, nc, c; FILE *in = fopen("mucs.out", "r"); char buf[1000]; while (fgets(buf, 1000, in)) { switch (buf[0]) { case 'V': sscanf(buf, "%*c %*d %d %d", &x, &y); CreateNewVia(PCB->Data, x, y, Settings.ViaThickness, Settings.ViaDrillingHole, "", VIAFLAG); break; case 'T': sscanf(buf, "%*c %*d %d %d", &l, &nc); l--; fgets(buf, 1000, in); sscanf(buf, "%*c %d %d", &x0, &y0); for (c=1; cData->Layer+l, x0, y0, x, y, Settings.LineThickness, 0); x0 = x; y0 = y; } } } fclose(in); } free_mucs(); } static void build_mucs_box() { static char buf[20]; int l, b; Widget masterform, label, last=0; static DialogButtonType buttons[] = { { "defaultButton", " Route ", CB_CancelOrOK, (XtPointer) OK_BUTTON, NULL }, { "cancelButton", " Cancel ", CB_CancelOrOK, (XtPointer) CANCEL_BUTTON, NULL }}; popup = XtVaCreatePopupShell("MUCS Router", transientShellWidgetClass, Output.Toplevel, XtNallowShellResize, True, XtNmappedWhenManaged, False, NULL); masterform = XtVaCreateManagedWidget("mucsMasterForm", formWidgetClass, popup, XtNresizable, True, NULL); label = XtVaCreateManagedWidget("gridL", labelWidgetClass, masterform, XtNfromVert, NULL, XtNlabel, "Grid", LAYOUT_TOP, NULL); sprintf(buf, "%d", grid); gridText = XtVaCreateManagedWidget("gridText", asciiTextWidgetClass, masterform, XtNfromVert, NULL, XtNfromHoriz, label, XtNeditType, XawtextEdit, XtNstring, buf, XtNinsertPosition, strlen(buf), LAYOUT_TOP, NULL); last = gridText; for (l=0; lData->Layer[l].Name, "solder") == 0) { pre = 3; solder_layer = l; } if (strcmp(PCB->Data->Layer[l].Name, "component") == 0) { pre = 3; component_layer = l; } for (b=0; b<4; b++) { layer_bias[l].toggles[b] = XtVaCreateManagedWidget("biast", toggleWidgetClass, masterform, XtNfromHoriz, l2, XtNradioGroup, l2, XtNradioData, b, XtNfromVert, last, XtNstate, b==pre?True:False, XtNlabel, bias_texts[b], LAYOUT_TOP, NULL); l2 = layer_bias[l].toggles[b]; } layer_bias[l].label = XtVaCreateManagedWidget("biasl", labelWidgetClass, masterform, XtNfromVert, last, XtNfromHoriz, l2, XtNlabel, PCB->Data->Layer[l].Name, LAYOUT_TOP, NULL); last = layer_bias[l].toggles[0]; } AddButtons(masterform, last, buttons, ENTRIES(buttons)); } void ActionMUCSbox(Widget w, XEvent *e, String *argv, Cardinal *argc) { build_mucs_box(); StartDialog(popup); DialogEventLoop(&ReturnCode); EndDialog(popup); }