diff --git a/trunk/ulp/DESCRIPTION b/trunk/ulp/DESCRIPTION
new file mode 100644
index 00000000..166f4987
--- /dev/null
+++ b/trunk/ulp/DESCRIPTION
@@ -0,0 +1,25 @@
+
+User Language Programs
+
+ULPs named ex-... are examples which demonstrate some features of the User Language.
+They have no practical use.
+
+All other programs are real applications which, of course, show the abilities of the
+EAGLE User Language, too.
+
+Please check our web pages for further interesting ULPs:
+http://www.cadsoftusa.com
+
+
+User-Language-Programme
+
+ULPs mit ex-... im Namen sind Beispiel-ULPs, die einige Funktionen der User-Language
+erklären. Sie sind nicht für eine konkrete Anwendung geeignet.
+
+Bei allen anderen Programmen handelt es sich um echte Anwendungen, die natürlich
+auch als Beispiele für die Möglichkeiten der User-Language dienen.
+
+Bitte sehen Sie auch auf unsere Internet-Seiten. Dort finden Sie weitere
+nützliche ULPs:
+http://www.cadsoft.de
+
"
+ "RUN Felicitas_PCBSim /E | Daten-Export. "
+ "RUN Felicitas_PCBSim /I | Exportiert nur die Attribute der selektierten Instanz. "
+ "RUN Felicitas_PCBSim /S | Setup Option. "
+ "RUN Felicitas_PCBSim /RELOAD | Import der simulierten Werte."
+ "
"
+ "Handshake erfolgt durch Datei-Polling."
+ "Um das ULP als Kontext einer Instanz (Symbol) zu starten, tragen Sie die unten stehende "
+ "Zeile in Ihre eagle.scr unter SCH: ein. "
+ "SET CONTEXT instance 'PCBsim' 'RUN Felicitas_PCBSim /I';"
+ "
"
+ "Globale Attribute für die Übergabe von Werten (Design-Regeln) müssen mit 'FEL_' beginnen. "
+ "Jedes globale Attribute wird mit \"@GLOBAL\" gekennzeichnet."
+ "
"
+ "Author: alf@cadsoft.de"
+
+
+#require 6.0503
+string ULP_Version = "1.0.8"; // 1.0.2 | 2013-12-18
+ // 1.0.3 | 2014-01-15 Netzliste mit allen Nicht-SUPPLY-Pins ausgeben.
+ // 1.0.4 | 2014-02-11 Globale Attrubte ausgeben.
+ // 1.0.5 | 2014-02-13 Globale Attrubte auch für ToPCBSim_SingleAttributes_txt ausgeben
+ // und wieder zurücklesen, inkl. aller geänderten Values und Part-Attribute.
+ // Home path in Linux wird richtig benutzt.
+ // 1.0.6 | 2014-02-17 MOVE Datei unter Windows jetzt mit Absoluten Pfad
+ // 1.0.7 | 2014-02-26 Anlegen des Ordner "/PCBSimExchange" unter Windows 8 berichtigt
+ // 1.0.8 | 2014-03-11 Usage geändert "RUN Felicitas_PCBSim"
+ // #require 6.0503
+
+char Separator = '\t'; /* ***************************************************************************
+ Der Separator zum trennen der Parameter in der Zeile.
+ Es muß ein nicht druckbares Zeichen sein, aber nicht SPACE,
+ da in VALUES von Bauteilen und Attributen "SPACE" erlaubt ist.
+ Bauteilnamen, NET-Namen und ATTIBUTE-Namen sind immer groß geschrieben,
+ und können kein SPACE oder sonstige nicht druckbare ASCII-Zeichen anthalten.
+ ******************************************************************************/
+int Test = 0;
+int PCBsim_running = 0;
+
+string Search_Felicitas_Execute; // "felicitas/pcbsim.exe";
+
+string Exchange_Directory;
+ /* 2.2 Exchange Directory
+ The exchange directory can be given by a command line option ?-d?.
+ The environment variable PCBSIMEXCHANGE overwrites that default.
+ If neither a command line option is given nor the environment variable PCBSIMEXCHANGE is
+ set, the directory to exchange data defaults to
+ ? Windows: C:/Documents and Settings/Username/PCBSimExchange
+ ? Linux: ~/PCBSimExchange
+ */
+string UserHome[];
+int Ucnt = strsplit(UserHome, EAGLE_HOME, '/');
+
+string OS_System = OS_SIGNATURE;
+
+if (strstr(OS_System, "Windows") == 0) {
+ OS_System = "Windows";
+ Exchange_Directory = "/PCBSimExchange";
+ Search_Felicitas_Execute = "pcbsim.exe"; // "PCBsim program Windows";
+}
+
+else if (OS_System == "Linux") {
+ // da der relative Pfad zum Homeverzeichnis ~/ u.U. Probleme machen kann,
+ // könnte man evtl. auch EAGLE_HOME benutzen.
+ //Exchange_Directory = "~/PCBSimExchange"; // 2014-02-12 Pfade nie mit / beenden
+ sprintf(Exchange_Directory, "%s", "/PCBSimExchange"); // 2014-02-12 Pfade immer mit / trennen
+ Search_Felicitas_Execute = "pcbsim"; // "PCBsim program Linux";
+}
+
+else if (OS_System == "MAC_OS") {
+ dlgMessageBox("Für MAC OS gibt es keine Version von PCBsim.", "OK");
+ exit(-81);
+}
+else {
+ dlgMessageBox("Betriebssystem " + OS_SIGNATURE + " wird nicht unterstützt!", "OK");
+ exit(-85);
+}
+
+/* ***** PCBsim file definition ****** */
+string Logging_Directory = "logging";
+
+string PCBSim_Present_txt = EAGLE_HOME + Exchange_Directory + "/PCBSim_Present.txt";
+ /*
+ This file is created by PCBSim uppon start and deleted when closed. It
+ can be used by the CAD system to determine whether PCBSim is present or not. If in doubt,
+ use the command ?Ping? to determine whether PCBSim is till alive...
+ */
+ /* **********************************************************************
+ ***** PCBSim_Present.txt, 14/11/2013, 14:07:13 *****
+ VERSION 1 01 Windows Beta version
+ @END
+ ********************************************************************** */
+string PCBSim_Busy_txt = EAGLE_HOME + Exchange_Directory + "/PCBSim_Busy.txt";
+ /*
+ This file indicates that PCBSim is busy with a lenghty operation. It can be used to indicate the
+ status of PCBSim within the CAD system. If PCBSim is not busy anymore, it just erases that file.
+ The file is not logged.
+ It contains a message which might be used by the CAD system to display a status bar. An optional
+ status number is presented also. It contains an estimate on how much percent of the current task has
+ been done.
+ */
+string ToPCBSim_Command_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_Command.txt";
+ /*
+ A file which contains special commands. Currently defined is
+ ?Version?, ?Close? and ?Ping?. Commands are NOT case sensitive.
+ */
+string FrPCBSim_Command_txt = EAGLE_HOME + Exchange_Directory + "/FrPCBSim_Command.txt";
+ /*
+ The respond for special commands. Currently not used
+ */
+string ToPCBSim_Netlist_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_Netlist.txt";
+ /*
+ Netlist written from the CAD system in order to start the simulation
+ with PCBSim.
+ */
+string ToPCBSim_AllAttributes_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_AllAttributes.txt";
+ /*
+ All attributes of all components in the netlist. This file MUST
+ be written BEFORE ToPCBSim_Netlist.txt is written.
+ */
+string ToPCBSim_SingleAttributes_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_SingleAttributes.txt";
+ /*
+ The attributes of a single component. It is written so that
+ PCBSim opens a dialog to edit the special properties of the component. For example IBIS
+ model, or transmission line properties.
+ */
+string FrPCBSim_SingleAttributes_txt = EAGLE_HOME + Exchange_Directory + "/FrPCBSim_SingleAttributes.txt";
+ /*
+ The changed attributes of a single component. Those are used by the CAD system
+ to update the attributes after PCBSim has changed some properties.
+ */
+string FrPCBSim_AllAttributes_txt = EAGLE_HOME + Exchange_Directory + "/FrPCBSim_AllAttributes.txt";
+ /*
+ The changed attributes of all components. This file might
+ contain changed attributes of a number of components. It is written after the simulation by
+ PCBSim and might contain changed values for termination resistors or other components.
+ */
+ /* ************************************************************************************************
+ A transaction is started by the CAD system writing one of the ?ToPCBSim...? files. PCBSim reacts
+ accordingly. When PCBSim is finished, it first writes any result files (FrPCBSim...) and then deletes
+ the files ?ToPCB...? from the directory (rather moves them to the logging directory). The deletion of
+ the files is the signal for the CAD system that PCBSim has finished. It can then process any
+ ?FrPCBSim...? files if there are any.
+ As soon as the CAD system has finished processing the ?FrPCBSim...? files, it moves them to the
+ logging directory.
+ After a complete transaction, the exchange directory is empty again.
+ ************************************************************************************************* */
+
+
+string Executable = ""; // Pfad-Dateiname zum Executable-Programm
+string EagleExecute = EAGLE_PATH;
+
+int Ex_WaitOnHandShake = 1; // flag for response of external executable has changed the data file
+
+string FileNewTemp = "wtD"; // option for function output() for generate temporary file (script).
+string FileAppend = "at"; // option for function output() append data to existing file.
+string ScriptFile = "";
+
+int ExportAll = 1;
+
+char SearchStartDrive = 'C'; // *** first Windows-System drive ***
+string StartFolder; // the ground path
+char SearchLastDrive = 'Z'; // 'Z' *** last Windows-System drive ***
+
+int SearchnRoot;
+string SearchRoot[];
+
+string SearchFiles[];
+int SearchStart, SearchEnd;
+string a[];
+int SearchIs_UNC;
+int CntSubDirIteration = 4; // maximal bis in den 4. Unterordner suchen
+
+
+string GlobalAttribute = "@GLOBAL"; // Markierung der globalen Attribute des Schaltplan für die Definition der Design-Regeln im Schaltplan
+int PCBsimGlobalAttributeCount = 10; //
+int CntNewI = 0;
+string NewInstancePart[];
+
+string SearcheLibrary = "/felicitas/felicitas-simulation.lbr";
+string FelicitasSimulationLbr;
+string Cmd = "";
+
+
+
+/* ################## Functions ####################### */
+string showsyscommand(string command, string call, string debug) {
+ dlgDialog("show command") {
+ dlgLabel("Call from: " + call);
+ dlgLabel("Debug: " + debug);
+ dlgHBoxLayout dlgSpacing(800);
+ dlgHBoxLayout {
+ dlgLabel("system(");
+ dlgStringEdit(command);
+ dlgLabel(")");
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-209); }
+ dlgStretch(1);
+ }
+ };
+ return command;
+}
+
+
+/* *************** file functions ********** */
+// change Eagle slash in path names to backslash for windows
+string lash2backslash(string f) {
+ string s[];
+ int cnt = strsplit(s, f, '/');
+ return strjoin(s, '\\');
+}
+
+// change backslash in windows path names to Eagle slash
+string backslash2lash(string f) {
+ string s[];
+ int cnt = strsplit(s, f, '\\');
+ return strjoin(s, '/');
+}
+
+int make_sub_dir(string root, string subdir) { /*** generate DOS command MKDIR ***/
+ if (OS_System == "Windows") { /* ** generate DOS command MKDIR ** */
+ string doscommand;
+ sprintf(doscommand, "CMD.EXE /C MKDIR \"%s%s\"", lash2backslash(root), lash2backslash(subdir));
+ if (Test) doscommand = showsyscommand(doscommand, "(Test) make directory", "");
+ system(doscommand);
+ }
+
+ else {
+ string linuxshellscript;
+ // mkdir ist das offizielle Komando!
+ // md kann auch funktionieren, muß aber nicht!
+ // bei ~/... für den Home-Pfad darf man den Pfad nicht in " " einschliessen,
+ // sonst wird die Tilde ~ nicht ausgewertet!
+ // Wegen evtl. Leerzeichen im Pfad, ist es besser EAGLE_HOME + "/" als Pfad zu benutzen, eingeschlossen in " ".
+ string sd[], s;
+ int cnt = strsplit(sd, subdir, '/');
+ string mk;
+ sprintf(mk, "mkdir %s%s", root, sd[0]); // setze den Grundpfad
+ for (int n = 1; n < cnt; n++) {
+ sprintf(s, "%s/%s\n", mk, sd[n] );
+ mk += "/" + sd[n]; // der erweiterte Pfad ist jetzt der Grundpfad
+ linuxshellscript += s;
+ }
+
+ if (Test) linuxshellscript = showsyscommand(linuxshellscript, "(Test) make directory", "");
+
+ system(linuxshellscript);
+ }
+ string f[];
+ int n = fileglob(f, root + subdir); // prüfe ob das Verzeichnis angelegt werden konnte.
+ return n;
+}
+
+void move_and_rename_to_logging(string f) {
+ if (OS_System == "Windows") { /* ** generate DOS command MKDIR ** */
+ string doscommand;
+ /*
+ Um eine oder mehrere Dateien zu verschieben:
+ MOVE [/Y| /-Y] [Laufwerk:][Pfad]Datei1[,...] Ziel
+
+ Um ein Verzeichnis umzubenennen:
+ MOVE [/Y| /-Y] [Laufwerk:][Pfad]Verz1 Verz2
+
+ [Laufwerk:][Pfad]Datei1 Bezeichnet den Pfad und den Namen der zu
+ verschiebenden Datei(en).
+ Ziel Bezeichnet den Zielort für die Datei. Das Ziel
+ kann ein Laufwerkbuchstabe mit Doppelpunkt, ein
+ Verzeichnisname oder eine Kombination beider sein.
+ Wenn Sie nur eine einzelne Datei verschieben,
+ können Sie auch einen Dateinamen angeben, um die
+ Datei beim Verschieben umzubenennen.
+ [Laufwerk:][Pfad]Verz1 Bezeichnet das umzubenennende Verzeichnis.
+ Verz2 Bezeichnet den neuen Namen des Verzeichnisses.
+ /Y Unterdrückt die Bestätigungsaufforderung zum
+ Überschreiben bestehender Zieldateien.
+ /-Y Fordert vor dem Überschreiben bestehender
+ Zieldateien zur Bestätigung auf.
+ Die Option /Y ist in der COPYCMD-Umgebungsvariablen eventuell voreingestellt.
+ */
+
+ string fext; // file extension
+ sprintf(fext, ".%s.txt", t2string(time(), "Uyyyy-MM-dd hh_mm_ss"));
+ sprintf(doscommand, "CMD.EXE /C MOVE \"%s\" \"%s\"",
+ lash2backslash(f),
+ lash2backslash(filedir(f)) + lash2backslash(Logging_Directory + "/" + filesetext(filename(f), fext)) // 2014-0217
+ );
+ if (Test) {
+ dlgDialog("(Test) move") {
+ dlgHBoxLayout dlgSpacing(900);
+ dlgTextEdit(doscommand);
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-305); }
+ }
+ };
+ }
+ system(doscommand);
+ }
+ else { // move file for Linux
+ string linuxshellscript;
+ string fext; // file extension
+ sprintf(fext, ".%s.txt", t2string(time(), "Uyyyy-MM-dd hh_mm_ss"));
+ sprintf(linuxshellscript, "mv \"%s\" \"%s\"", // Linux braucht für das Ziel den kompletten Pfad
+ f,
+ filedir(f) + Logging_Directory + "/" + filesetext(filename(f), fext) // 2014-02-17
+ );
+ if (Test) {
+ dlgDialog("(Test) move") {
+ dlgHBoxLayout dlgSpacing(900);
+ dlgTextEdit(linuxshellscript);
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-328); }
+ }
+ };
+ }
+ system(linuxshellscript);
+ }
+ return;
+}
+
+int check_directory(string dir) {
+ string fdir[];
+ return fileglob(fdir, dir);
+}
+
+int check_exist_file(string path, string ckfile) {
+ return fileglob(SearchFiles, path + ckfile);
+}
+
+// ein Windows-Laufwerk beginnt mit "Buchstabe:\"
+// suche nach ":/" hinter dem Laufwerksbuchstaben
+void check_windows_root(void) {
+ string drv;
+ for(int d = SearchStartDrive; d <= SearchLastDrive; d++) {
+ sprintf(drv, "%c:/", d);
+ if (check_exist_file(drv, "/")) {
+ SearchRoot[SearchnRoot] = drv;
+ SearchnRoot++;
+ }
+ }
+ return;
+}
+
+
+/* *********************** die Suchschleife ****************************************************** */
+// searchfile = die zu suchende Datei
+// root = der Start-Pfad ab dem gesucht werden soll, inkl. Laufwerkbuchstabe unter Windows
+// maxiteration = die Tiefe, Anzahl der Verzweigung (Unterordner) ab dem root Pfad.
+/* *********************************************************************************************** */
+string file_search(string root, string searchfile, int maxiteration, string debugnum) {
+ if (!root) {
+ if (debugnum == "init") {
+ dlgMessageBox("RUN '" + filesetext(argv[0], "") + "' with option Setup: " + searchfile, "CANCEL");
+ }
+ else {
+ if (dlgMessageBox(debugnum + "\nUnknown path of file : "+searchfile, "OK", "CANCEL") == 0) return "";
+ }
+ exit(-374);
+ }
+ int len = strlen(root);
+ if (root[len-1] != '/') root += "/"; // root muß mit Slash enden!
+ if (!check_exist_file(root, "")) { // den Pfad prüfen
+ return "";
+ }
+ // *** Betriebsystem feststellen ***
+ // ******* Windows Laufwerke *******
+ if (root) {
+ SearchRoot[0] = root;
+ SearchnRoot = 1;
+ }
+ else {
+ check_windows_root(); // unter Windows die Laufwerke ermitteln
+ }
+
+ int n, r;
+ SearchStart = 0;
+ SearchEnd = SearchnRoot;
+ int iteration = 1;
+ int finish = 0;
+ int cntf;
+ string searchfoundfile[];
+ string h;
+
+ do {
+ // 1. die Root-Ordner nach der Datei durchsuchen
+ for (r = SearchStart; r < SearchEnd; r++) {
+ status(SearchRoot[r]); // Anzeige des aktuellen Verzeichnisnamen
+ n = check_exist_file(SearchRoot[r], searchfile); // suche im Verzeichnis nach Datei
+ if (n) {
+ for (int f=0; f 1) {
+ s = "";
+ for (int i = 0; i < cnt; i++) {
+ if (i == 0) {
+ if (t[i]) s += t[i];
+ }
+ else if (i) s += "''" + t[i];
+ }
+ }
+ return s;
+}
+
+void readconfig(void) { // read configuration file of ULP
+ Executable = cfgget("ULP:felicitas.Executable");
+ return;
+}
+
+void saveconfig(void) {
+ cfgset("ULP:felicitas.Executable", Executable);
+ return;
+}
+
+void call_system(string exportfile, string debug) { // DOS comand execute
+ string syscommand;
+ // Das executable und der Dateiname müssen in " " eingeschlossen werden, wegen Spaces im Pfad-Dateinamen!
+ sprintf(syscommand, "CMD.EXE /C \"%s\" \"%s\"", lash2backslash(Executable), lash2backslash(ToPCBSim_Netlist_txt));
+ if (Test) syscommand = showsyscommand(syscommand, "(Test) call_system()", debug);
+ system(syscommand); // externes Programm starten
+ return;
+}
+
+/* *************************************
+ ********** Reload - Import ************
+ ************************************* */
+// check if exist attribute and has changed the value
+int checkatt(string p_name, string att_name, string att_value) {
+ sheet(S) {
+ S.instances(I) {
+ if (ingroup(I) || strupr(argv[1]) == "/E") { // mit Iption /E werden alle Parts geprüft/geändert
+ if (I.part.name == p_name) {
+ if (att_name == "VALUE") {
+ if (I.part.value == att_value) return 0; // value is the sam, do nothing
+ else return 1; // value is changed
+ }
+ else {
+ I.part.attributes(A) {
+ if (A.name == att_name) {
+ if (A.value == att_value) return 0; // value is the sam, do nothing
+ else return 1; // value is changed
+ }
+ }
+ return 1; // returns a new attribute from PCBsim
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void set_attributes(string valuelines) {
+ string line[];
+ int cntlines = strsplit(line, valuelines, '\n');
+ string cmd, s;
+ for (int n = 0; n < cntlines; n++) {
+ string v[];
+ int cnt = strsplit(v, line[n], Separator);
+ if (cnt > 1) {
+ if (v[0] == GlobalAttribute) { // 2014-02-12 set global attributes
+ sprintf(s, "ATTRIBUTE * '%s' '%s';\n", v[1], v[2]);
+ cmd+=s;
+ }
+ else if (checkatt(v[0], v[1], v[2])) {
+ if (v[1] == "VALUE") {
+ sprintf(s, "VALUE '%s' '%s';\n", v[0], v[2]);
+ cmd+=s;
+ }
+ else {
+ sprintf(s, "CHANGE DISPLAY OFF;\n");
+ cmd+=s;
+ sprintf(s, "ATTRIBUTE '%s' '%s' '%s';\n", v[0], v[1], v[2]);
+ cmd+=s;
+ }
+ }
+ }
+ else {
+ if (v[0][0] == '*') {
+ // Nur die Kopfzeile (Kommentar), wird nicht ausgewertet
+ }
+ else if (v[0] == "@END") {
+ break;
+ }
+ }
+ }
+ if (Test) dlgDialog("(Test) Die Rückgabewerte") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgTextEdit(valuelines);
+ dlgTextEdit(cmd);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-550); }
+ dlgStretch(1);
+ }
+ };
+ exit(cmd);
+}
+
+/* ************************************
+ ********* Export functions ***********
+ ************************************ */
+int newpart(UL_INSTANCE I) { // 2014-02-12 check exits this part of instance on list
+ for (int n = 0; n < CntNewI; n++) {
+ if (NewInstancePart[n] == I.part.name) return 0;
+ }
+ NewInstancePart[CntNewI++] = I.part.name;
+ return 1;
+}
+
+void ex_attrib_value(UL_INSTANCE I) { // 2014-02-12
+ printf("%s%cVALUE%c%s\n", I.part.name, Separator, Separator , I.part.value);
+ I.part.attributes(A) {
+ if (A.name != "_EXTERNAL_") printf("%s%c%s%c%s\n", I.part.name, Separator, A.name, Separator, A.value);
+ }
+ return;
+}
+
+void ex_draw_net_wire(UL_SEGMENT SEG, string netname) {
+ SEG.pinrefs(P) {
+ if (P.pin.direction != PIN_DIRECTION_SUP) { // 2014-01-15 keine Supply-Pins ausgeben
+ printf("@Part%c%s%c%s%c%s\n", Separator, P.part.name, Separator, P.pin.name, Separator, netname);
+ }
+ }
+ return;
+}
+
+void ex_globalattribute(UL_SCHEMATIC SCH) { // 2014-02-11
+ int cnta = 0;
+ SCH.attributes(A) {
+ if (strstr(A.name, "FEL_") == 0) { // nur Attribute die mit "FEL_" beginnen werden exportiert
+ cnta++;
+ printf("%s%c%s%c%s\n", GlobalAttribute, Separator, A.name, Separator, A.value);
+ }
+ }
+ if (cnta < PCBsimGlobalAttributeCount) {
+ dlgMessageBox("!Not enough global attributes \"FEL_...\" defined.\nFirst define global attributes for PCBsim (Design-Rules).", "OK");
+ exit("ATTRIBUTE *");
+ }
+}
+
+void ex_attribute(UL_PART P) { // für Option /I nur die Attribute dieser Instance ausgeben
+ printf("%s%cVALUE%c%s\n", P.name, Separator, Separator, P.value);
+ P.attributes(A) { // Das Attribute _EXTERNAL_ wird nicht ausgegeben, da es speziell für Bauteile
+ // reserviert ist, die nur für Simulation oder Dokumentation vorgesehen sind,
+ // und daher kein Package besitzen dürfen, um nicht im Board zu erscheinen.
+ if (A.name != "_EXTERNAL_") printf("%s%c%s%c%s\n", P.name, Separator, A.name, Separator, A.value);
+ }
+ return;
+}
+
+void ex_pinlist(UL_PART PA) {
+ /*
+ Definition der Pinlist:
+ Part-Name __Kennung__ Pin-Name Pad-Name Net-Name
+ Besitzt der Pin keinen Conntact (Pad) wird er mit *_PCBsim_* markiert.
+ Ist der Pin an keinem Net angeschlossen, wird er mit *_not_connected_* markiert.
+ */
+ PA.instances(I) {
+ I.gate.symbol.pins(P) {
+ string netcontact = P.net;
+ if (!netcontact) netcontact = "*_not_connected_*"; // Pin ist an keinem Net angeschlossen
+ int cntcont = 0; // Contactzähler für die Pads
+ P.contacts(C) {
+ printf("%s%c__PinList__%c%s%c%s%c%s\n", PA.name, Separator, Separator, P.name, Separator, C.name, Separator, netcontact);
+ cntcont++;
+ }
+ if (!cntcont) { /* Pin hat keinen Contact zu einem PAD (also ohne Package),
+ dann wird als Kennung *_PCBsim_* ausgegeben.
+ */
+ printf("%s%c__PinList__%c%s%c%s%c%s\n", PA.name, Separator, Separator, P.name, Separator, "*_PCBsim_*", Separator, netcontact);
+ }
+ }
+ }
+ return;
+}
+
+/* **** EXPORT menu **** */
+void ex_setupmenu(void) {
+ string schexportname;
+ dlgDialog("Eagle-felicitas Setup") {
+ dlgHBoxLayout dlgSpacing(200);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-2); }
+ dlgStretch(1);
+ dlgLabel(ULP_Version);
+ }
+ };
+ saveconfig();
+ return;
+}
+
+
+void autosetupinfo(string dlgheader) {
+ dlgDialog(dlgheader) {
+ dlgGridLayout {
+ dlgCell( 0, 1) dlgLabel("Program:");
+ dlgCell( 0, 2) dlgLabel(EAGLE_SIGNATURE);
+ dlgCell( 1, 1) dlgLabel("System:");
+ dlgCell( 1, 2) dlgLabel(OS_SIGNATURE);
+ dlgCell( 2, 1) dlgLabel("Eagle Path:");
+ dlgCell( 2, 2) dlgLabel(EAGLE_PATH);
+ dlgCell( 3, 1) dlgLabel("Eagle Dir:");
+ dlgCell( 3, 2) dlgLabel(EAGLE_DIR);
+ dlgCell( 4, 1) dlgLabel("User Dir:");
+ dlgCell( 4, 2) dlgLabel(EAGLE_HOME);
+ dlgCell( 5, 1) dlgLabel("");
+ dlgCell( 5, 2) dlgLabel("");
+ dlgCell( 6, 1) dlgLabel("Executable");
+ dlgCell( 6, 2) dlgLabel(Executable);
+ dlgCell( 7, 1) dlgLabel("FelicitasLibDir");
+ dlgCell( 7, 2) dlgLabel(FelicitasSimulationLbr);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ //dlgPushButton("-CANCEL") {dlgReject(); exit(-10); }
+ dlgStretch(1);
+ if (dlgheader == "Diagnose") {
+ dlgPushButton("Save") {
+ string rptfile = filesetext(argv[0], ".fel");
+ output(rptfile, "wt") {
+ printf("Program:%c%s\n", Separator, EAGLE_SIGNATURE);
+ printf("System:%c%s\n", Separator, OS_SIGNATURE);
+ printf("Eagle Path:%c%s\n", Separator, EAGLE_PATH);
+ printf("Eagle Dir:%c%s\n", Separator, EAGLE_DIR);
+ printf("User Dir:%c%s\n", Separator, EAGLE_HOME);
+ printf("Executable:%c%s\n", Separator, Executable);
+ printf("FelicitasLibDir:%c%s\n", Separator, FelicitasSimulationLbr);
+ }
+ dlgMessageBox("Saved to:"+rptfile, "OK");
+ }
+ }
+ }
+ };
+ return;
+}
+
+void reload(void) {
+ string frpcbsim_singleattributes_txt;
+ string frpcbsim_allattributes_txt;
+ int answer = 0; // für Datei-Hand-Shake
+ do {
+ if (check_exist_file(FrPCBSim_SingleAttributes_txt, "")) {
+ fileread(frpcbsim_singleattributes_txt, FrPCBSim_SingleAttributes_txt);
+ //move and rename to logging dir // = "FrPCBSim_SingleAttributes.txt";
+ move_and_rename_to_logging(FrPCBSim_SingleAttributes_txt);
+ set_attributes(frpcbsim_singleattributes_txt);
+ answer = 1;
+ }
+ if (check_exist_file(FrPCBSim_AllAttributes_txt, "")) {
+ fileread(frpcbsim_allattributes_txt, FrPCBSim_AllAttributes_txt);
+ //move and rename to logging dir // = "FrPCBSim_SingleAttributes.txt";
+ move_and_rename_to_logging(FrPCBSim_AllAttributes_txt);
+ set_attributes(frpcbsim_allattributes_txt);
+ answer = 1;
+ }
+ sleep(1); // 1 Sekunde warten, ohne CPU-Last
+ } while (!answer);
+
+ exit(-718); // hier kommt das Programm niemals her.
+}
+
+/* ***********************
+ ******** MAIN ***********
+ *********************** */
+readconfig();
+
+if (!Executable || argv[1] == "/S") {
+ string rootpath[];
+ if (OS_System == "Windows" ) {
+ rootpath[0] = "C:/Programme/";
+ rootpath[1] = "C:/Program files (x86)/";
+ rootpath[2] = "C:/Program files/";
+ rootpath[3] = "D:/Program files (x86)/";
+ rootpath[4] = "D:/Program files/";
+ rootpath[5] = "E:/Programme";
+ rootpath[6] = "C:/";
+ }
+ else if (OS_System == "Linux" ) rootpath[0] = "//";
+ else {
+ dlgMessageBox("!PCBsim runs not on MAC OS", "OK");
+ exit(-740);
+ }
+ int nroot = 0;
+ do {
+ Executable = file_search(rootpath[nroot],Search_Felicitas_Execute, 3, "550");
+ nroot++;
+ } while (!Executable && rootpath[nroot]);
+
+ if (!Executable) {
+ dlgMessageBox("!felicitas (" + Search_Felicitas_Execute + ") not found.", "OK");
+ Executable = dlgFileOpen(Search_Felicitas_Execute);
+ if (!Executable) exit(-751);
+ }
+
+ int pos = strstr(EagleExecute, "bin/"); // nur den Hauptpfad zu den Unterordnern
+ string eagleroot = strsub(EagleExecute, 0, pos);
+
+ // durchsuche alle Pfade nach der LBR
+ // string cfgdirlbr = cfgget("EAGLE:Directories.Lbr");
+ // den Pfad unter Optionen Verzeichnisse zu den LBRs!
+ for (int fn = 0; path_lbr[fn]; fn++) {
+ //if (dlgMessageBox("Suche in " + path_lbr[fn] + " nach " + SearcheLibrary, "ok", "esc") != 0) exit(568);
+ FelicitasSimulationLbr = file_search( path_lbr[fn], SearcheLibrary, 1, "-644"); // die Symbole zum simulieren
+ if (FelicitasSimulationLbr) break;
+ }
+ if (!FelicitasSimulationLbr) {
+ dlgMessageBox("!Default felicitas simulation library " + SearcheLibrary + "\nnot found:\n" + EAGLE_DIR + "..\n\n" +
+ "Please check path: Controlpanel - Options - Libraries" , "CANCEL");
+ // 2013-10-01 Pfadtrenner nach EAGLE_DIR und lbr...
+ exit(-768);
+ }
+
+ autosetupinfo("Auto Setup Info");
+ saveconfig();
+ // die felicitas LBR in die USE-Liste eintragen!
+ string uselbr;
+ sprintf(uselbr, "USE -*;\nUSE '%s';", FelicitasSimulationLbr);
+ // Pfade immer in ' (Apostroph) einschließen, besonders bei Windows 7/8 64-Bit,
+ // da es den Ordner "Programm (x86)" gibt, und die Klammern () von Eagle als Koordinate ausgewertet werden!
+ // für die felicitas.lbr muß der absolute Pfad angegeben werden.
+ if (dlgMessageBox("Die USE-Liste ändern?\n\n" + uselbr, "OK", "CANCEL") != 0) exit(-780);
+ exit(uselbr);
+}
+
+// 1. check exist used directory
+if (!check_directory(EAGLE_HOME + Exchange_Directory + "/" + Logging_Directory)) {
+ if (!make_sub_dir(EAGLE_HOME, Exchange_Directory + "/" + Logging_Directory)) { // 2014-02-26
+ if (dlgMessageBox("can't make directory :" + EAGLE_HOME + Exchange_Directory + "/" + Logging_Directory + "\nPlease check rights and the path.", "OK", "CANCEL810") != 0) exit(-788);
+ exit(-787);
+ }
+}
+
+// 2. check is PCBsim running
+if (check_exist_file(PCBSim_Present_txt, "")) {
+ string pcbsimpresent[];
+ int n = fileread(pcbsimpresent, PCBSim_Present_txt);
+ // "VERSION 1 01 Windows Beta version"
+ //dlgMessageBox("PCBsim " + pcbsimpresent[1] + " is running!", "OK");
+ PCBsim_running = 1;
+}
+else {
+ if (Test) dlgMessageBox("PCBsim start now!", "OK"); // die Meldung, das PCBsim jetzt zum ersten mal gestartet wird.
+ PCBsim_running = 0;
+}
+
+// 3. check if PCBsim is busy
+if (check_exist_file(PCBSim_Busy_txt, "")) {
+ string pcbsymbusy;
+ int n = fileread(pcbsymbusy, PCBSim_Busy_txt);
+ dlgMessageBox(pcbsymbusy + "\n\n" "Please try later.", "OK");
+ exit(-809);
+ do {
+ sleep(1); // sleep 1 seconds to check if file time changed
+ } while (check_exist_file(PCBSim_Busy_txt, ""));
+ dlgMessageBox("PCBsym are now ready.", "OK");
+ exit(-814);
+}
+
+/* *****************************
+ ******** main Import **********
+ ***************************** */
+if (argv[1] == "/RELOAD") { /* **** Laden der berechneten Rückgabewerte **** */
+ status("reload ");
+ string reload_text = argv[2];
+ status("wait on PCBsim to reload " + reload_text);
+ int n = 0;
+ do {
+ sleep(1); // sleep 1 second to new check
+ n = check_exist_file(reload_text, "");
+ if (Test) {
+ string h;
+ sprintf(h, "(Test) file %s are exist %d", reload_text, n);
+ if (dlgMessageBox(h, "ok", "esc") != 0) exit(-831);
+ }
+ } while(n);
+ status("start handshake..");
+ reload();
+}
+
+/* *************************
+ ******** Diagnostic *******
+ ************************* */
+if (strupr(argv[1]) == "/?") { // 2013-10-01
+ //autosetupinfo("Diagnose");
+ dlgDialog("Help") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(200);
+ dlgTextView(usage);
+ }
+ dlgHBoxLayout {
+ dlgLabel("System: "+OS_SIGNATURE);
+ dlgStretch(1);
+ dlgLabel("ULP Version : " + ULP_Version);
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ exit(-862);
+}
+
+/* ******************************
+ ******** main Export ***********
+ ****************************** */
+if (strupr(argv[2]) == "/S") {
+ ex_setupmenu();
+ exit(0);
+}
+
+if(board) {
+ dlgMessageBox("Die Option der Board-Simulation ist noch nicht verfügbar!", "OK");
+ exit(-875);
+}
+if (schematic) schematic(SCH) {
+ if (strupr(argv[1]) == "/E" || strupr(argv[1]) == "/I") {
+ if (Test) if (dlgMessageBox("(Test) Export Schematic to:\n" + ToPCBSim_Netlist_txt, "OK", "CANCEL") != 0) exit(-879);
+ sheet(S) {
+ if (strupr(argv[1]) == "/E") {
+ S.nets(N) {
+ N.segments(SEG) {
+ if(ingroup(SEG)) {
+ ExportAll = 0;
+ break;
+ }
+ }
+ if (!ExportAll) break;
+ }
+ output(ToPCBSim_AllAttributes_txt, "wt") { // make a new file
+ printf("***** %s, %s *****\n", ToPCBSim_AllAttributes_txt, t2string(time(), "Uyyyy/MM/dd, hh:mm:ss"));
+ ex_globalattribute(SCH);
+ S.instances(I) {
+ if (newpart(I)) { // 2014-02-12 export the Attributes of part only once
+ ex_attrib_value(I);
+ }
+ }
+ }
+ output(ToPCBSim_Netlist_txt, "wt") {
+ printf("***** %s, %s *****\n", ToPCBSim_Netlist_txt, t2string(time(), "Uyyyy/MM/dd, hh:mm:ss"));
+ printf("***** %s Version %s *****\n", filename(argv[0]), ULP_Version);
+ S.nets(N) N.segments(SEG) {
+ if (ingroup(SEG) || ExportAll) {
+ ex_draw_net_wire(SEG, N.name);
+ }
+ }
+ printf("@END");
+ }
+ output(ToPCBSim_AllAttributes_txt, "at") printf("@END"); // write @END
+ }
+ else if (strupr(argv[1]) == "/I") { // nur die Attribute dieser Instance
+ S.instances(I) {
+ if (ingroup(I)) {
+ output(ToPCBSim_SingleAttributes_txt, "wt") { // make a new file
+ printf("***** %s, %s *****\n", ToPCBSim_SingleAttributes_txt, t2string(time(), "Uyyyy/MM/dd, hh:mm:ss"));
+ ex_globalattribute(SCH); // 2014-02-12
+ ex_attribute(I.part);
+ ex_pinlist(I.part);
+ printf("@END"); // write @END
+ }
+ break;
+ }
+ }
+ }
+
+ status(" ..waiting to return of "+filename(Executable));
+
+ if (Ex_WaitOnHandShake) { /* *** Handshake über Datei-Polling *** */
+ status("wait on handshake of PCBsim");
+ // Wenn PCBsim schon läuft, reicht es, wenn die Datei geschrieben wurde,
+ // ansonsten muß PCBsim gestartet und die Datei übergeben werden.
+ if (!PCBsim_running) {
+ string syscommand;
+ if (OS_System == "Windows") {
+ //sprintf(syscommand, "CMD.EXE /C \"%s\" \"%s\"", lash2backslash(Executable), lash2backslash(ToPCBSim_Netlist_txt));
+ // *** call external programm, exit from call directly on WINDOWS XP ***
+ sprintf(syscommand, "\"%s\" \"%s\"", lash2backslash(Executable), lash2backslash(ToPCBSim_Netlist_txt));
+ if (Test) syscommand = showsyscommand(syscommand, "(Test) Main /E xport SCH", "Ex_WaitOnHandShake");
+ system(syscommand); // externes Programm starten
+ }
+ else if (OS_System == "Linux") {
+ sprintf(syscommand, "\"%s\" < \"%s\" &", Executable, ToPCBSim_Netlist_txt); // der Linux programm aufruf mit &
+ if (Test) syscommand = showsyscommand(syscommand, "(Test) Main /E xport SCH", "Ex_WaitOnHandShake");
+ system(syscommand); // externes Programm starten
+ }
+ }
+ if (Test) if (dlgMessageBox("(Test) Jetzt Daten zurück lesen!", "OK", "ESC") != 0) exit(-948);
+ reload();
+ exit(0);
+ }
+ else {
+ /* *****************************************************************************************
+ Kein Handshake, das ULP wartet auf die Beendigung des aufgerufenen Programm (DOS-BOX)
+ und kehrt dann zum aufrufenden Fenster zurück.
+ Vorteil, das Fenster (Schaltplan) hat den Fokus wieder!
+ ****************************************************************************************** */
+ if (OS_System == "Windows") { /* ** generate DOS command MKDIR ** */
+ call_system(ToPCBSim_Netlist_txt, "NO handshake, wait on return from system call");
+ }
+ else if (OS_System == "Linux") {
+ ;
+ }
+ reload();
+ }
+ }
+ }
+}
+else {
+ dlgMessageBox("Start this ULP in a schematic!", "OK");
+ exit(-971);
+}
+
diff --git a/trunk/ulp/README b/trunk/ulp/README
new file mode 100644
index 00000000..dbce6f21
--- /dev/null
+++ b/trunk/ulp/README
@@ -0,0 +1 @@
+Please see docs/pcbgcode.pdf.
diff --git a/trunk/ulp/bom.ulp b/trunk/ulp/bom.ulp
new file mode 100644
index 00000000..1603413e
--- /dev/null
+++ b/trunk/ulp/bom.ulp
@@ -0,0 +1,694 @@
+#require 6.5100
+
+// Revision history:
+//
+// 1.00
+// - Initial release
+//
+// 1.01
+// - Dialog mask for text or html output selection corrected
+//
+// 1.02
+// - CSV export added after a suggestion of Christian Schlittler
+// - File extension for text file output changed from .bom to .txt
+//
+// 1.03
+// - Added missing description column in value mode.
+//
+// 1.04
+// - List also Packages bei Value
+//
+// 1.05
+// - 2012-03-01 change PartValue[], PartDevice[], PartPackage[], PartHeadline[], PartDescription[] to normal string. alf@cadsoft.de
+// numeric strings with only numericasl characters, sorts up to 8 characters!
+//
+// 1.06
+// - 2012-05-25 support now populated variants
+// switch on/off attributes
+// is now the standard bom.ulp alf@cadsoft.de
+//
+// 1.07
+// - 2012-06-22 set correct variant
+//
+// 1.08
+// - 2012-11-08 list different values of attributes
+//
+// 1.09
+// - 2012-12-04 now can change the separator character for CSV files.
+// change the character in line Separator = ',';
+//
+// 1.10
+// - 2014-08-07 extended to V7 hierarchical schematic
+//
+// Revision: 1.10
+//
+
+string Version = "1.10";
+
+char Separator = ';'; // 2012-12-04
+
+
+#usage "en: Export a Bill Of Material\n"
+ "
"
+ "Generates a project's Bill Of Material including the attributes introduced in"
+ " version 5.0.0."
+ "
"
+ "Author: support@cadsoft.de "
+ "Modified to use the new attributes by Carsten Wille. "
+ ".csv export added by Christian Schlittler."
+ "Select variant and switch on/off attributes alf@cadsoft.de",
+ "de: Stückliste exportieren\n"
+ "
"
+ "Erzeugt die Stückliste (Bill Of Material) eines Projekts, einschließlich der"
+ " mit Version 5.0.0 neu eingeführten Attribute."
+ "
"
+ "Autor: support@cadsoft.de "
+ "Modifiziert von Carsten Wille, um die neuen Attribute zu nutzen. "
+ "Export als .csv-Datei durch Christian Schlittler hinzugefügt."
+ "Auswählen von Bestückungs-Varianten und Attribute können ein/ausgeschaltet werden alf@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string HelpTextEN =
+ "How to generate the Bill Of Material\n"
+ "
\n"
+ "List type\n"
+ "
\n"
+ "The Bill Of Material can be generated either as a list\n"
+ "of parts (where every part is listed on a line of its own),\n"
+ "or as a list of values, where all parts with the same value are grouped\n"
+ "together in one line. Use the Parts and Values\n"
+ "radio buttons to select the list type.\n"
+ "
\n"
+ "Output format\n"
+ "
\n"
+ "Choose between pure ASCII Text format, CSV or HTML.\n"
+ ;
+
+string HelpTextDE =
+ "Erzeugen der Stückliste\n"
+ "
\n"
+ "Listen-Typ\n"
+ "
\n"
+ "Die Stückliste kann entweder als Liste der Bauteile generiert werden\n"
+ "(wobei jedes Bauteil in einer eigenen Zeile aufgeführt wird),\n"
+ "oder als Liste der Werte, wobei alle Bauteile mit dem gleichen Wert in einer Zeile\n"
+ "zusammengefasst werden. Mit den Radio-Buttons Bauteile und Werte\n"
+ "kann zwischen den beiden Listen-Typen gewählt werden.\n"
+ "
\n"
+ "Ausgabeformat\n"
+ "
\n"
+ "Wählen Sie zwischen reinem ASCII-Text, CSV oder HTML"
+ "-Format.\n"
+ ;
+
+string I18N[] = {
+ "en\v"
+ "de\v"
+ ,
+ "
ERROR: No schematic!
\nThis program can only work in the schematic editor.\v"
+ "
\nThis program can only work in"
+ " the schematic editor."));
+ exit (1);
+}
+
+string SeparatorString;
+int NumParts;
+numeric string Lines[];
+numeric string PartName[];
+string PartValue[], PartDevice[], PartPackage[], PartHeadline[];
+numeric string PartDescription [];
+int PartValueOn[];
+int Selected;
+
+string CurrentVariant = "";
+string Variants[] = { "" }; // 2012-04-16
+int cntVD = 0;
+int VDsel = 0;
+
+
+// cwi: Added arrays for an arbitraty number of attributes.
+int UseAttributes = 1;
+int FoundAttributes = 0; // # of different attribute names found in schematic.
+numeric string AttributesList[]; // Sorted list of all attributes found in the schematic.
+numeric string PartAttributes[]; // Adjusted list of attributes per part.
+
+enum { ltParts, ltValues }; // List Types
+enum { ofText, ofCSV, ofHTML }; // Output Formats
+int ListType = 0;
+int OutputFormat = 0;
+
+
+string StripWhiteSpace (string s)
+{
+ while (s && isspace (s[0]))
+ s = strsub (s, 1);
+ while (s && isspace (s[strlen (s) - 1]))
+ s = strsub (s, 0, strlen (s) - 1);
+ return s;
+}
+
+
+// Collect part data from the schematic.
+//
+// Arguments: -
+//
+// Returns: NumParts - # of found parts
+// ParteName[]
+// PartValue[]
+// PartDevice[]
+// PartPackage[]
+// PartHeadline[]
+// PartDescription []
+// PartValueOn[] - 0=part value off, 1= part value on, 2=override with attr. VAL
+// FoundAttributes - # of different attribute names found in schematic.
+// AttributesList[] - Sorted list of all attributes found in the schematic.
+// PartAttributes[] - Adjusted list of attributes per part.
+
+void CollectPartData (string var)
+{
+ int Found = 0;
+ int i;
+ string attr[];
+
+ NumParts = 0;
+
+ // First, collect the names of all available attributes.
+ FoundAttributes = 0;
+ if (UseAttributes) {
+ schematic (SCH)
+ {
+ SCH.allparts (P) // 2014-08-07
+ {
+ if (P.device.package)
+ {
+ if (P.populate)
+ {
+ P.attributes (A)
+ {
+ if (0 == FoundAttributes)
+ {
+ // First one
+ AttributesList[0] = A.name;
+ FoundAttributes = 1;
+ }
+ else
+ {
+ Found = 0;
+ for (i = 0; i < FoundAttributes; i ++)
+ {
+ if (A.name == AttributesList[i])
+ {
+ // Found an already listed atrribute
+ Found = 1;
+ break;
+ }
+ }
+ if (0 == Found)
+ {
+ // Attribute not listed, add at the end.
+ AttributesList[FoundAttributes] = A.name;
+ FoundAttributes ++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ sort (FoundAttributes, AttributesList);
+ }
+ // Second, collect all data
+ schematic (SCH)
+ {
+ SCH.allparts (P)
+ {
+ if (P.device.package)
+ {
+ if (P.populate)
+ {
+ PartName[NumParts] = P.name;
+ PartValue[NumParts] = P.value;
+ PartDevice[NumParts] = P.device.name;
+ PartPackage[NumParts] = P.device.package.name;
+ PartHeadline[NumParts] = P.device.headline;
+ PartDescription [NumParts] = P.device.description;
+ PartValueOn[NumParts] = P.device.value == "On";
+ // Zero all strings
+ for (i = 0; i < FoundAttributes; i ++)
+ attr[i] = "";
+ P.attributes(A)
+ {
+ for (i = 0; i < FoundAttributes; i ++)
+ if (A.name == AttributesList[i])
+ {
+ attr[i] = A.value;
+ break;
+ }
+ if ("VALUE" == A.name && 0 < strlen (A.value))
+ // Override old fashioned value information!
+ PartValueOn[NumParts] = 2;
+ }
+ PartAttributes[NumParts] = strjoin(attr, Separator);
+ NumParts ++;
+ }
+ }
+ }
+ }
+}
+
+
+void GeneratePartList(void)
+{
+ int NumLines = 0;
+ string attr[], s;
+
+ if (UseAttributes) s = strjoin(AttributesList, '\t');
+ Lines[NumLines ++] = tr ("Part\tValue\tDevice\tPackage\tDescription\t") + s;
+ for (int i = 0; i < NumParts; i ++)
+ {
+ strsplit (attr, PartAttributes[i], Separator);
+ if (UseAttributes) s = strjoin(attr, '\t');
+ Lines[NumLines] = PartName[i] + "\t" + PartValue[i] + "\t" + PartDevice[i] + "\t" +
+ PartPackage[i] + "\t" + PartHeadline[i] + "\t" + s;
+ NumLines ++;
+ }
+ Lines[NumLines] = "";
+}
+
+
+// Generate list with one entry per value.
+// 'VALUE' is replaced by the value of attribute 'VAL', if existing.
+
+void GenerateValueList (void)
+{
+ int NumLines = 0;
+ int Index [];
+ string attr[], s, s_val;
+
+ if (UseAttributes) s = strjoin(AttributesList, '\t');
+
+ // 2010-04-17 cwi: Included description.
+ Lines[NumLines ++] = tr ("Qty\tValue\tDevice\tPackage\tParts\tDescription\t") + s; // 2011-04-08
+ sort (NumParts, Index, PartValue, PartDevice, PartPackage, PartAttributes, PartName, PartHeadline); // 2011-11-08 Partattribute jetzt nach Package alf@cadsoft.de
+ for (int n1 = 0, n2 = 0; ++ n2 <= NumParts; )
+ {
+ int i1 = Index [n1];
+ strsplit (attr, PartAttributes[i1], Separator);
+ if (UseAttributes) s = strjoin(attr, '\t');
+ s_val = attr[i1];
+ if (n2 < NumParts)
+ {
+ int i2 = Index [n2]; // 2012-11-08
+ strsplit (attr, PartAttributes[i2], Separator);
+ if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2] && PartAttributes[i1] == PartAttributes[i2]) // 2012-11-08 check diffent values of attributes
+ continue;
+ }
+ string Quantity;
+ sprintf (Quantity, "%d", n2 - n1);
+ Lines[NumLines] = Quantity + "\t" + PartValue[i1] + "\t" + PartDevice[i1] + "\t" + PartPackage[i1] + "\t";
+ for (;;)
+ {
+ Lines[NumLines] += PartName[i1];
+ if (++n1 < n2)
+ {
+ i1 = Index [n1];
+ Lines[NumLines] += ", ";
+ }
+ else
+ break;
+ }
+ // cwi: add extra information from attributes
+ // 2010-04-17 cwi: Included description.
+ Lines[NumLines] += "\t" + PartHeadline[i1] + "\t" + s;
+ NumLines ++;
+ }
+ Lines[NumLines] = "";
+}
+
+
+void GenerateList (void)
+{
+ switch (ListType)
+ {
+ case ltParts: GeneratePartList (); break;
+ case ltValues: GenerateValueList (); break;
+ }
+}
+
+
+string MakeListHeader (void)
+{
+ string s;
+ schematic(SCH)
+ sprintf (s, tr ("Partlist exported from %s at %s"), SCH.name, t2string (time ()));
+ return s;
+}
+
+
+string MakeListText(void)
+{
+ int l, Width [];
+ string List;
+ int numHeaders;
+
+ for (l = 0; Lines[l]; l ++)
+ {
+ string a [];
+ for (int n = strsplit (a, Lines[l], '\t'); n --; )
+ Width [n] = max (Width [n], strlen (a [n]));
+ }
+
+ List = MakeListHeader () + "\n\n";
+
+ for (l = 0; Lines[l]; l ++)
+ {
+ string line, a [];
+
+ int n = strsplit (a, Lines[l], '\t');
+ if (l == 0)
+ numHeaders = n;
+ else
+ n = numHeaders; // for the hidden key!
+ for (int i = 0; i < n; i ++)
+ {
+ string s;
+
+ sprintf (s, "%s%-*s", line ? " " : "", Width [i], a [i]);
+ line += s;
+ }
+ List += line + "\n";
+ }
+ return List;
+}
+
+
+// 2008-11-24 Christian Schlittler:
+// Make comma-serparated list, with all values double-quoted.
+
+string MakeListCSV (void)
+{
+ string List;
+ int numHeaders;
+
+ for (int l = 0; Lines[l]; l ++)
+ {
+ string a [];
+ int n = strsplit (a, Lines[l], '\t');
+ if (l == 0)
+ numHeaders = n;
+ else
+ n = numHeaders; // for the hidden key!
+ for (int i = 0; i < n; i ++)
+ List += "\"" + a[i] + "\"" + SeparatorString;
+ List += "\n";
+ }
+ return List;
+}
+
+
+string MakeListHTML (void)
+{
+ string List;
+ int numHeaders;
+
+ List = "" + MakeListHeader() + "\n
\n";
+ List += "
\n";
+ for (int l = 0; Lines[l]; l++)
+ {
+ List += "
";
+ string a [];
+ int n = strsplit (a, Lines[l], '\t');
+ if (l == 0)
+ numHeaders = n;
+ else
+ n = numHeaders; // for the hidden key!
+ for (int i = 0; i < n; i ++)
+ {
+ if (l == 0)
+ a[i] = "" + a[i] + "";
+ List += "
" + a[i] + "
";
+ }
+ List += "
\n";
+ }
+ List += "
\n";
+ return List;
+}
+
+
+string MakeList (void)
+{
+ switch (OutputFormat)
+ {
+ case ofText: return MakeListText(); break;
+ case ofCSV: return MakeListCSV(); break;
+ case ofHTML: return MakeListHTML(); break;
+ }
+ return "";
+}
+
+
+void ViewList (void)
+{
+ dlgDialog (tr ("Bill Of Material - Preview"))
+ {
+ string s = MakeList ();
+ if (OutputFormat == ofText || OutputFormat == ofCSV)
+ s = "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+// CAM-Job token
+string tok_job = "[CAM Processor Job]";
+string tok_Descrition = "Description=";
+string description;
+string descriptionLine[];
+int descrCnt;
+string tok_Section = "Section=";
+string tok_Sec_n = "[Sec_";
+string section[];
+string tok_Name = "Name=";
+string sec_Name[];
+string tok_Prompt = "Prompt=";
+string sec_Prompt[];
+string tok_Out_put = "Output=";
+string sec_Out_put[];
+
+string tok_Sheet = "Sheet=";
+int sec_Sheet[];
+int sheetprint = 0; // 0 = All, 1 = From To, 2 = This section defined, 3 = Actual
+
+int sheetprint_from[];
+int sheetprint_to[];
+string actualsheet;
+
+string tok_Layers = "Layers=";
+string sec_Layers[];
+string sec_usedlayer[];
+int absolutUsedLayer = 0;
+
+string lines[];
+int nLines;
+string s;
+string nu;
+int sx = 0;
+
+int lVisible[];
+int useLayer[];
+string lNames[] = { " " };
+int lastsheet = 0;
+string lastSH;
+
+string Unit = " -u MM";
+string AlwaysVertorFont = " -a";
+string UseWireWidth = " -w";
+string FillArea = " -f";
+
+string help = usage+ "This ULP converts a CAM Job to a DXF Export script!
\n" +
+ "If the layer list is empty after starting this ULP,\n" +
+ "you did not start it from the proper editor window (SCH/BRD).
\n" +
+ "CAM jobs for the layout have to be started from the Layout Editor, " +
+ "jobs for a schematic from the Schematic Editor. " +
+ "CAM Jobs can be edited and saved by the CAM processor only.
\n" +
+ "If the layer list is empty after starting this ULP,\n" +
+ "you did not start it from the proper editor window (SCH/BRD). \n" +
+ "CAM jobs for the layout have to be started from the Layout Editor, " +
+ "jobs for a schematic from the Schematic Editor. \n" +
+ "CAM Jobs can be edited and save only by the CAM processor.
"
+ "RUN change-via-by-stack 1 2 "
+ "RUN change-via-by-stack 1 2 0.1 0.15 "
+ "RUN change-via-by-stack 1 2 0.1 0.15 SQUARE "
+ "RUN change-via-by-stack 1 2 no square "
+ "RUN change-via-by-stack 1 2 1-16 STACK "
+ "Ändert Drill, Durchmesser, Shape bzw. Stacktiefe (Via-Länge) von Vias mit angegebener Stacktiefe. "
+ "Wird die Option Drill bzw. Diameter nicht angegeben, so werden die "
+ "aktuell eingestellten (zuletzt mit CHANGE geänderten) Werte benutzt. "
+ "Wird Shape nicht angegeben, bleibt die Form unverändert. "
+ "Soll Drill bzw. Diameter nicht geändert werden, geben Sie die Option NO vor Shape an. "
+ "NO darf nicht angegeben werden, wenn Drill oder Diameter benutzt wird. "
+ "Vor der Option STACK muß die neue Stacktiefe Start-End (z.B. 2-15) angegeben werden. "
+ "Die Optionen können groß oder klein geschrieben werden."
+ "
"
+ "Author alf@cadsoft.de"
+ ,
+ "[en]Change Via by Stack (Start-Layer End-Layer) "
+ "Changes drill, diameter, shape or via stack (via length) of vias with a given via stack. "
+ "If the options Drill and/or Diameter are not used, the ULP will take the "
+ "currently valid values (previously set with the CHANGE command). "
+ "If the Shape option is not given, the via shapes stay unchanged. "
+ "If you want to have Drill and Diameter unchanged, use the option NO "
+ "before the Shape option. "
+ "You must not use NO, if Drill or Diameter are to be changed. "
+ "Define the new via stack Start-End (for example: 2-15) before the STACK option. "
+ "Upper or lower case letters does not matter here."
+ "
"
+ "FILLING also draws the filling as wire. "
+ "Layernumber the new layer of copy. "
+ "support@cadsoft.de"
+ ,
+ "de: Zeichnet die berechneten Konturen eines Polygons als WIRE.
"
+ "RUN cmd-draw-polygon-contours-as-wire SIGNALNAME [FILLING] [Layernumer] "
+ "FILLING zeichnet auch die Füllung als WIRE.
"
+ "Layernumber ist der Layer in dem die Kopie erzeugt werden soll. "
+ "support@cadsoft.de"
+
+string Version = "1.0.0"; // 2011-09-07 alf@cadsoft.de
+string f;
+string tempextension = "~.scr";
+int Ratsnest = 0;
+
+int Newlayer = strtol(argv[3]);
+
+if (!argv[1]) {
+ if (language() == "de") dlgMessageBox(usage + "
Geben Sie einen SIGNALNAMEN an.", "OK");
+ else dlgMessageBox(usage + "
Missing SIGNALNAME.", "OK");
+ exit(-1);
+}
+
+if (board) {
+ board(B) {
+ f = filesetext(B.name, tempextension);
+ output(f, "wtD") {
+ printf("GRID MM;\nSET WIRE_BEND 2;\n");
+ B.signals(S) {
+ if (S.name == strupr(argv[1]) ) {
+ S.polygons(P) {
+ if (P.layer == 1 || P.layer == 16) {
+ printf("CHANGE LAYER %d;\nCHANGE WIDTH %.4f;\n", P.layer, u2mm(P.width) );
+ if (P.thermals) printf("CHANGE THERMAL ON;\n");
+ else printf("CHANGE THERMAL OFF;\n");
+ P.fillings(W) {
+ Ratsnest = 1;
+ break;
+ }
+ if (!Ratsnest) {
+ if (language() == "de") dlgMessageBox("!Starten Sie zuerst RATSNEST um die Füllung der Polygone zu berechnen.", "OK");
+ else dlgMessageBox("!Start first RATSNEST to calculate polygons.", "OK");
+ exit("RATSNEST");
+ }
+ P.contours(W) {
+ if (Newlayer) printf("Layer %d;\nWIRE (%.4f %.4f) (%.4f %.4f);\n", Newlayer, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ else printf("WIRE '%s' (%.4f %.4f) (%.4f %.4f);\n", S.name, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ }
+ if (argv[2] == "FILLING") P.fillings(W) {
+ if (Newlayer) printf("Layer %d;\nWIRE (%.4f %.4f) (%.4f %.4f);\n", Newlayer, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ else printf("WIRE '%s' (%.4f %.4f) (%.4f %.4f);\n", S.name, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ exit("SCRIPT '" + f + "'");
+}
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-calcdeg.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-calcdeg.bmp
new file mode 100644
index 00000000..b2ca08b4
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-calcdeg.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-calcstep.bmp
new file mode 100644
index 00000000..d1671961
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-degstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-degstep.bmp
new file mode 100644
index 00000000..aa2323be
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-none.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-none.bmp
new file mode 100644
index 00000000..5ad8bce0
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse4-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse4-calcstep.bmp
new file mode 100644
index 00000000..826139b8
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse4-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse4-degstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse4-degstep.bmp
new file mode 100644
index 00000000..398a29cd
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse4-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-ellipse4-none.bmp b/trunk/ulp/cmd-draw-polygon-ellipse4-none.bmp
new file mode 100644
index 00000000..b14f727c
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse4-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-none-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-none-calcstep.bmp
new file mode 100644
index 00000000..7ed1cf0d
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-none-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-polygon-none.bmp b/trunk/ulp/cmd-draw-polygon-none.bmp
new file mode 100644
index 00000000..8a1be253
Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-circle-match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-circle-match-calcstep.bmp
new file mode 100644
index 00000000..2ee501ab
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-circle-match-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-circle-match-degstep.bmp b/trunk/ulp/cmd-draw-smd-circle-match-degstep.bmp
new file mode 100644
index 00000000..b671eb12
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-circle-match-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-circle-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-circle-no_match-calcstep.bmp
new file mode 100644
index 00000000..d11a8373
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-circle-no_match-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-cricle-no_match-degstep.bmp b/trunk/ulp/cmd-draw-smd-cricle-no_match-degstep.bmp
new file mode 100644
index 00000000..8658461c
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-cricle-no_match-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse-match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse-match-calcstep.bmp
new file mode 100644
index 00000000..c321cb69
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-match-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse-match-degstap.bmp b/trunk/ulp/cmd-draw-smd-ellipse-match-degstap.bmp
new file mode 100644
index 00000000..bf8503de
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-match-degstap.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse-no_match-calcstep.bmp
new file mode 100644
index 00000000..57f5ce2b
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-no_match-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse-no_match-degstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse-no_match-degstep.bmp
new file mode 100644
index 00000000..ffb7b3f1
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-no_match-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-match-calcstep.bmp
new file mode 100644
index 00000000..0f7ad8ca
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-match-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-match-degstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-match-degstep.bmp
new file mode 100644
index 00000000..4fafc5c3
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-match-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-calcstep.bmp
new file mode 100644
index 00000000..eb8e4f3a
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-no_match-degstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-degstep.bmp
new file mode 100644
index 00000000..d172797c
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-match-degstep.bmp b/trunk/ulp/cmd-draw-smd-match-degstep.bmp
new file mode 100644
index 00000000..b0386be0
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-match-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-match-none.bmp b/trunk/ulp/cmd-draw-smd-match-none.bmp
new file mode 100644
index 00000000..b084676d
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-match-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-no_match-degsetp.bmp b/trunk/ulp/cmd-draw-smd-no_match-degsetp.bmp
new file mode 100644
index 00000000..a274a63f
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-no_match-degsetp.bmp differ
diff --git a/trunk/ulp/cmd-draw-smd-no_match-none.bmp b/trunk/ulp/cmd-draw-smd-no_match-none.bmp
new file mode 100644
index 00000000..2463bc4e
Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-no_match-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-calc-ellipse.bmp b/trunk/ulp/cmd-draw-wire-calc-ellipse.bmp
new file mode 100644
index 00000000..0b7b2572
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-calc-ellipse.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-calcstep-none.bmp b/trunk/ulp/cmd-draw-wire-calcstep-none.bmp
new file mode 100644
index 00000000..c858135e
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-calcstep-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-circle-calcstep.bmp b/trunk/ulp/cmd-draw-wire-circle-calcstep.bmp
new file mode 100644
index 00000000..ef597a8e
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-circle-calcstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-circle-degstep.bmp b/trunk/ulp/cmd-draw-wire-circle-degstep.bmp
new file mode 100644
index 00000000..424ab584
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-circle-degstep.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-clac-ellipse4.bmp b/trunk/ulp/cmd-draw-wire-clac-ellipse4.bmp
new file mode 100644
index 00000000..73ec4d12
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-clac-ellipse4.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-degstep-none.bmp b/trunk/ulp/cmd-draw-wire-degstep-none.bmp
new file mode 100644
index 00000000..3bca32e9
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-degstep-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-ellipse.bmp b/trunk/ulp/cmd-draw-wire-ellipse.bmp
new file mode 100644
index 00000000..4e74965d
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-ellipse.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-none.bmp b/trunk/ulp/cmd-draw-wire-none.bmp
new file mode 100644
index 00000000..5900e046
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-none.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-step-ellipse.bmp b/trunk/ulp/cmd-draw-wire-step-ellipse.bmp
new file mode 100644
index 00000000..b0d11e36
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-step-ellipse.bmp differ
diff --git a/trunk/ulp/cmd-draw-wire-step-ellipse4.bmp b/trunk/ulp/cmd-draw-wire-step-ellipse4.bmp
new file mode 100644
index 00000000..e66f8b8c
Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-step-ellipse4.bmp differ
diff --git a/trunk/ulp/cmd-draw.ulp b/trunk/ulp/cmd-draw.ulp
new file mode 100644
index 00000000..8c4fb630
--- /dev/null
+++ b/trunk/ulp/cmd-draw.ulp
@@ -0,0 +1,1587 @@
+#usage "en: Command draw
Options:
"
+ "+ distance/radius "
+ "Angle start [Angle step] [End angle] "
+ "[Layer] "
+ "[Wire & width] "
+ "[Xcoordinate] [Ycoordinate] ** "
+ "[Polygon] "
+ "[Pad || Smd || Via] "
+ "[Width Length] SMD_dx SMD_dy "
+ "[-Name] signal/pad/smd "
+ "[Diameter] for Pad/Via, if used "
+ "[Drill] for Pad/Via/Hole, if used "
+ "[] define angle (in degrees) for step "
+ "[/] define number of steps within start and end angle "
+ "[Group] rotate and paste "
+ "[rotate match] "
+ "[MOVE] elements on place by order start with name (only in Board) "
+ "[Circle] emulate/draw a cricle with wire or polygon "
+ "[full ellipse 0] "
+ "[Ellipse factor] height = radius * f "
+ "[1/4 ellipse] 90 degree, 1st quadrant "
+ " "
+ "** If MARK is set in PAC/BRD/SCH editor, coordinates are relativ. "
+ "Parameters can be used in any order; not case sensitive."
+ "
"
+ "Author: alf@cadsoft.de
",
+
+ "de: Command draw
Optionen:
"
+ "+ Distance/Radius "
+ "Startwinkel [Winkelschritt oder Anzahl (# .)] [Endwinkel] "
+ "[Layer] "
+ "[Wre width] setzt die Breite (width) und den Befehl WIRE. "
+ "Für Polygon muß W vor O angegeben werden. "
+ "[X-Koordinate] [Y-Koordinate] ** "
+ "[Polygon] "
+ "[Pad || Smd || Via] "
+ "[Width Length] SMD_dx SMD_dy "
+ "[-Name] Signal/Pad/Smd "
+ "[Diameter] für Pad/Via, wenn benutzt "
+ "[Drill] für Pad/Via/Hole, wenn benutzt "
+ "[] Winkelschritt in Grad "
+ "[/] berechnet den Winkel (End - Start / Anzahl "
+ "[Group] Pasted die Gruppe rotiert. "
+ "Die Gruppe kann vor dem Start des ULP definiert werden, "
+ "oder das ULP selektiert alle sichtbaren Objekte als Gruppe. "
+ "[Rotate match] dreht die Bauteile/Pad/Smd im selben Winkel in dem sie angeordnet werden "
+ "[MOVE] plaziert Elemente aufsteigend beginnend mit dem angegebenen Namen (nur im Board nutzbar ) "
+ "[Circle] zeichnet einen Kreis oder Ellipse als Wire oder Polygon je nach Option (W/O) "
+ "[full ellipse 0] zeichnet eine volle Ellipse "
+ "[Ellipse faktor] der Wert mit dem die Länge multipliziert wird (Raduis * f) ergibt die Länge in y "
+ "[1/4 ellipse] zeichnet nur den ersten Qudranten einer Ellipse oder Kreises "
+ " "
+ "** Ist MARK im benutzten PAC/BRD/SCH Editor gesezt, werden die Koordinaten relativ zur Marke benutzt. "
+ "Die Parameter können in beliebiger Reihenfolge angegeben und groß oder klein geschrieben werden."
+ "
"
+ "Attention:"
+ "In special situations it could happen that importing a netlist into a schematic "
+ "(in form of 'airwires' as it happens here) results in misconnections. "
+ "This is the case if a net line overlaps a pin connection point. "
+ "If this certain pin under the net should get connected later, EAGLE will connect to the net "
+ "instead of the pin under it. "
+ "We want to avoid this problem in the ULP by drawing the net "
+ "line from the first pin with an offset of 50 mil. This way "
+ "diagonal net lines will be drawn "
+ "and there will be hardly pins that lie under net lines. "
+ "If a net has to be drawn on a further sheet of the schematic "
+ "EAGLE uses the diagonal offset of 50 mil and places an "
+ "additional LABEL."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string Hilfe = "
ACHTUNG: \n"
+ "Das Einlesen einer Netzliste (Airwire) in den Schaltplan, " +
+ "kann in besonderen Situationen zu falschen Verbindungen führen. " +
+ "Werden die Netze als Luftlinien zwischen den Bauteilpins gezeichnet, " +
+ "so kann es vorkommen, dass eine Netzlinie Bauteilpins überlagert. " +
+ "Wird später dieser Pin unter der Linie an ein Netz angeschlossen " +
+ "so nimmt EAGLE das Netz als Kontaktpunkt und nicht den darunterliegenden Pin. " +
+ "In diesem ULP wird versucht diese Problematik zu umgehen, in dem vom " +
+ "ersten Pin mit einem Offset (50mil) diagonal vom Pin weg, " +
+ "und dann direkt zum zweiten Pin gezeichnet wird. " +
+ "Dadurch entstehen diagonale Luftlinien die nur in seltenen Fällen einen Pin " +
+ "überlagern. " +
+ "Wird ein Netz auf einer anderen Schaltplanseite weitergeführt, " +
+ "so wird vom Pin um 50 Mil diagonal weggezeichnet und zusätzlich " +
+ "ein LABEL plaziert.
"
+ "Opens a file dialog to select a netscript file. "
+ "Some PCB systems allow to export an EAGLE netscript file in order to make "
+ "a layout in EAGLE. This ULP allows to use the netscript to generate an "
+ "EAGLE schematic, too. At least it can be used to draw all net connections "
+ "in the schematic easily, provided all parts have been placed before. "
+ "
"
+ "Attention: "
+ "In special situations it could happen that importing a netlist "
+ "into a schematic (in form of 'airwires' as it happens here) "
+ "results in misconnections. This is the case if a net line "
+ "overlaps a pin connection point. If this certain pin under the "
+ "net should get connected later, EAGLE will connect to the net "
+ "instead of the pin under it.
"
+ "We want to avoid this problem in the ULP by drawing the net "
+ "line from the first pin with an offset of 50 mil. This way "
+ "diagonal net lines will be drawn and there will be hardly pins "
+ "that lie under net lines.
"
+ "If a net has to be drawn on a further sheet of the schematic "
+ "EAGLE uses the diagonal offset of 50 mil and places an "
+ "additional LABEL."
+ "
"
+ "Author: support@cadsoft.de"
+
+// 2006-01-26 -- modified #usage -- ric
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+/* German info
+ "ACHTUNG
\n"
+ "Das Einlesen einer Netzliste (Airwire) in den Schaltplan, "
+ "kann in besonderen Situationen zu falschen Verbindungen fuehren.
\n"
+ "Werden die Netze als "Luftlinien" zwischen den Bauteilpins gezeichnet, "
+ "so kann es vorkommen, dass eine Netzlinie Bauteilpins ueberlagert. "
+ "Wird spaeter dieser Pin unter der Linie an ein Netz angeschlossen "
+ "so nimmt EAGLE das Netz als Kontaktpunkt und nicht den "
+ "darunterliegenden Pin.
"
+ "In diesem ULP wird versucht diese Problematik zu umgehen, in dem vom "
+ "ersten Pin mit einem Offset (50mil) vom Pin weg "
+ "und dann zum zweiten Pin gezeichnet wird. Dadurch entstehen diagonale "
+ "Luftlinien die nur in seltenen Faellen einen Pin ueberlagern.
\n"
+ "Wird ein Netz auf einer anderen Schaltplanseite weitergefuehrt, "
+ "so wird vom Pin um 50 Mil diagonal weggezeichnet und zusaetzlich "
+ "ein LABEL plaziert.
"
+ "Generates a command sequence copying the name texts-wires and value texts-wires "
+ "of all elements of your layout into restrict layers (41 and 42)."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+int tNames = 25, bNames = 26;
+real distance = 0.2; // distance Wire <> Text in Millimeter.
+string cmd;
+string h;
+string scriptfile;
+
+
+string help = "If the Autorouter shall avoid the NAME and VALUE text area\n" +
+ "we have to draw the texts as wires in the restrict layers.\n" +
+ "To let the Autorouter keep a minimum distance to the texts (wires)\n" +
+ "to avoid short circuits, we have to draw the text wires with a\n" +
+ "higher width which includes the respective minimum clearance.\n" +
+ "\n"+
+ "German help text inside the ulp file.\n";
+
+
+/*string German help = "Kopiert die Texte 'Name' und 'Value' in die Restrict-Layer.\n" +
+ * "Soll der Autorouter unter den NAME- und VALUE-Texten\n" +
+ * "nicht routen, so muss der Text als Wire in die Restrict-Layer\n" +
+ * "kopiert werden.\n" +
+ * "Damit der Autorouter einen Abstand zu den Elementen (Textlinien)\n" +
+ * "einhaelt, sodass keine Kurzschluesse erzeugt werden, muss die Linienbreite\n" +
+ */ "um den entsprechenden Mindestabstand erweitert werden.\n";
+
+void header(void) {
+ sprintf(cmd, "# Exported from %s by %s\n", scriptfile, EAGLE_SIGNATURE );
+ sprintf(h, "# Distance = %.3f mm\n", distance); cmd += h;
+ cmd += "SET UNDO_LOG OFF;\n"; // advisable for speed reasons
+ cmd += "set wire_bend 2;\n";
+ cmd += "GRID mm;\n";
+}
+
+// Distance menue
+int menue(void) {
+ int d = dlgDialog("Place Text as Wire") {
+ dlgLabel(usage);
+ dlgLabel(help);
+ dlgHBoxLayout {
+ dlgLabel("&Distance [mm]");
+ dlgRealEdit(distance);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+&OK") dlgAccept();
+ dlgPushButton("-&Cancel") dlgReject();
+ dlgStretch(1);
+ }
+ };
+ return d;
+ }
+
+if (board) board(B) {
+ if (!menue()) exit (0);
+ scriptfile = filesetext(B.name, ".scr");
+ header();
+ distance *= 2;
+ B.elements(E) {
+
+ E.texts(T) { // *** smased ***
+ if (T.layer == 25) {
+ sprintf(h, "Change Layer %d;\n", 41);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ if (T.layer == 26) {
+ sprintf(h, "Change Layer %d;\n", 42);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ if (T.layer == 27) {
+ sprintf(h, "Change Layer %d;\n", 41);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ if (T.layer == 28) {
+ sprintf(h, "Change Layer %d;\n", 42);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ }
+
+ E.package.texts(T) { // *** non smased
+ if (T.layer == 25) {
+ sprintf(h, "Change Layer %d;\n", 41);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ if (T.layer == 26) {
+ sprintf(h, "Change Layer %d;\n", 42);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ if (T.layer == 27) {
+ sprintf(h, "Change Layer %d;\n", 41);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ if (T.layer == 28) {
+ sprintf(h, "Change Layer %d;\n", 42);cmd += h;
+ T.wires(W) {
+ sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n",
+ u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) );
+ cmd += h;
+ }
+ }
+ }
+ }
+}
+cmd += "SET UNDO_LOG ON;\n";
+cmd += "GRID LAST;\n";
+
+// EditBox
+int Result = dlgDialog("Copy Text in Restrict.Layer") {
+ dlgHBoxLayout {
+ dlgTextEdit(cmd);
+ dlgVBoxLayout {
+ dlgSpacing(300);
+ }
+ }
+ dlgHBoxLayout {
+ dlgSpacing(500);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+&Execute") dlgAccept();
+ dlgPushButton("-&Cancel") dlgReject();
+ dlgStretch(1);
+ }
+ };
+if (Result == 0) exit(0);
+
+output(scriptfile, "wt") printf("%s", cmd);
+
+exit("script '" + scriptfile + "';\nREMOVE '" + scriptfile + "';\n");
diff --git a/trunk/ulp/cmd-rename-in-lbr.ulp b/trunk/ulp/cmd-rename-in-lbr.ulp
new file mode 100644
index 00000000..aaca4643
--- /dev/null
+++ b/trunk/ulp/cmd-rename-in-lbr.ulp
@@ -0,0 +1,45 @@
+#usage "Rename device/symbol/package in library\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string edit = "";
+string toName = edit;
+
+if (library) library(L) {
+
+ if (deviceset) deviceset(D) {
+ edit = D.name;
+ }
+
+ if (symbol) symbol(S) {
+ edit = S.name;
+ }
+ if (package) package(P) {
+ edit = P.name;
+ }
+
+int Result = dlgDialog("RENAME") {
+ dlgStretch(0);
+ string h;
+ sprintf(h, "Rename
"
+ "See Help of the ULP for further instructions."
+ "
"
+ "Author: support@cadsoft.de (based on original code from Michel Dagenais, jcmae@sympatico.ca)"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+// 16.06.2002 "Scan window"/"Unit" do not take effect in the current instance of the program -- alf@cadsoft.de
+
+string HelpText =
+
+ "This ULP will renumber a board's components starting from any corner, renaming from suffix 1, either horizontally or vertically."
+ "
\n"
+ "If there are names like R01, the program will ask you if it may change those names. "
+ "Otherwise no renaming can be performed."
+ "
\n"
+ "Your board MUST be drawn on layer 20 (dimension) and all components MUST be inside it, otherwise the result is unpredictable.\n"
+ "
\n"
+ "
\n"
+ "Meaning of Parameters\n"
+ "
\n"
+ "Unit\n"
+ "
\n"
+ "Unit for the value entered in the Scan window.\n"
+ "
\n"
+ "Direction\n"
+ "
\n"
+ "Renumber direction.\n"
+ "
\n"
+ "Top Side: Start from\n"
+ "
\n"
+ "Renumber starting point for top (component) side.\n"
+ "
\n"
+ "Bottom Side: Start from\n"
+ "
\n"
+ "Renumber starting point for bottom (solder) side.\n"
+ "
\n"
+ "Scan window\n"
+ "
\n"
+ "Dimension of the user-defined window to determine row or column width for components scanning.\n"
+ "
\n"
+ "Bottom suffix\n"
+ "
\n"
+ "Renumbering starts at the component side.\n"
+ "If Bottom suffix is 0, the bottom component suffixes are continued in sequence.\n"
+ "If Bottom suffix is > 0, the bottom component suffixes start with this number, provided there is no overlapping with component names at the top side.\n"
+ "
\n"
+ "Show scripts\n"
+ "
\n"
+ "If this box is checked, the respective command scripts are shown before execution of Preview and Renumber. \n"
+ "The Renumber Script can be saved.\n"
+ "
\n"
+ "Preview\n"
+ "
\n"
+ "Highlights all components in the order of the currently selected renumbering sequence. \n"
+ "Please note that on fast computers Preview might be too fast to watch!\n"
+ "
\n"
+ "Renumber\n"
+ "
\n"
+ "Executes the renumber function and quits program.\n"
+ "
"
+ "Implemented for parts and signals on a board. "
+ "Could be extended for schematics."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string h, cmd = "", sname = "";
+real x, y, zoom_win = 10;
+int part = 1, xmin, xmax, ymin, ymax, found = 0;
+
+zoom_win = zoom_win/2;
+
+if (board) board(B) {
+ cmd = "grid mm finest;\n";
+ int Result = dlgDialog("Show and zoom in") {
+ dlgHBoxLayout {
+ dlgGroup("Include") {
+ dlgRadioButton("&Signals", part);
+ dlgRadioButton("&Parts", part);
+ }
+ }
+ dlgLabel("&Enter Name");
+ dlgStringEdit(sname);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ }
+ };
+ if (Result == 0) exit (0);
+
+ if (!part) { // if signals checked
+ B.signals(S) {
+ if (strupr(sname)==strupr(S.name)) {
+ found = 1;
+ S.wires(W) {
+ xmin = min(W.x1, W.x2);
+ ymin = min(W.y1, W.y2);
+ xmax = max(W.x1, W.x2);
+ ymax = max(W.y1, W.y2);
+ break;
+ }
+ S.wires(W) {
+ xmin = min(xmin, W.x1);
+ xmin = min(xmin, W.x2);
+ ymin = min(ymin, W.y1);
+ ymin = min(ymin, W.y2);
+ xmax = max(xmax, W.x1);
+ xmax = max(xmax, W.x2);
+ ymax = max(ymax, W.y1);
+ ymax = max(ymax, W.y2);
+ }
+ xmin = u2mm(xmin);
+ xmax = u2mm(xmax);
+ ymin = u2mm(ymin);
+ ymax = u2mm(ymax);
+ }
+ }
+ h = "";
+ sprintf(h, "Window (%f %f)(%f %f);\n",
+ xmin-zoom_win, ymin-zoom_win, xmax+zoom_win, ymax+zoom_win);
+ }
+
+ if (part) { // if parts checked
+ B.elements(E) {
+ if (strupr(sname)==strupr(E.name)) {
+ found = 1;
+ x = u2mm(E.x);
+ y = u2mm(E.y);
+ }
+ }
+ h = "";
+ sprintf(h, "Window (%f %f)(%f %f);\n",
+ x-zoom_win, y-zoom_win, x+zoom_win, y+zoom_win);
+ }
+
+ if (!found) {
+ dlgMessageBox("Name not found!", "&OK");
+ exit(1);
+ }
+ cmd += h;
+ cmd += "Show " + sname + ";\n";
+ cmd += "grid last;\n";
+ exit(cmd);
+ }
+else {
+ dlgMessageBox("No board loaded!");
+ exit(1);
+ }
diff --git a/trunk/ulp/cmd-snap-board.ulp b/trunk/ulp/cmd-snap-board.ulp
new file mode 100644
index 00000000..b649dd39
--- /dev/null
+++ b/trunk/ulp/cmd-snap-board.ulp
@@ -0,0 +1,246 @@
+#usage "Snap objects in a board\n"
+ "
"
+ "Snaps components, wires and vias of the current "
+ "board to a given grid. "
+ "If 'Show script' is checked, you can edit the MOVE commands "
+ "before they are executed. So you are able to exclude certain "
+ "elements from the snap procedure."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string Version = "Version 1.1"; // 2009-01-28 move step by step
+ // 1. Packages
+ // 2. Vias
+ // 3. Wires alf@cadsoft.de
+
+real GridDist = 25.0;
+enum { unitINCH, unitMIL, unitMM, unitMIC };
+string h, cmd = "";
+int unit = unitMIL; // predefined unit, can be changed to unitMM, unitINCH, unitMIC
+int Result;
+string Status = "";
+string script_name;
+
+int cntm = 0; // count unsnaped
+
+int n = 0, x[], y[], l[], UsedLayers[];
+
+
+real u2unit(int u) {
+ if (unit == unitMIL) return u2mil(u);
+ if (unit == unitMM) return u2mm(u);
+ if (unit == unitINCH) return u2inch(u);
+ if (unit == unitMIC) return u2mic(u);
+}
+
+
+real snap(int n) { // returns next grid point
+ return round(u2unit(n) / GridDist) * GridDist;
+}
+
+
+int isNew(int X, int Y, int L) {
+ for (int i = 0; i < n; i++) {
+ if (x[i] == X && y[i] == Y && (l[i] == L || l[i] == LAYER_VIAS )) return 0;
+ }
+ return 1;
+}
+
+
+void Move(int Layer) {
+ if (UsedLayers[Layer]) {
+ sprintf(h, "DISPLAY NONE %d;\n", Layer);
+ cmd += h;
+ // Snap the signal wires and vias:
+ for (int i = 0; i < n; i++) {
+ if (l[i] == Layer && (u2unit(x[i]) != snap(x[i]) || u2unit(y[i]) != snap(y[i]))) {
+ sprintf(h, "MOVE (%f %f) (%f %f);\n", u2unit(x[i]), u2unit(y[i]), snap(x[i]), snap(y[i]));
+ cmd += h;
+ cntm++;
+ }
+ }
+ }
+ return;
+}
+
+real check_coord(int x, int y) {
+ real v1, v2;
+ v1 = snap(x) - u2unit(x);
+ v2 = snap(y) - u2unit(y);
+ if (v1) return v1;
+ else if(v2) return v2;
+ else return 0;
+}
+
+
+void snap_to_grid(void) {
+ board(B) {
+ script_name = filesetext(B.name, "~snap.scr");
+ // Remember the active layers:
+ int ActiveLayers[];
+ B.layers(L) {
+ ActiveLayers[L.number] = L.visible;
+ }
+ if (unit == unitMIL) {
+ sprintf(h, "GRID MIL FINEST;\n");
+ cmd += h;
+ }
+ if (unit == unitMM) {
+ sprintf(h, "GRID MM FINEST;\n");
+ cmd += h;
+ }
+ if (unit == unitINCH) {
+ sprintf(h, "GRID INCH FINEST;\n");
+ cmd += h;
+ }
+ if (unit == unitMIC) {
+ sprintf(h, "GRID MIC FINEST;\n");
+ cmd += h;
+ }
+ sprintf(h, "SET OPTIMIZING OFF;\n"); // 2009-01-28
+ cmd += h;
+ if (!argv[1]) { // 1. snap elements
+ // Snap the elements:
+ B.elements(E) {
+ status("Element: "+E.name);
+ if (u2unit(E.x) != snap(E.x) || u2unit(E.y) != snap(E.y)) {
+ sprintf(h, "MOVE %s (%f %f);\n", E.name, snap(E.x), snap(E.y));
+ cmd += h;
+ cntm++;
+ }
+ }
+ }
+ // snap check vias
+ if (argv[1] == "V") { // 2. snap vias
+ // Collect all (unique!) signal via coordinates:
+ B.signals(S) {
+ status("Signal: "+S.name);
+ S.vias(V) {
+ UsedLayers[LAYER_VIAS] = 1;
+ x[n] = V.x;
+ y[n] = V.y;
+ l[n] = LAYER_VIAS;
+ if(check_coord(V.x, V.y)) n++;
+ }
+ }
+ }
+ if (argv[1] == "E" && n) {
+ cmd = "";
+ for (int vn = 0; vn < n; vn++) {
+ sprintf(h, "(%.4f %.4f);\n", u2unit(x[vn]), u2unit(y[vn]) );
+ }
+ cmd+=h;
+ sprintf(h, "Kann %d VIAs nicht snapen\n", n);
+ dlgMessageBox(h+cmd, "OK");
+ exit(-1);
+ }
+ // snap check wires
+ if (argv[1] == "W") { // 3. snap wires
+ // Collect all (unique!) signal wire coordinates:
+ B.signals(S) {
+ status("Signal: "+S.name);
+ S.wires(W) {
+ UsedLayers[W.layer] = 1;
+ if (isNew(W.x1, W.y1, W.layer)) {
+ x[n] = W.x1;
+ y[n] = W.y1;
+ l[n] = W.layer;
+ if (check_coord(W.x1, W.y1)) n++;
+ }
+ if (isNew(W.x2, W.y2, W.layer)) {
+ x[n] = W.x2;
+ y[n] = W.y2;
+ l[n] = W.layer;
+ if (check_coord(W.x2, W.y2)) n++;
+ }
+ }
+ }
+ }
+
+ // Go through the used layers (this avoids problems with wires on different
+ // layers that are selected at the same coordinates):
+ for (int u = LAYER_TOP; u <= LAYER_BOTTOM; u++) {
+ Move(u);
+ }
+ Move(LAYER_VIAS);
+
+ // Reactivate the active layers:
+ sprintf(h, "DISPLAY");
+ cmd += h;
+ for (int j = 1; j < 256; j++) {
+ if (ActiveLayers[j]) {
+ sprintf(h, " %d", j);
+ cmd += h;
+ }
+ }
+ sprintf(h, ";\n");
+ cmd += h;
+ if (!argv[1]) {
+ sprintf(h, "RUN '%s' 'V' %d %.4f;\n", argv[0], unit, GridDist);
+ }
+ else if (argv[1] == "V") {
+ sprintf(h, "RUN '%s' 'W' %d %.4f;\n", argv[0], unit, GridDist);
+ }
+ else if (argv[1] == "W") {
+ sprintf(h, "RUN '%s' 'E' %d %.4f;\n", argv[0], unit, GridDist);
+ }
+ else if (argv[1] == "E") {
+ exit(0);
+ }
+ }
+ return;
+}
+
+
+//---- main ----------------------------------------------------------------------
+
+if (!board) {
+ dlgMessageBox(usage + "
"
+ "consisting of several Symbols (Gates), "
+ "which have been extracted from one big Symbol by GROUP CUT and PASTE.
"
+ "Example: "
+ "It is possible to generate a Device with Symbol and Package from a BSDL or a text file (spreadsheet) with "
+ "the help of RUN make-symbol-device-package-bsdl. In case the Symbol becomes too big and does not "
+ "fit onto a single schematic sheet due to the number of pins, you can divide it into several smaller Symbols with "
+ "the commands GROUP, CUT, EDIT xx.sym, PASTE and so on. With the help of this ULP you can adopt the Connect "
+ "list from the 'original Device'.
"
+ "Please note: "
+ "There must not be pins with same names. So it is impossible to use this ULP for Devices that consist of "
+ "several identical Symbols (gates like NAND or OP-AMP..). "
+ "The chosen Package variant will be generated in the current Device. If this variant already exists, the "
+ "Connect list will be checked. If there are already connects between pins and pads, the ULP will exit with an error message. "
+ "
"
+ "librarian@cadsoft.de"
+ ,
+ "de: Dieses ULP erstellt die CONNECT-Liste für ein neues Device"
+ "aus mehreren Symbolen (Gates), "
+ "die mithilfe von GROUP CUT und PASTE aus einem großen Symbol entnommen wurden.
"
+ "Beispiel: "
+ "Mit RUN make-symbol-device-package-bsdl kann mit einer BSDL- oder Textdatei (Tabelle) ein Device mit Symbol "
+ "und Package generiert werden. Falls das Symbol durch die Anzahl der Pins zu groß wird, "
+ "um es im Schaltplan auf eine Seite zu platzieren, kann mit GROUP - CUT - EDIT xx.sym - PASTE .... das Symbol in "
+ "mehrere kleinere Symbole aufgeteilt und mithilfe dieses ULPs die Connect-Liste vom 'Original-Device' übernommen werden.
"
+ "ACHTUNG: "
+ "Es dürfen keine Pin-Namen doppelt vorkommen. So ist es z.B. nicht möglich dieses ULP für ein Device, das aus mehreren gleichen "
+ "Symbolen (Gates wie NAND oder OP-AMP) besteht, zu benutzen. "
+ "Die gewählte Package-Variante wird im aktuellen Device erzeugt. Sollte die Variante schon vorhanden sein "
+ "wird die Connect-Liste überprüft. Sind Connects zwischen Pins und Pads vorhanden, so wird das ULP mit einer Fehlernummer beendet."
+ "
"
+ "librarian@cadsoft.de
"
+
+
+
+string Version = "1.02"; // 1.00 - 2006.12.01 alf@cadsoft.de
+ // 1.01 - 2007.08.07 Abfrage der selektierten Variante darf nicht negativ sein.
+ // überprüft die Connectliste falls die Package-Variate schon angelegt ist
+ // 1.02 - 2008.04.24 Hinweis zum selektieren durch doppelklick
+
+string listv1 = "Select a &Device to get Connect list";
+string listv2 = "Select a Package &Variant";
+string listv3 = "double click in list";
+string listv4 = " ";
+
+if (language() == "de") {
+ listv1 = "Wählen Sie ein &Device für die Connectliste";
+ listv2 = "Wählen Sie eine Package &Variante";
+ listv3 = "doppelklick in Liste";
+ listv4 = " ";
+}
+
+string DeviceVariant, Pin_Name[], Pad_Name[];
+string DeviceSet;
+string Device_Sets[];
+string Variant[];
+string Package[];
+string Device_Variant[], Device_Package[];
+int cntD = 0;
+int cntConnect = 0;
+
+string actualpackage = " ";
+
+string cmd;
+string DeviceDescription;
+
+string replacenewline(string nl) {
+ string a[];
+ int n = strsplit(a, nl, '\n');
+ if (n > 0) {
+ nl = "";
+ for (int x = 0; x < n - 1; x++) {
+ nl += a[x] + "\\n";
+ }
+ nl += a[x];
+ }
+ return "'" + nl + "'";
+}
+
+
+string checkVariant(string s) {
+ if (s == "''") s = "''''";
+ return s;
+}
+
+
+void getPackage(int x) {
+ actualpackage = Device_Package[x]+".PAC";
+ return;
+}
+
+
+void getVariant(int x) {
+ string p[], v[];
+ int cnt;
+ cnt = strsplit(p, Package[x], ' ');
+ cnt = strsplit(v, Variant[x], ' ');
+ for (int n = 0; n < cnt; n++) {
+ Device_Variant[n] = v[n];
+ Device_Package[n] = p[n];
+ }
+ return;
+}
+
+
+string getPadName(string name) {
+ for (int n = 0; n < cntConnect; n++) {
+ if (name == Pin_Name[n]) return Pad_Name[n];
+ }
+ return "";
+}
+
+
+if (library) {
+ string file;
+ if (deviceset) {
+ deviceset(DEV) {
+ DeviceSet = DEV.name;
+ DEV.devices(D) {
+ cntConnect = 0;
+ D.gates(G) {
+ G.symbol.pins(P) {
+ cntConnect++; // count all pins
+ }
+ }
+ }
+ }
+ if (!cntConnect) {
+ if (language() == "de") {
+ dlgMessageBox("!Dieses Deviceset besitzt kein(e) Symbol(e)", "OK");
+ }
+ else {
+ dlgMessageBox("!This Device set has no Symbol(s)", "OK");
+ }
+ exit(0);
+ }
+
+ int selD = -1;
+ int selV = -1;
+ library(L) {
+ L.devicesets(DEV) { // collect only devicesets with the same counts of connects as the actual deviceset
+ int cntC;
+ if (DEV.name != DeviceSet) {
+ DEV.devices(D) {
+ cntC = 0;
+ D.gates(G) {
+ G.symbol.pins(P) cntC++;
+ }
+ if (cntC == cntConnect) {
+ Device_Sets[cntD] = DEV.name;
+ Variant[cntD] += D.name + " "; // Package Variant
+ Package[cntD] += D.package.name + " ";
+ }
+ else {
+// only for test / nur zum test
+// sprintf(cmd , "%d Connects in %s : %d connects in %s", cntC, DEV.name, cntConnect, DeviceSet);
+// if (dlgMessageBox(cmd, "OK", "esc") != 0) exit(-99);
+ }
+ }
+ if (cntC == cntConnect) cntD++;
+ }
+ }
+ string use_Device;
+ int listsel = 0;
+ string infodev;
+ sprintf(infodev, "%d Devivces found with %d connects", cntD, cntConnect);
+ do {
+ int RESULT = dlgDialog(filename(argv[0])) {
+ dlgHBoxLayout {
+ dlgLabel(DeviceSet+".DEV");
+ //dlgLabel(" Variant:"+DeviceVariant);
+ }
+ dlgSpacing(8);
+
+ dlgHBoxLayout {
+ dlgGridLayout {
+ dlgCell(0, 1) dlgLabel(listv1);
+ dlgCell(1, 1) dlgListView("Device", Device_Sets, selD, listsel) {
+ getVariant(selD); actualpackage = " ";
+ if (language() == "de") actualpackage = "doppelklick in Liste";
+ else actualpackage = "double click in list";
+ listv3 = " ";
+ }
+ dlgCell(0, 2) dlgSpacing(12);
+ dlgCell(0, 3) dlgLabel("Select a Package &Variant") ;
+ dlgCell(1, 3) dlgListView("Variant", Device_Variant, selV) getPackage(selV);
+ dlgCell(2, 1) dlgLabel(listv3, 1);
+ dlgCell(2, 3) dlgLabel(actualpackage, 1);
+ }
+ dlgStretch(1);
+ }
+ dlgLabel(infodev);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ dlgPushButton("&Help") dlgMessageBox(usage);
+ }
+ };
+ if (!RESULT) exit(0);
+
+ if (selD < 0) {
+ if (language() == "de") {
+ dlgMessageBox("Kein DEVICE gewählt!", "OK");
+ }
+ else {
+ dlgMessageBox("No DEVICE selected!", "OK");
+ }
+ }
+ else {
+ // 2007.08.03
+ if (selV < 0) {
+ if (language() == "de") {
+ dlgMessageBox("!Keine Variante gewählt.\nWählen Sie eine Variante.\nDurch doppelklick auf das Device wird die Spalte Variant angezeigt.", "OK");
+ }
+ else {
+ dlgMessageBox("No package variant selected!\nTo display the variant colomn, select a Device with a double mouse click first.", "OK");
+ }
+ }
+ }
+ } while (selD < 0 || selV < 0);
+ }
+ library(L) {
+ file = filesetext(L.name, "~connect.scr");
+ L.devicesets(DEV) {
+ if (DEV.name == Device_Sets[selD]) {
+ DEV.devices(D) {
+ if (D.name == Device_Variant[selV]) {
+ int n = 0;
+ D.gates(G) {
+ G.symbol.pins(P) {
+ Pin_Name[n] = P.name;
+ Pad_Name[n] = P.contact.name;
+ n++;
+ }
+ }
+ }
+ }
+ DeviceDescription = DEV.description;
+ }
+ }
+ }
+ deviceset(DEV) {
+ int variant_not_used = 1;
+ int variant_exist = 0;
+ DEV.devices(D) {
+ if (D.name == Device_Variant[selV]) {
+ if (D.package) { // 2007.08.06
+ variant_exist = 1;
+ D.gates(G) {
+ G.symbol.pins(P) {
+ if (P.contact) {
+ variant_not_used = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (variant_not_used == 0) {
+ string h;
+ if (language() == "de") {
+ sprintf(h, "Package-Variante %s schon vorhanden und connected. Benutzen Sie eine noch nicht vorhandene Variante in der Quelle, oder löschen Sie die Variante im aktuellen Device!", D.name);
+ }
+ else {
+ sprintf(h, "Package-Variant %s is already defined and connected. Choose a a new variant in the source or delete this variant in the current Device.", D.name);
+ }
+ dlgMessageBox(h, "OK");
+ exit(-1);
+ }
+ }
+ }
+ if (variant_not_used) {
+ output(file, "wtD") {
+ DEV.devices(D) {
+ if (!variant_exist) printf("PACKAGE %s %s;\n", Device_Package[selV], Device_Variant[selV]);
+ D.gates(G) {
+ G.symbol.pins(P) {
+ string pad = getPadName(P.name);
+ if (language() == "de") {
+ if (!pad) dlgMessageBox("Kein PAD gefunden für "+ P.name +"\nÜberprüfen Sie die Pinnamen der Symbole", "OK");
+ }
+ else {
+ if (!pad) dlgMessageBox("No PAD found for "+ P.name +"\nCheck the Pin names of the Symbols", "OK");
+ }
+ printf("CONNECT '%s.%s' '%s';\n", G.name, P.name, pad); // 2007.08.6 *** Namen in ' ' wegen Kommentarzeichen in Scripten "#"
+ }
+ }
+ string t[];
+ printf("DESCRIPTION %s;\n", replacenewline(DeviceDescription+" Connect-List generated from "+ Device_Sets[selD] +".DEV Variant "+ checkVariant(Device_Variant[selV]) +" with "+ filename(argv[0])+""));
+ }
+ printf("WIN FIT;\n");
+ }
+ exit("SCRIPT '"+ file + "';\n");
+ }
+ }
+ }
+ else {
+ if (language() == "de") {
+ dlgMessageBox("Öffnen Sie ein Device.", "OK");
+ }
+ else {
+ dlgMessageBox("Edit a Device.", "OK");
+ }
+ }
+}
+
+else dlgMessageBox("Start this ULP in a LBR (Device)", "OK");
diff --git a/trunk/ulp/copy-attribute-at-deviceset.ulp b/trunk/ulp/copy-attribute-at-deviceset.ulp
new file mode 100644
index 00000000..09a1e742
--- /dev/null
+++ b/trunk/ulp/copy-attribute-at-deviceset.ulp
@@ -0,0 +1,87 @@
+#usage "Kopiere die Attribute der Devices in alle Package-Varianten, und benenne die 1. Variante um zu ''
"
+ "In den (Connect) Scripten von LT werden Package-Varianten angelegt, aber nur die erste "
+ "erhält die Attribute aus der importierten *.asy. "
+ "In den Beispielschaltplänen, wird keine Package-Variante angegeben, deshalb muß ein Device im Deviceset "
+ "ein neutrales sein! "
+ "Package-Variante == '' "
+ "Author alf@cadsoft.de"
+
+
+string Version = "1.0.0"; // 2012-10-05 alf@cadsoft.de
+string Dev_AttributtesName[];
+string Dev_AttributtesValue[];
+int cntAttr = 0;
+
+string Cmd = "";
+string s;
+
+string checkname(string s) {
+ if (s == "''") return "";
+ return s;
+}
+
+void loopdeviceset(UL_DEVICESET DEV) {
+ int n;
+ DEV.devices(D) {
+ int numofattr = 0;
+ string t[];
+ n = strsplit(t, D.technologies, ' ');
+ for (int i = 0; i < n; i++) {
+ D.attributes(A, t[i]) {
+ numofattr++;
+ }
+ }
+ if (numofattr > cntAttr) {
+ cntAttr = 0;
+ n = strsplit(t, D.technologies, ' ');
+ for (int i = 0; i < n; i++) {
+ D.attributes(A, t[i]) {
+ Dev_AttributtesName[cntAttr] = A.name;
+ Dev_AttributtesValue[cntAttr] = A.value;
+ cntAttr++;
+ }
+ }
+ }
+ }
+ int dcnt = 0;
+ DEV.devices(D) {
+ sprintf(s, "PACKAGE '%s';\n", checkname(D.name));
+ Cmd += s;
+ sprintf(s, "TECHNOLOGY '';\n");
+ Cmd += s;
+ for (n = 0; n < cntAttr; n++) {
+ sprintf(s, "ATTRIBUTE %s '%s';\n", Dev_AttributtesName[n], Dev_AttributtesValue[n]);
+ Cmd+= s;
+ }
+ if (!dcnt) {
+ string pacnam = checkname(D.name);
+ if (pacnam) {
+ sprintf(s, "PACKAGE -%s '''''';\n", pacnam);
+ Cmd+=s;
+ }
+ dcnt++;
+ }
+ }
+ return;
+}
+
+
+if (deviceset && !argv[1]) {
+ Cmd = "";
+ deviceset(DEV) {
+ loopdeviceset(DEV);
+ }
+ //dlgMessageBox(Cmd, "ok");
+ exit(Cmd);
+}
+
+else if (library || deviceset && argv[1] == "/ALL") {
+ Cmd = "";
+ library(L) L.devicesets(DEV) {
+ sprintf(s, "EDIT %s.DEV;\n", DEV.name);
+ Cmd+=s;
+ loopdeviceset(DEV);
+ //if (dlgMessageBox(Cmd, "ok", "esc") != 0) exit(Cmd);
+ }
+ exit(Cmd);
+}
\ No newline at end of file
diff --git a/trunk/ulp/copy-layer-to-any-layer.ulp b/trunk/ulp/copy-layer-to-any-layer.ulp
new file mode 100644
index 00000000..b8e722f6
--- /dev/null
+++ b/trunk/ulp/copy-layer-to-any-layer.ulp
@@ -0,0 +1,509 @@
+#usage "Copy Wire (Polygon Wire) to any layer
"
+ "This ULP copies copper wire and/or polygon from layer (1 or 16) of selected signals into "
+ "any layer in order.
"
+ "If the selected layer is not a copper layer, also RECT, CIRCLE and TEXT will be copied. "
+ "Use: "
+ "run copy-wire-to-any-layer.ulp [signalname] [signalname] "
+ "run copy-wire-to-any-layer.ulp $nameoff$ "
+ "run copy-wire-to-any-layer.ulp -p [signalname] [signalname] "
+ "run copy-wire-to-any-layer.ulp +p [signalname] [signalname] "
+ "run copy-wire-to-any-layer.ulp -p -f [signalname] [signalname] "
+ "run copy-wire-to-any-layer.ulp +p +f [signalname] [signalname] "
+ "$nameoff$ switches off the checking of net names
"
+ "Options are case sensitive. "
+ "$nameoff$ copy all signals. "
+ "-p copies also polygons. "
+ "+p copies only polygons. "
+ "-f copies only polygon contour as polygon. "
+ "-f copies polygon contour and filling as wire. "
+ "
"
+ "Author: support@cadsoft.de
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED.
+
+string Version = "Version 1.5"; // 2008-04-23 check is a polygon placed
+ // changed menu to copy to any layer
+ // 2008-05-05 renamed from "copy-wire-to-solder-mask.ulp" to
+ // "copy-wire-to-any-layer.ulp"
+ // 2008-10-24 renamed to copy-layer-to-any-layer.ulp
+ // copy also rect, circle, text and non copper layer
+ // 2009-01-28 check polygon filling on orphan
+ // 2009-04-28 copy also not copper layer with RECT, CIRCLE, TEXT
+
+
+int NameOff = 0; // 0 = copy by signal name
+ // 1 = copy without signal name (all)
+int PolygonOn = 1; // copy also polygon
+int onlyPolygon = 0;
+int fillPolygon = 0; // copy only polygon contour or copy polygon filling as wire 2006.01.20 alf
+int PolygonAsPolygon = 1; // 2009.-04-28 alf
+int PolygonContours = 0;
+int ploycontourleft = 0;
+int cntp = 0;
+string isRatsnest;
+string isLayer = "";
+int isLayerNb = 0;
+string toLayer = "";
+
+string fromName[], toName[];
+ fromName[0] = "";
+ toName[0] = "";
+int fromNumber;
+int toNumber;
+int fcntLay = 0;
+int fromlNumber[];
+
+int lNumber[];
+int cntLay = 0;
+int selisLayer = 0, seltoLayer = 0;
+
+string signals[] = { "" };
+string chsignals[] = { "" };
+int chngsig = 0;
+int lastSigCh = -1;
+int decs;
+
+int n = 1;
+
+string cmd;
+string c;
+
+string Tfont[] = { "VECTOR", "PROPORTIONAL", "FIXED" };
+
+
+// *************************************
+int found(string fnam) {
+ int fnd = 0;
+ do {
+ if (chsignals[fnd] == fnam) {
+ return 1;
+ break;
+ }
+ ++fnd;
+ } while (chsignals[fnd]);
+ return 0;
+}
+
+
+int getlayernumber(string isL) {
+ board(B) B.layers(L) if (L.name == isL) return (L.number);
+ return 0;
+}
+
+
+void changeLayer(void) {
+ sprintf(c, "CHANGE LAYER %d;\n", toNumber);
+ cmd+= c;
+ return;
+}
+
+
+int delfromList(int selct) {
+ if (lastSigCh >= 0) {
+ lastSigCh--;
+ for (int r = selct; r <= lastSigCh; r++) {
+ chsignals[r] = chsignals[r + 1];
+ }
+ chsignals[lastSigCh + 1] = "";
+ }
+ return selct;
+}
+
+void AddList (string SigName) {
+ int nofound = 1;
+ for (int r = 0; r <= lastSigCh; r++) {
+ if (chsignals[r] == SigName) {
+ nofound = 0;
+ break;
+ }
+ }
+ if (nofound) {
+ lastSigCh++;
+ if (lastSigCh > 0) {
+ for (int x = lastSigCh; x > 0; x--) {
+ chsignals[x] = chsignals[x - 1];
+ }
+ }
+ chsignals[0] = SigName;
+ }
+ return;
+}
+
+
+void AddArgument(int n) {
+ do {
+ AddList(strupr(argv[n]));
+ n++;
+ } while(argv[n]);
+ return;
+}
+
+
+// 2009-04-28 die print funktionen
+void printW(UL_WIRE W) {
+ if (W.layer == fromNumber) {
+ sprintf(c, "WIRE %.4f (%.4f %.4f) %+.1f (%.4f %.4f);\n",
+ u2mm(W.width),
+ u2mm(W.x1), u2mm(W.y1), W.curve, u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd+= c;
+ }
+ return;
+}
+
+
+void printC(UL_CIRCLE C) {
+ if (C.layer == fromNumber) {
+ sprintf(c, "CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n",
+ u2mm(C.width),
+ u2mm(C.x), u2mm(C.y), u2mm(C.x + C.radius), u2mm(C.y)
+ );
+ cmd+= c;
+ }
+ return;
+}
+
+
+void printR(UL_RECTANGLE R) {
+ if (R.layer == fromNumber) {
+ sprintf(c, "RECT R%.1f (%.4f %.4f) (%.4f %.4f);\n",
+ R.angle,
+ u2mm(R.x1), u2mm(R.y1), u2mm(R.x2), u2mm(R.y2)
+ );
+ cmd+= c;
+ }
+ return;
+}
+
+
+void printT(UL_TEXT T) {
+ if (T.layer == fromNumber) {
+ string Spin = "";
+ if (T.spin) Spin = "S";
+ sprintf(c, "CHANGE SIZE %.4f;\n", u2mm(T.size) );
+ cmd+= c;
+ sprintf(c, "CHANGE FONT %s;\n", Tfont[T.font] );
+ cmd+= c;
+ sprintf(c, "TEXT %sR%.1f '%s' (%.4f %.4f);\n",
+ Spin,
+ T.angle,
+ T.value, u2mm(T.x), u2mm(T.y)
+ );
+ cmd+= c;
+ }
+ return;
+}
+
+
+void printP(UL_POLYGON P) {
+ if (PolygonAsPolygon) {
+ if (PolygonContours) {
+ int i = -1;
+ int active;
+ int first = 0;
+ if (ploycontourleft) i = -1;
+ else i = 1;
+ do {
+ active = 0;
+ P.contours(W, i) {
+ active = i;
+ if (first != i) {
+ sprintf(c, "POLYGON %.4f (%.4f %.4f) %+.1f (%.4f %.4f) \n",
+ u2mm(W.width),
+ u2mm(W.x1), u2mm(W.y1),
+ W.curve,
+ u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd+=c;
+ first = i;
+ }
+ else {
+ sprintf(c, " %+.1f (%.4f %.4f) \n",
+ W.curve,
+ u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd+=c;
+ }
+ }
+ if (ploycontourleft) i--;
+ else i++;
+ cmd += ";\n"; // close the polygon command
+
+ } while (active);
+ }
+ else {
+ int first = 1;
+ P.wires(W) {
+ if (first) {
+ sprintf(c, "POLYGON %.4f (%.4f %.4f) %+.1f (%.4f %.4f) \n",
+ u2mm(W.width),
+ u2mm(W.x1), u2mm(W.y1),
+ W.curve,
+ u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd+=c;
+ first = 0;
+ }
+ else {
+ sprintf(c, " %+.1f (%.4f %.4f) \n",
+ W.curve,
+ u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd+=c;
+ }
+ }
+ cmd += ";\n"; // close the polygon command
+ }
+ }
+ else {
+ P.contours(W) printW(W);
+ if (fillPolygon) P.fillings(W) printW(W);
+ }
+ return;
+}
+
+
+// die Contacts werden noch nicht ausgegeben 2009-04-28 alf
+void printCon(UL_CONTACT C) {
+ if (C.smd) {
+ if (C.smd.layer == fromNumber) {
+// angle
+ }
+ }
+ else { // Pad
+ if (fromNumber >= 1 && fromNumber <= 16) {
+// diameter[fromNumber]
+// shape[fromNumber]
+// angle
+ }
+ }
+ return;
+}
+
+
+
+// alle nicht Kupferlayer ausgeben
+void copy_any_layer(void) {
+ board(B) {
+ B.wires(W) printW(W);
+ B.circles(C) printC(C);
+ B.rectangles(R) printR(R);
+ B.texts(T) printT(T);
+ B.polygons(P) printP(P);
+
+ B.elements(E) {
+ E.package.wires(W) printW(W);
+ E.package.circles(C) printC(C);
+ E.package.rectangles(R) printR(R);
+ E.package.texts(T) printT(T);
+ E.package.polygons(P) printP(P);
+ E.package.contacts(C) printCon(C);
+ }
+ }
+ return;
+}
+
+
+void collectlayer(void) {
+ board(B) B.layers(L) {
+ if (L.used) {
+ fromName[fcntLay] = L.name;
+ fromlNumber[fcntLay] = L.number;
+ fcntLay++;
+ fromName[fcntLay] = "";
+ fromlNumber[fcntLay] = 0;
+ }
+ toName[cntLay] = L.name;
+ lNumber[cntLay] = L.number;
+ cntLay++;
+ toName[cntLay] = "";
+ lNumber[cntLay] = 0;
+ }
+ return;
+}
+
+void menue() {
+ string tempSignal0 = signals[0];
+ string tempSignal1 = signals[1];
+ int srt = 0;
+ int tempNameOff = NameOff;
+ string CopyAllInfo = "also without signal name";
+ if (argc > 1) {
+ if (argv[1] == "-p" || argv[1] == "+p" || argv[1] == "$nameoff$") {
+ if (argv[1] == "-p") PolygonOn = 1;
+ if (argv[1] == "+p") onlyPolygon = 1;
+ if (argv[2] == "-f") fillPolygon = 0; // 2006.01.20 alf
+ if (argv[2] == "+f") fillPolygon = 1;
+ if (argv[1] == "$nameoff$") { NameOff = 1; AddArgument(2); }
+ else if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); }
+ else AddArgument(2);
+ if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); }
+ else if (argv[3] == "$nameoff$") { NameOff = 1; AddArgument(4); }
+ else AddArgument(3);
+ }
+ else AddArgument(1);
+ }
+ else {
+ string slist[];
+ int Result = dlgDialog(filename(argv[0])) {
+ dlgHBoxLayout dlgSpacing(250);
+ dlgHBoxLayout {
+ dlgCheckBox("&Copy all ", NameOff);
+ dlgLabel(CopyAllInfo, 1);
+ dlgStretch(1);
+ }
+ dlgSpacing(10);
+ dlgStretch(0);
+ dlgLabel("&Add signal to list");
+ dlgComboBox(signals, chngsig) { AddList(signals[chngsig]); dlgRedisplay();}
+ dlgSpacing(12);
+ dlgLabel("&Delete signal from list");
+ dlgComboBox(chsignals, decs) decs = delfromList(decs);
+ dlgGroup("Polygon") {
+ dlgCheckBox("Copy &polygon with signal name", PolygonOn);
+ dlgCheckBox("Copy &only polygons", onlyPolygon);
+ dlgGroup("wire/poly") {
+ dlgHBoxLayout {
+ dlgRadioButton("Copy polygon as &wire",PolygonAsPolygon);
+ dlgRadioButton("Copy polygon &as polygon",PolygonAsPolygon);
+ }
+ }
+ dlgGroup("outline/inner") {
+ dlgHBoxLayout {
+ dlgRadioButton("Copy polygon defintition",PolygonContours);
+ dlgRadioButton("Copy polygon contours",PolygonContours);
+ }
+ }
+ dlgGroup("outer/inner rotation") {
+ dlgHBoxLayout {
+ dlgRadioButton("left rotation (outer) contour", ploycontourleft);
+ dlgRadioButton("right rotation (inner) contour", ploycontourleft);
+ }
+ }
+ dlgHBoxLayout {
+ dlgRadioButton("Copy conto&ur", fillPolygon);
+ dlgRadioButton("Copy &filling", fillPolygon);
+ }
+ }
+ dlgHBoxLayout {
+ dlgListView("from Layer", fromName, selisLayer, srt) {
+ fromNumber = getlayernumber(fromName[selisLayer]);
+ if (fromNumber > 16) {
+ tempSignal0 = signals[0];
+ tempSignal1 = signals[1];
+ signals[0] = "Kein Kupferlayer";
+ signals[1] = "";
+ tempNameOff = NameOff;
+ NameOff = 1;
+ }
+ else if (signals[0] = "Kein Kupferlayer") {
+ signals[0] = tempSignal0;
+ signals[1] = tempSignal1;
+ NameOff = tempNameOff;
+ }
+ }
+ dlgListView("to Layer", toName, seltoLayer, srt) toNumber = getlayernumber(toName[seltoLayer]);
+ dlgStretch(1);
+ }
+ dlgLabel("If you want to change the default setting, type in the appropriate layer numbers here.");
+ dlgHBoxLayout {
+ dlgIntEdit(fromNumber);
+ dlgIntEdit(toNumber);
+ dlgStretch(1);
+ }
+ dlgSpacing(10);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") {
+ if (!fromNumber || !toNumber) dlgMessageBox("!Select a valid layer", "OK");
+ else if(fromNumber == toNumber) dlgMessageBox("!Select a differnt layer from <-> to", "OK");
+ else if(fromNumber <= 16 && lastSigCh < 0 && !NameOff) dlgMessageBox("!Select one or more signal(s)", "OK");
+ else dlgAccept();
+ }
+ dlgPushButton("-Cancel") dlgReject();
+ dlgStretch(1);
+ dlgLabel(Version);
+ dlgStretch(1);
+ dlgPushButton("&Help") dlgMessageBox(usage, "OK");
+ }
+ dlgStretch(0);
+ };
+ if (Result == 0) exit (0);
+ }
+ isLayerNb = fromNumber; // 2009-04-24
+ return;
+}
+
+
+// main
+if (board) board(B) {
+ isRatsnest = "! Start RATSNEST first!";
+ int cntPoly = 0;
+ B.signals(S) {
+ S.polygons(P) {
+ cntPoly++;
+ P.fillings(F) {
+ isRatsnest = "";
+ break;
+ }
+ if (isRatsnest) { // check a orphan 2009-01-28 alf@cadsoft.de
+ P.wires(W) {
+ sprintf(isRatsnest, "Start RATSNEST and check polygon on (%.4f %.4f) mm!", u2mm(W.x1), u2mm(W.y1) );
+ dlgMessageBox(isRatsnest, "OK");
+ sprintf(isRatsnest, "GRID MM;\nWIN (%.4f %.4f);\nGRID LAST;\n", u2mm(W.x1), u2mm(W.y1) );
+ exit(isRatsnest);
+ }
+ }
+ }
+ }
+ if (cntPoly) {
+ if (isRatsnest) {
+ dlgMessageBox(isRatsnest, "OK");
+ exit(0);
+ }
+ }
+ int s = 0;
+ B.signals(S) {
+ signals[s] = S.name;
+ s++;
+ }
+ collectlayer();
+ menue();
+ sprintf(c, "GRID MM;\nSET WIRE_BEND 2;\nSET UNDO OFF;\n");
+ cmd+= c;
+ changeLayer();
+ if (isLayerNb > 16) copy_any_layer();
+ else {
+ B.signals(S) {
+ if (found(S.name) || NameOff || onlyPolygon) {
+ if (!onlyPolygon) {
+ S.wires(W) {
+ if (fromNumber == W.layer) printW(W);
+ }
+ }
+ // ##### ACHTUNG #####
+ // POLYGONE die kein *echtes* SIGNAL sind, also nicht an einen PAD oder SMD angebunden sind,
+ // werden nicht ausgegeben, weil signals(S) nur durch echte Signale läuft.
+ /**************************************************************************/
+ if (PolygonOn) {
+ S.polygons(POL) {
+ if (fromNumber == POL.layer) {
+ printP(POL);
+ }
+ }
+ }
+ }
+ }
+ }
+ sprintf(c, "SET UNDO ON;\nGRID LAST;\n");
+ cmd+= c;
+dlgDialog("test") {
+ dlgTextEdit(cmd);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") { dlgReject(); exit(-1); }
+ dlgStretch(1);
+ }
+};
+ exit (cmd);
+}
+else dlgMessageBox("! Start this ULP in a Board", "OK");
diff --git a/trunk/ulp/copy-silk-screen.ulp b/trunk/ulp/copy-silk-screen.ulp
new file mode 100644
index 00000000..4220cca7
--- /dev/null
+++ b/trunk/ulp/copy-silk-screen.ulp
@@ -0,0 +1,264 @@
+#usage "Generate a copy of Name; Value; Place and Docu layers to user defined layer.\n"
+ "
"
+ "Generates a command sequence which copies the silk placement "
+ "of all elements of your layout into newly generated layers (+100). "
+ "After running the ULP you can GROUP, CUT and PASTE your layout "
+ "to get an array of several boards."
+ "
"
+ "The duplicated name texts in the new layers will not be changed. "
+ "Please notice that you have to deactivate layers 21 - 28 and 51 - 52, if you use "
+ "the CAM processor for example to generate gerber data. Instead, you have to activate "
+ "the new layers 121 - 152. Thus you get an identical silk screen for all "
+ "your layouts in this array."
+ "
"
+ "This ULP copies copper wire and/or polygon from layer (1 or 16) of selected signals into "
+ "the solder stop layers or any layer in order to keep it free from solder stop layer.
\n";
+ }
+}
+
+// Only search by keyword
+void DoSearch(string keyword)
+{
+ if (FilteredSearch(keyword, DISearchByKeyword)) {
+ Result2List();
+ ShowSelection();
+ }
+ // Remember settings
+ DIInStockBef = DIInStock;
+ DIRoHSBef = DIRoHS;
+ DISearchKeyBef = keyword;
+}
+
+string SingleSearch(int dlg_mode, string dlg_head, string description, string image,
+ int start_search_mode, string singlekey, string displaykey) {
+ // Without treating the help text here local maintenance of it is a nightmare !
+ string help[] = {
+ "Bauteilsuche "
+ "Gehen Sie schrittweise durch die Bauteiltypen Ihres Schaltplans und suchen "
+ "nach passenden Artikeln in Farnell's Produktkatalog. "
+ "Pro Bauteiltyp werden zunächst Suchergebnisse anhand des Bauteil-Value angezeigt. "
+ "Befindet sich ein geeigneter Farnell-Artikel darunter, können Sie diesen "
+ "per Button oder Doppelklick auswählen. "
+ "Wenn nicht, können Sie eine beliebige manuelle Suche starten und dann auswählen. "
+ "Nach der Auswahl gelangen Sie zum nächsten Bauteiltyp. "
+ "Mit Überspringen kommen Sie ohne Auswahl weiter. "
+ "Bauteiltypen, die anhand des Value kein Suchergebnis liefern, werden automatisch übersprungen. "
+ "Wenn Sie alle Bauteiltypen durchgegangen sind oder auch mit dem Button Direkt zur Bestelliste "
+ "gelangen Sie zur Bestellliste, von der aus Sie direkt bei Farnell ordern können. "
+ "Sie können Ihre Auswahl vorher noch beliebig ändern. "
+ "
Hersteller-Bibliotheken mit Ordercodes "
+ "Für Bauteile aus Hersteller-Bibliotheken, die bereits mit Farnell-Ordercodes versehen sind, "
+ "erübrigt sich diese Suche und der entsprechende Farnell-Artikel wird automatisch in die "
+ "Bestellliste übernommen. "
+ "
Alternative Suche mit Value und Package "
+ "Anstatt nur mit dem Bauteil-Value können Sie die automatische Suche auch mit Value und Package "
+ "durchführen. Sie erreichen dies, in dem Sie " + filename(argv[0]) + " mit der Option "
+ "-sop (search option package) aufrufen."
+ "
Hinweis zu Internet-Verbindungseinstellungen "
+ "Falls Sie über einen Proxy auf das Internet zugreifen, passen Sie bitte die Einstellungen "
+ "im Control Panel unter Hilfe / Auf Update prüfen / Konfigurieren entsprechend an."
+ ,
+ "Part search " +
+ "Step through the part types of your schematic and search for according articles in " +
+ DICompany + "'s product catalog. " +
+ "For each part type, search results fitting to the part value are displayed at first. " +
+ "If there's an appropriate article from " + DICompany + " among them you can choose it by button or mouse click. "+
+ "If not, you can start an arbitrary manual search and select then. " +
+ "After selection you get to the next part type. " +
+ "With Skip this you proceed without a choice. " +
+ "Part types with no search results based on the part value are skipped automatically. " +
+ "After going through all part types or by pressing Directly to order list " +
+ "you get to the order list where you can load it to a " + DICompany + " shopping cart. " +
+ "You can still change your selection before." +
+ "
Manufacturer libraries with order codes " +
+ "This search is not necessary for parts from manufacturer libraries with " + DICompany + " order codes. " +
+ "The corresponding " + DICompany + " article is taken automatically to the order list." +
+ "
Alternative search by value and package " +
+ "Instead of search by part value you can do the automatic search by value and package. " +
+ "You achieve this by starting " + filename(argv[0]) + " with option -sop (search option package)."
+ "
Hint on internet settings "
+ "If you access the internet by a proxy, please adjust the settings in the Control Panel under "
+ "Help / Check for Update / Configure accordingly."
+ };
+ DIProductSel = -1;
+ string key = displaykey;
+ int ok = 1; // Wether search worked or not
+
+ if (!((start_search_mode == DISearchByOC) && (singlekey == DIUnknown))) { // Avoid search with an unknown OC !
+ ok = FilteredSearch(singlekey, start_search_mode);
+ Result2List();
+ }
+
+ if (DINrProducts > 0)
+ DIProductSel = 0;
+ // If it's the initial search and no products have been found don't display the dialog (and go to next item)
+ // The same for initial search by OC: If OC is there, everything is clear.
+ // Search must have worked (ok=1). Otherwise user needs to be informed !
+ if (ok && (dlg_mode == DIModeInitSearch) && ((DINrProducts == 0) || (start_search_mode == DISearchByOC)) )
+ return (DINrProducts == 0) ? "" : DIProductList[0];
+ else {
+ DIMode = 0; // For displaying search message
+ if (ok) ShowSelection(); // Prepares Html string for display
+ int dlg_ret = dlgDialog(dlg_head) {
+ dlgVBoxLayout {
+ if (dlg_mode == DIModeLbrSearch) {
+ dlgLabel("" + tr("Suche nach ") + (DICountry == "US" ? "NEWARK" : "FARNELL") +
+ " Code (" + GetDesignLinkURL() + ")");
+ }
+ dlgHBoxLayout dlgSpacing(800);
+ dlgHBoxLayout {
+ dlgTextView(DIHtml); // Gleich anzeigen...
+ dlgVBoxLayout dlgSpacing(400); // flines
+ }
+ dlgListView(DIProductListHead ,DIProductList, DIProductSel)
+ if (dlgSelectionChanged()) ShowSelection();
+ else dlgAccept();
+ dlgGroup(tr("Beschreibung") + " EAGLE Part/Device:") {
+ dlgHBoxLayout {
+ dlgLabel(description);
+ if (image) dlgLabel(image);
+ }
+ }
+ dlgHBoxLayout {
+ dlgStringEdit(key, DISearchHist, 9);
+ dlgPushButton(tr("+Manuelle Suche")) {
+ Clear();
+ DoSearch(key);
+ }
+ }
+ dlgHBoxLayout {
+ dlgPushButton(tr("Auswählen")) {
+ if (DIProductSel < 0) dlgMessageBox(
+ tr("Bitte wählen Sie einen Listeneintrag oder überspringen Sie dieses Bauteil !"), "OK");
+ else dlgAccept();
+ }
+
+ dlgPushButton(tr("Überspringen")) {
+ DIProductSel = -1;
+ dlgAccept();
+ }
+ dlgStretch(1);
+ if (dlg_mode == DIModeLbrSearch) {
+ dlgPushButton(tr("Vorige"))
+ if (DIProductOffset > 0) {
+ DIProductOffset -= DINrProductsPerPage;
+ DoSearch(key);
+ }
+ dlgLabel(DIResInfo, 1);
+ dlgPushButton(tr("Nächste")) //tr !
+ if (DIProductOffset + DINrProductsPerPage < DINrAccessibleProducts) {
+ DIProductOffset += DINrProductsPerPage;
+ DoSearch(key);
+ }
+ else
+ dlgMessageBox(tr("Keine weiteren Produkte verfügbar!"));
+ dlgStretch(1);
+ }
+ if (dlg_mode == DIModeInitSearch) // In case of initial search offer help
+ dlgPushButton(tr("Hilfe") + "...")
+ dlgMessageBox(help[DILangIdx]);
+ string button_text;
+ if (dlg_mode == DIModeInitSearch) button_text = tr("Direkt zur Bestelliste");
+ else button_text = tr("Zurück");
+ dlgPushButton(button_text) {
+ dlgAccept();
+ if (dlg_mode == DIModeInitSearch) DISkipRem = 1;
+ else DICancelSearch = 1;
+ }
+ }
+ }
+ };
+ DIMode = 1; // Reset
+ // User pressed the "x" close button:
+ // This means: No selection, no change of data in case of search from order list
+ // In case of the initial search, assume/respect that the user wants to leave DL
+ // Pro: He should have a possibility to leave. Otherwise he'd have to go directly to orderlist
+ // first (involving unintended searches) before he can close.
+ // Con: He may click without being aware that all his previous decisions are lost.
+ // This is less likely as we are not providing a close button here.
+ if (dlg_ret == -1) {
+ if (dlg_mode == DIModeInitSearch)
+ exit(EXIT_SUCCESS);
+ DIProductSel = -1;
+ DICancelSearch = 1;
+ }
+ return (DIProductSel < 0 ? "" : DIProductList[DIProductSel]);
+ }
+}
+
+// --- replace package and technology text holder ----
+string techpacvar(string devsetname, string devname, string tech, string pacname) {
+ if (tech == "''") tech = "";
+ if (pacname == "''") pacname = "";
+ if (devname == "''") devname = "";
+ string s[];
+ int cnt;
+ cnt = strsplit(s, devsetname, '*');
+ if (cnt > 1) {
+ if (cnt == 2) {
+ if (!s[0]) {
+ devsetname = tech + s[1];
+ }
+ else if (!s[1]) {
+ devsetname = s[0] + tech;
+ }
+ else devsetname = s[0] + tech + s[1];
+ }
+ }
+ else devsetname += tech;
+
+ cnt = strsplit(s, devsetname, '?');
+ if (cnt > 1) {
+ if (cnt == 2) {
+ if (!s[0]) {
+ devsetname = devname + s[1];
+ }
+ else if (!s[1]) {
+ devsetname = s[0] + devname;
+ }
+ else devsetname = s[0] + devname + s[1];
+ }
+ }
+ else devsetname += devname;
+ return devsetname;
+}
diff --git a/trunk/ulp/designlink-lbr.ulp b/trunk/ulp/designlink-lbr.ulp
new file mode 100644
index 00000000..9183030a
--- /dev/null
+++ b/trunk/ulp/designlink-lbr.ulp
@@ -0,0 +1,394 @@
+#usage "en: DesignLink Library Tool\n"
+ "
"
+ "ULP for embedding Farnell and/or Newark order codes and related data to EAGLE library devices."
+ "
"
+ "Usage: run designlink-lbr [-both_oc]|[-sop]\n"
+ "
"
+ "Options:"
+ "
"
+ "-both_oc: This lets you search both in Farnell and Newark databases and embed both order codes. \n"
+ "-sop : Search option package. By default searching for Farnell parts "
+ "is done with device name and technology. With this option the "
+ "package name is taken additionally for getting more accurate results.\n"
+ "
"
+ "ULP für die Zuweisung von Farnell- und/oder Newark-Ordercodes und verwandte Daten zu EAGLE-Devices."
+ "
"
+ "Usage: run designlink-lbr [-both_oc]|[-sop]\n"
+ "
"
+ "Optionen:"
+ "
"
+ "-both_oc: Damit können Sie sowohl in der Farnell- als auch in der Newark-Datenbank suchen"
+ " und Ordercodes zuweisen. \n"
+ "-sop : Search option package. Fuer die Produktsuche zu einem Bauteil wird "
+ "standardmässig der Value verwendet. Mit dieser Option wird mit "
+ "Value und Packagebezeichnung gesucht, um genauere Ergebnisse zu erzielen.\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+#require 5.1001
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+#include "designlink-inc.ulp"
+
+string Version = "1.0.7";
+string NotAssigned = "not assigned";
+string LibName;
+int NrDev = 0;
+string DevFullName[];
+string DevSet[];
+string DevName[];
+string DevPkg[];
+string DevTech[];
+string DevDesc[];
+int DevOCIdx[];
+string DevOC[];
+string DevMF[];
+string DevMPN[];
+string DevProdDesc[];
+string DevImgLink[];
+numeric string DevList[];
+
+// For transferring OCs to other library
+int Transfer = 0;
+string NewLibPath;
+
+
+if (DIVersion != Version) {
+ dlgMessageBox(tr("Verschiedene Versionen von ") + filename(argv[0]) + " (" + Version + ") " +
+ tr("und Include ") + "designlink-inc.ulp (" + DIVersion + ") !\n");
+}
+
+InitCountryData();
+InitCfg();
+
+DIAdvice = "\n " + tr("Bitte manuell suchen oder Part überspringen !") + "\n";
+DISkipRem = 0; // For processing the libraries we don't want to skip the unfound parts by default
+
+// Cool string replace function...
+string StrRep(string str, string a, string b) {
+ int la = strlen(a), lb = strlen(b);
+ if (la == 0) return str; // Makes no sense. Should be treated as an error !
+ for (int pos = strstr(str, a); pos >= 0; pos = strstr(str, a, pos + lb)) {
+ str = strsub(str, 0, pos) + b + strsub(str, pos + la);
+ }
+ return str;
+}
+
+// Windows uses backslashes for directories which have to be backslashed which have to be backslashed...
+string SetWeirdBackSlashesForWindows(string ReasonblePathWithSlashes) {
+ return StrRep(ReasonblePathWithSlashes, "/", "\\\\");
+}
+
+string ImgFile(string s) {
+ return StrRep(s, "/", "@") + ".png";
+}
+
+void InitFarnellNewark(int idx) {
+ DILanguage = "en";
+ DICountry = (idx == 0) ? "UK" : "US";
+ InitCountryData();
+}
+
+void FillDevListRow(int idx) {
+ sprintf(DevList[idx], "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", DevSet[idx], DevPkg[idx],
+ DevTech[idx], DevFullName[idx], DICompany, DevOC[idx], DevMPN[idx], DevProdDesc[idx]);
+}
+
+void SearchDev(int sel_idx) {
+ DISkipRem = 0;
+ Clear();
+
+ // Prepare country settings, Farnell/Newark
+ InitFarnellNewark(DevOCIdx[sel_idx]);
+ // Go ahead !
+ // translate to German !!!
+ string product = SingleSearch(DIModeLbrSearch, tr(" DesignLink Devicesuche und -anzeige - ") + LibName,
+ DevDesc[sel_idx], DevImgLink[sel_idx],
+ (DevOC[sel_idx] == NotAssigned) ? DISearchByKeyword : DISearchByOC,
+ (DevOC[sel_idx] == NotAssigned) ? DevFullName[sel_idx] : DevOC[sel_idx],
+ DevFullName[sel_idx]);
+ // Cancel: Nothing to do. Reset Flag.
+ if (DICancelSearch) {
+ DICancelSearch = 0;
+ return;
+ }
+ if (product != "") {
+ string s[];
+ strsplit(s, product, '\t');
+ DevOC[sel_idx] = s[0];
+ DevMF[sel_idx] = s[1];
+ DevMPN[sel_idx] = s[2];
+ DevProdDesc[sel_idx] = s[5];
+ }
+ else {
+ DevOC[sel_idx] = DIUnknown;
+ DevMF[sel_idx] = "";
+ DevMPN[sel_idx] = "";
+ DevProdDesc[sel_idx] = "";
+ }
+ FillDevListRow(sel_idx);
+}
+
+// Save the stuff !
+string SaveAttributes() {
+ string cmds, cmd;
+ // Transfer option
+ if (Transfer) sprintf(cmd, "OPEN '%s';\n", NewLibPath); cmds += cmd;
+ //-------------------------------------------------------------------
+ for (int i = 0; i < NrDev; i++) {
+ if (DevOC[i] != NotAssigned) {
+ InitFarnellNewark(DevOCIdx[i]);
+ sprintf(cmd, "EDIT %s.dev;\n", DevSet[i]); cmds += cmd;
+ sprintf(cmd, "PACKAGE '%s';\n", (DevName[i] == "''") ? "" : DevName[i]); cmds += cmd;
+ sprintf(cmd, "TECHNOLOGY '%s';\n", (DevTech[i] == "''") ? "" : DevTech[i]); cmds += cmd;
+ sprintf(cmd, "ATTRIBUTE %s '%s';\n", DIAttOC, DevOC[i]); cmds += cmd;
+ sprintf(cmd, "ATTRIBUTE %s '%s';\n", DIAttMF, DevMF[i]); cmds += cmd;
+ sprintf(cmd, "ATTRIBUTE %s '%s';\n", DIAttMPN, DevMPN[i]); cmds += cmd;
+ }
+ }
+ cmds += "WRITE;\n";
+ return cmds;
+}
+
+// ------------ Library Device --------------------
+if (!library) {
+ dlgMessageBox(tr("Bitte starten Sie vom Bibliotheks-Editor aus !"));
+ exit(EXIT_FAILURE);
+}
+
+library(L) {
+ // Parsing arguments:
+ int both_oc, export, skip_exp;
+ // Statistic stuff
+ int statistics;
+ string st_opt_list = "-st_list";
+ string st_opt_idx = "-st_idx";
+ string st_opt_nr_dev = "-st_nr_dev";
+ string st_opt_nr_oc_f = "-st_nr_oc_f";
+ string st_opt_nr_oc_n = "-st_nr_oc_n";
+ string st_opt_nr_not_ass = "-st_nr_not_ass";
+ // The parameters themselves
+ string st_list;
+ int st_idx = -1;
+ int st_all_nr_dev;
+ int st_all_nr_oc_f;
+ int st_all_nr_oc_n;
+ int st_all_nr_not_ass;
+ int st_nr_oc_f;
+ int st_nr_oc_n;
+ int st_nr_not_ass;
+
+ for (int i = 1; i <= argc; ++i) {
+ if (argv[i] == "-sop") DISearchOptPac = 1;
+ if (argv[i] == "-both_oc") both_oc = 1;
+ if (argv[i] == "-skip_exp") skip_exp = 1;
+ // Transfer option: Not supported officially. Used internally.
+ if (strsub(argv[i], 0, 9) == "-transfer") {
+ Transfer = 1;
+ NewLibPath = strsub(argv[i], 9); // Full path
+ }
+ // Statistic function: Also for internal use.
+ if (strsub(argv[i], 0, strlen(st_opt_list)) == st_opt_list) {
+ statistics = 1;
+ both_oc = 1; // In that case we want it for both order codes
+ skip_exp = 1; // In that case we don't want the images exported
+ st_list = strsub(argv[i], strlen(st_opt_list)); // Full path
+ }
+ if (strsub(argv[i], 0, strlen(st_opt_idx)) == st_opt_idx)
+ st_idx = strtol(strsub(argv[i], strlen(st_opt_idx)));
+ if (strsub(argv[i], 0, strlen(st_opt_nr_dev)) == st_opt_nr_dev)
+ st_all_nr_dev = strtol(strsub(argv[i], strlen(st_opt_nr_dev)));
+ if (strsub(argv[i], 0, strlen(st_opt_nr_oc_f)) == st_opt_nr_oc_f)
+ st_all_nr_oc_f = strtol(strsub(argv[i], strlen(st_opt_nr_oc_f)));
+ if (strsub(argv[i], 0, strlen(st_opt_nr_oc_n)) == st_opt_nr_oc_n)
+ st_all_nr_oc_n = strtol(strsub(argv[i], strlen(st_opt_nr_oc_n)));
+ if (strsub(argv[i], 0, strlen(st_opt_nr_not_ass)) == st_opt_nr_not_ass)
+ st_all_nr_not_ass = strtol(strsub(argv[i], strlen(st_opt_nr_not_ass)));
+ }
+ if (Transfer && !NewLibPath) {
+ dlgMessageBox("Missing transfer library path !");
+ exit(EXIT_FAILURE);
+ }
+ if (statistics && !st_list) {
+ dlgMessageBox("Missing library list for statistics !");
+ exit(EXIT_FAILURE);
+ }
+ // Optional generation of image files
+ // If not specified to skip the export check if it's necessary:
+ if (!skip_exp) {
+ string cmds, cmd;
+ string img_dir = filesetext(L.name, "");
+ string matches[];
+ int dir_error;
+ if (!fileglob(matches, img_dir)) {
+ // Need to use CMD for Windows (?)
+ if (system("CMD /C \"mkdir \"" + SetWeirdBackSlashesForWindows(img_dir) + "\"\"") != 0) {
+ dlgMessageBox("Creating image directory " + SetWeirdBackSlashesForWindows(img_dir) + " failed !");
+ dir_error = 1;
+ }
+ export = 1;
+ }
+ L.packages(P) {
+ string img_file = ImgFile(P.name);
+ if (!fileglob(matches, img_dir + "/" + img_file)) {
+ export = 1;
+ real large = u2inch(P.area.x2 - P.area.x1);
+ if (P.area.y2 - P.area.y1 > large)
+ large = u2inch(P.area.y2 - P.area.y1);
+ large = max(0.01, large); // use a minimum size to avoid 0 (in case of empty package)
+ real f = max(50, min(1.0 / large * 150, 2400.0)); // max. 2 Inch long
+ sprintf(cmd, "EDIT %s.PAC;\nEXPORT IMAGE '%s' %.0f;\n", P.name, img_dir + "/" + img_file, f);
+ cmds += cmd;
+ }
+ }
+ if (export && !dir_error) {
+ dlgMessageBox(tr("Erzeugung der Package-Bilder zunächst !"));
+ cmds += "RUN '" + argv[0] + "' -skip_exp"; // Run again without doing the export !
+ for (int i = 1; i <= argc; ++i) cmds += " " + argv[i];
+ exit(cmds);
+ }
+ }
+ //------------------------------------------------------------------------
+ // We don't use those flags here. Set them to false
+ DIInStock = 0;
+ DIRoHS = 0;
+ LibName = filename(L.name);
+ string dev_list_head = tr("Deviceset\tPackage\tTechnologie\tDevicename\tOrdercode-Typ\tOrdercode\tHerstellercode\tBeschreibung");
+
+ L.devicesets(DS) {
+ DS.devices(D) {
+ if (D.package) {
+ string t[];
+ int n = strsplit(t, D.technologies, ' ');
+ for (int i = 0; i < n; i++) {
+ string full_name = techpacvar(DS.name, D.name, t[i], D.package.name);
+ // Same problem like for package names
+ string description = " Deviceset: " + DS.name + " " +
+ " Package: " + (D.package.name ? D.package.name : "---") +
+ " Technology: " + t[i] +
+ " Device name: " + full_name + "
"
+ "With this ULP you can do a general product search or a search for all parts "
+ "of your schematic, check price and availability and order directly at Farnell. "
+ "Found order codes can be saved as attributes. "
+ "The order list can be exported."
+ "
"
+ "Usage: run designlink-order [-general]|[-sop]"
+ "
"
+ "Options: "
+ "
"
+ "
-general
General product search. Without this option search is done "
+ "for all parts of a schematic.
"
+ "
-sop
Search option package. By default, for a product search the part "
+ "value is used. With this option value and package name are used.
"
+ "
"
+ "
"
+ "Author: support@cadsoft.de
",
+ "de: DesignLink Suche und Bestellung\n"
+ "
"
+ "Mit diesem ULP können Sie eine allgemeine Produktsuche oder eine Suche für "
+ "alle Bauteile Ihres Schaltplans durchführen, Preis und Verfügbarkeit prüfen "
+ "und direkt bei Farnell bestellen. "
+ "Gefundene Ordercodes können als Attribute gespeichert werden. "
+ "Die Bestelliste kann exportiert werden."
+ "
"
+ "Usage: run designlink-order [-general]|[-sop]"
+ "
"
+ "Optionen: "
+ "
"
+ "
-general
Allgemeine Produktsuche. Ohne diese Option erfolgt die "
+ "Suche für alle Bauteile eines Schaltplans.
"
+ "
-sop
Search option package. Für die Produktsuche zu einem Bauteil wird "
+ "standardmässig der Value verwendet. Mit dieser Option wird mit "
+ "Value und Packagebezeichnung gesucht.
"
+ "
"
+ "
"
+ "Autor: support@cadsoft.de
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+#require 7.0101 // uses UL_PART.module* members
+
+#include "designlink-inc.ulp"
+
+string Version = "1.0.7"; // 2010-08-13: Part of beta 5.10.1
+ // 2010-08-24: Checkbox Ordercode speichern
+ // 2010-08-30: Value und Package in Liste mit TAB getrennt, nicht mehr mit " "
+ // clipDeviceDescription, nur Headerzeile anzeigen
+
+if (DIVersion != Version)
+ dlgMessageBox(tr("Verschiedene Versionen von ") + filename(argv[0]) + " (" + Version + ") " +
+ tr("und Include ") + "designlink-inc.ulp (" + DIVersion + ") !\n");
+
+string SchPartName[]; // name, sheet, coordinates of every part to save attributes into schematic
+numeric string SchPartSheet[]; // string needed for sorting
+
+int Icnt = 0;
+
+int CntSchPart = 0;
+string SchParts[]; // the collected parts, value:partname+sheet \t partname...
+string SchPartModule[]; // The part's module (if any)
+string SchPartModPart[]; // The part's corresponding part in module
+string SchPartValue[];
+string SchPartPackage[];
+string SchPartDescription[]; // The part's device description
+int SchQuantPart[];
+string SchFilename;
+string OrderCode[];
+string OrderCodes[];
+
+string SchPartAttOC[]; // the existing Farnell or Newark order code
+string SchPartAttMF[]; // the existing Manufacturer name
+string SchPartAttMPN[]; // the existing Manufacturer Part Number
+int PCBcount = 1; // PCB multiplyer
+int CntBasketLines = 0; // positions to order
+int CntInStock = 0;
+string NrPositions;
+numeric string PartCode[];
+string PartCodeHeader = tr("Anzahl\tValue\tPackage\tOrdercode\tHersteller\tHerstellercode\tVerfügbarkeit\tPreis (ab)\tBeschreibung"); // 2020-08-27 "/" zu TAB geändert Value\tPackage
+
+// Debug stuff
+void DbgWriteCode(string scode, int index) {
+ output(DIDbgFile, "wt")
+ for (int nw = 0; nw < DINrProductsInList; nw++) {
+ printf("%s\n", DIProductList[nw]);
+ }
+ return;
+}
+
+void DbgWritePartCode(void) {
+ output(DIDbgFile, "wt") {
+ printf("\n");
+ printf("%s\n", PartCodeHeader);
+ for (int n = 0; n < CntSchPart; n++) {
+ printf("%s\n", PartCode[n]);
+ }
+ printf("*end*");
+ }
+ return;
+}
+// End Debug stuff
+
+/************** Functions ****************************************************************/
+string GetBasket() { // 2010-08-09 alf
+ string basket;
+ CntBasketLines = 0;
+ CntInStock = 0;
+ string firsttilde = "";
+ string s[];
+ for (int n = 0; n < CntSchPart; n++) {
+ // WSP: Könnte man nicht alleine mit PartCode arbeiten ?
+ int cnt = strsplit(s, PartCode[n], '\t');
+ int partcnt = strtol(s[0]);
+ int availcnt = strtol(s[6]); // 2010-08-30
+ // Wenn ein Code vorhanden ist
+ if (OrderCode[n] && OrderCode[n] != DIUnknown) {
+ CntBasketLines++;
+ // Bestellen, wenn das Produkt auf Lager ist !
+ if (availcnt > 0) {
+ CntInStock++;
+ string h;
+ sprintf(h, "%s%s~%d", firsttilde, OrderCode[n], partcnt);
+ basket += h;
+ firsttilde = "~";
+ }
+ }
+ }
+ sprintf(NrPositions, "%s%d %s%d %s%d",
+ tr("Anzahl Positionen: "), CntSchPart,
+ tr("Mit Ordercodes: "), CntBasketLines,
+ tr("Auf Lager: "), CntInStock
+ );
+ string xbasket;
+ sprintf(xbasket, "%s ",
+ DIShoppingURL, basket, tr("Zum Warenkorb hinzufügen"));
+ return xbasket;
+}
+
+
+string GetShoppingURL() {
+ string url, order_str = "";
+ if (DIProductSel >= 0) {
+ string s[];
+ strsplit(s, DIProductList[DIProductSel], '\t');
+ order_str = s[0] + "~1"; // Only one piece
+ }
+ sprintf(url, "%s",
+ DIShoppingURL, order_str, tr("Selektion zum Warenkorb hinzufügen"));
+ return url;
+}
+
+
+string GetDescription(int idx) {
+ string description = " Value: " + (SchPartValue[idx] ? SchPartValue[idx] : "---") + " " +
+ " Package: " + (SchPartPackage[idx] ? SchPartPackage[idx] : "---");
+ if (SchPartDescription[idx]) description += " " + SchPartDescription[idx];
+ return description;
+}
+
+// Replace the Quantity with the multiple of number of pcbs
+void UpdateQuantity(int nr_pcbs) {
+ for (int i = 0; i < CntSchPart; i++) {
+ string s[];
+ int cnt = strsplit(s, PartCode[i], '\t');
+ sprintf(PartCode[i], "%d", SchQuantPart[i] * nr_pcbs);
+ for (int j = 1; j < cnt; j++)
+ PartCode[i] += "\t" + s[j];
+ }
+ return;
+}
+
+
+int NewSearch(int point) {
+ DISkipRem = 0; // reset DISkipRem
+ string s[];
+ int cnts = strsplit(s, PartCode[point], '\t');
+ Clear();
+
+ string farnell_part = SingleSearch(DIModeNewSearch, DICompany + " DesignLink " + tr("Bauteilsuche für ") + SchFilename,
+ GetDescription(point), "", DISearchByOC, s[3],
+ (s[3] == DIUnknown) ? SchPartValue[point] : s[3]); // Initially suggest part value for search if OC is unknown
+ // Cancel: Nothing to do. Reset Flag.
+ if (DICancelSearch) {
+ DICancelSearch = 0;
+ return 0;
+ }
+ else if (farnell_part != "") {
+ string o[];
+ strsplit(o, farnell_part, '\t');
+ OrderCode[point] = o[0];
+ SchPartAttOC[point] = o[0];
+ sprintf(PartCode[point], "%d\t%s\t%s\t%s\t%s",
+ SchQuantPart[point] * PCBcount,
+ SchPartValue[point],
+ SchPartPackage[point],
+ farnell_part,
+ SchParts[point]
+ );
+ }
+ else {
+ OrderCode[point] = DIUnknown;
+ SchPartAttOC[point] = DIUnknown;
+ sprintf(PartCode[point], "%d\t%s\t%s\t%s\t\t\t\t\t\t%s", // 2010-08-27
+ SchQuantPart[point] * PCBcount,
+ SchPartValue[point],
+ SchPartPackage[point],
+ SchPartAttOC[point],
+ SchParts[point]
+ );
+ }
+ return 0;
+}
+
+
+void GetOrderCode(void) {
+ DIAdvice = "\n " + tr("Bitte manuell suchen oder Part überspringen !") + "\n"; // If no result
+ string actVal = "";
+ string actPac = "";
+ string s[];
+ string description = "";
+ for (int n = 0; n < CntSchPart; n++) {
+ Clear();
+ string farnell_part = "";
+ string sch_key = (SchPartValue[n]) ? SchPartValue[n] : SchPartPackage[n]; // Fall, dass Value leer beachten !
+ if (DISearchOptPac && SchPartValue[n] && SchPartPackage[n]) sch_key += " " + SchPartPackage[n]; // 2010-08-28 aus Space muss später TAB werden
+ if (!SchPartAttOC[n]) {
+
+ // Do the actual Search (if the user doesn't want to skip the rest)
+ status(tr("Suche") + " " + sch_key);
+ if (!DISkipRem) {
+ farnell_part = SingleSearch(DIModeInitSearch, DICompany + " DesignLink " + tr("Bauteilsuche für ") + SchFilename,
+ GetDescription(n), "", DISearchByKeyword, sch_key, sch_key);
+ }
+ strsplit(s, farnell_part, '\t');
+
+ if (DIDebug) output(DIDbgFile, "wt") printf("\n%s\n", sch_key);
+ OrderCode[n] = s[0]; // farnell order code
+ if (!farnell_part) {
+ OrderCode[n] = DIUnknown;
+ sprintf(PartCode[n], "%d\t%s\t%s\t%s\t\t\t\t\t\t%s", // 2010-08-27 es wird immer Value und Package aus dem SCH benutzt
+ SchQuantPart[n], SchPartValue[n], SchPartPackage[n], OrderCode[n], SchParts[n]
+ );
+ }
+ else {
+ sprintf(PartCode[n], "%d\t%s\t%s\t%s\t%s", // 2010-08-27 es wird immer Value und Package aus dem SCH benutzt
+ SchQuantPart[n], SchPartValue[n], SchPartPackage[n], farnell_part, SchParts[n]
+ );
+ }
+ if (DIDebug) DbgWriteCode(sch_key, n);
+ }
+ else { // 2010-08-05 if order code exists, fill line
+ if (SchPartAttOC[n] == DIUnknown) {
+ sprintf(PartCode[n], "%d\t%s\t%s\t%s\t\t\t\t\t\t%s", // 2010-08-28 space zu TAB geändert
+ SchQuantPart[n],
+ SchPartValue[n], SchPartPackage[n],
+ SchPartAttOC[n],
+ SchParts[n]
+ );
+ }
+ else {
+ status(tr("Prüfe Preis und Verfügbarkeit: ") + SchPartAttOC[n]); // to see eagle/ulp is running
+ farnell_part = SingleSearch(DIModeInitSearch, DICompany + " DesignLink " + tr("Bauteilsuche für ") + SchFilename,
+ GetDescription(n), "", DISearchByOC, SchPartAttOC[n], SchPartAttOC[n]);
+ // Normal case: Search by OC was successful, the part is returned
+ // Special case: The OC is not (no longer) valid.
+ // The user can choose s.th. by manual search. We take this instead.
+ // Or if he skips the part, set the stuff to "unknown"
+ if (farnell_part) {
+ strsplit(s, farnell_part, '\t');
+ OrderCode[n] = s[0];
+ SchPartAttOC[n] = s[0];
+ sprintf(PartCode[n], "%d\t%s\t%s\t%s\t%s", // 2010-08-27 space zu TAB geändert
+ SchQuantPart[n], SchPartValue[n], SchPartPackage[n], farnell_part, SchParts[n]
+ );
+ }
+ else {
+ OrderCode[n] = DIUnknown;
+ SchPartAttOC[n] = DIUnknown;
+ sprintf(PartCode[n], "%d\t%s\t%s\t%s\t%s\t%s\t\t\t\t%s", // 2010-08-27 Space zu TAB geändert
+ SchQuantPart[n],
+ SchPartValue[n], SchPartPackage[n],
+ SchPartAttOC[n],
+ SchPartAttMF[n],
+ SchPartAttMPN[n],
+ SchParts[n]
+ );
+ }
+ }
+ }
+ }
+ DISkipRem = 0; // Reset after run through all parts is finished
+ return;
+}
+
+string SaveAttributes() { // 2010-08-09 alf
+ string cmd, h;
+
+ // Display of attributes. Useful feature. Do we add that ?
+ // => Too much stuff visible. Texts cover each other
+ // CHANGE DISPLAY OFF | VALUE | NAME | BOTH
+ //string attdisplay[] = { "OFF", "VALUE", "NAME", "BOTH" };
+ //int attdisplayoption = 0;
+ //dlgDialog(filename(argv[0])) {
+ // dlgGroup(tr("Attribute - Anzeigeoptionen")) {
+ // dlgRadioButton(tr("&Keine Anzeige"), attdisplayoption);
+ // dlgRadioButton(tr("&Wert anzeigen"), attdisplayoption);
+ // dlgRadioButton(tr("&Name anzeigen"), attdisplayoption);
+ // dlgRadioButton(tr("Wert &und Name anzeigen"), attdisplayoption);
+ // }
+ // dlgHBoxLayout {
+ // dlgStretch(1);
+ // dlgPushButton("+OK") dlgAccept();
+ // dlgStretch(1);
+ // }
+ //};
+
+ // We turn off visibility of attributes
+ cmd += "CHANGE DISPLAY OFF;\n";
+
+ int index[];
+ // Sortiert nach Modul, dann nach Sheet, dann nach Partname. reduziert lediglich das Herumspringen beim Speichern.
+ sort(CntSchPart, index , SchPartModule, SchPartSheet, SchParts);
+ for (int n = 0; n < CntSchPart; n++) {
+ string l[]; // split line
+ int cntl = strsplit(l, PartCode[index[n]], '\t'); // 2010-08-27 s[1] is the value, s[2] is the package
+ string r[]; // split row
+ int cntr = strsplit(r, l[cntl-1], ' ');
+ for (int np = 0; np < cntr; np++) {
+ for (int i = 0; i < Icnt; i++) {
+ if (SchPartName[i] == r[np]) {
+ // Bei einem hierarchischen Part muß ins Modul gegangen werden und das entspr. Part im Modul behandelt werden !
+ string pname = (SchPartModule[i] == "") ? SchPartName[i] : SchPartModPart[i];
+ // 0=Quant., 1=Value, 2=Package, 3=Ordercode Farnell, 4=Manufacturer Name, 5=Manuf. Code, 6=Verfügbarkeit, 7=Preis, 8=Beschreibung, 8=Value, 9=Partnames
+ sprintf(h, "EDIT %s.%s%s;\n", SchPartModule[i], (SchPartModule[i] == "") ? "s" : "m", SchPartSheet[i]); cmd += h;
+ sprintf(h, "ATTRIBUTE %s %s '%s';\n", pname, DIAttOC, l[3]); cmd += h;
+ sprintf(h, "ATTRIBUTE %s %s '%s';\n", pname, DIAttMF, l[4]); cmd += h;
+ sprintf(h, "ATTRIBUTE %s %s '%s';\n", pname, DIAttMPN, l[5]); cmd += h;
+ break;
+ }
+ }
+ }
+ }
+ cmd += "WRITE;\n";
+
+// //Debug stuff for checking command sequence
+// dlgDialog(tr("Rückgabe Script")) {
+// dlgHBoxLayout dlgSpacing(800);
+// dlgHBoxLayout {
+// dlgVBoxLayout dlgSpacing(600);
+// dlgTextEdit(cmd);
+// }
+// dlgHBoxLayout {
+// dlgStretch(1);
+// dlgPushButton(tr("OK")) dlgAccept();
+// dlgPushButton(tr("CANCEL")) { dlgReject(); exit(-2); }
+// dlgStretch(1);
+// }
+// };
+ return cmd;
+}
+
+
+string clipDeviceDescription(string partdescription) {
+ int pos = strstr(partdescription, "
");
+ if (pos > 0) {
+ return strsub(partdescription, 0, pos); // 2010-08-30 nur headerzeile anzeigen
+ }
+ return partdescription;
+}
+
+
+//---Here we go: Main section---------------------------------
+
+// Get arguments if any
+int OptGeneral = 0; // Means general search => Extended "old" DL interface is launched
+for (int i = 1; i <= argc; ++i) {
+ if (argv[i] == "-sop") DISearchOptPac = 1;
+ if (argv[i] == "-general") OptGeneral = 1;
+}
+
+// Init stuff
+InitCountryData();
+InitCfg();
+// ------------ Schematic Part --------------------
+if (schematic && (!OptGeneral)) {
+ // Keep help here locally "
+ string help[] = {
+ "Bestellliste "
+ "Die Bestellliste ist eine Stückliste all Ihrer Bauteile, die Sie für die "
+ "Fertigung der Leiterplatte benötigen. Je nach vorheriger Suche und Auswahl "
+ "sind den einzelnen Positionen Farnell-Artikel mit Ordercodes zugeordnet. "
+ "Per Doppelklick auf die einzelnen Positionen gelangen Sie zur Detailansicht "
+ "der Artikel und können mit manueller Suche und Auswahl diese "
+ "nochmal ändern oder rückgängig machen. Auf dieselbe Art können Sie auch für Bauteile, "
+ "denen Sie noch keinen Farnell-Artikel zugeordnet haben, eine Auswahl treffen. "
+ "Sie können für Ihre Bestellung eine beliebige Anzahl von Leiterplatten vorgeben "
+ "(in entprechendes Feld eingeben, Aktualisieren drücken). "
+ "Mit dem Link Zum Warenkorb hinzufügen "
+ "gelangen Sie schliesslich zur landesspezifischen Einkaufsseite von Farnell, "
+ "wo alle entsprechenden Produkte in einen Warenkorb gelegt werden, "
+ "soweit Sie auf Lager sind. "
+ "Alles Weitere (Bestellung, Bezahlung) können Sie dort erledigen."
+ "
Ordercodes speichern, Bestellliste exportieren "
+ "Wollen Sie die Ordercodes zu einem späteren Zeitpunkt wiederverwenden, "
+ "z.B. nachdem Sie Änderungen am Schaltplan vorgenommen haben, "
+ "können Sie diese durch Ankreuzen der entsprechenden Checkbox im Schaltplan speichern. "
+ "Beim nächsten Bestellvorgang brauchen Sie dann nur noch Produkte für die neuen "
+ "Bauteile auszusuchen. "
+ "Verwenden Sie Bauteile aus Hersteller-Bibliotheken, die bereits mit Farnell-Ordercodes "
+ "versehen sind, erübrigt sich auch diese Suche. Die entsprechenden Farnell-Artikel werden "
+ "automatisch in die Bestellliste aufgenommen. "
+ "Sie können die Bestellliste auch als Textdatei exportieren, z.B. zur Weiterverarbeitung "
+ "in anderen Systemen."
+ ,
+ "Order list "
+ "The order list is a list of all the parts that you need for manufacturing your PCB. " +
+ "The individual positions are related to " + DICompany + " articles with order codes, " +
+ "depending on your previous search and selection. By doubleclicking the items you get a " +
+ "detail view, can change them once more by manual search and selection or cancel the " +
+ "previous selection. " +
+ "The same way you can make a choice for parts that have not been assigned " + DICompany + " articles yet. " +
+ "You can specifiy the number of PCBs for your order (enter in according field, press " +
+ "update). " +
+ "Pressing the link add to shopping cart directs you to " + DICompany +"'s country specific " +
+ "shopping site and all your products are put into a shopping cart, depending on availability. " +
+ "You can finish all further steps (order, payment) on this site. " +
+ "
Saving the order codes " +
+ "If you want to reuse the order codes later, e.g. after changes of the schematic, you can " +
+ "save them to schematic with the according checkbox. " +
+ "Next time you order, you just need to select the articles for the new parts. " +
+ "If you use parts from manufacturer libraries with " + DICompany + " order codes this selection " +
+ "is also not necessary. The related articles are taken automatically to the order list. "
+ "You can also export the order list as a text file, e.g. for processing in other systems."
+ };
+ // We don't use those flags here.
+ DIInStock = 0;
+ DIRoHS = 0;
+ int saveatt = 1; // Flag for option save the attributes
+ schematic(SCH) {
+ SchFilename = filename(SCH.name);
+ Icnt = 0;
+ SCH.allparts(P) {
+ if (P.device.package) {
+ // For virtual parts get the module name and module part's name
+ if (P.modulepart) {
+ SchPartModule[Icnt] = P.module.name;
+ SchPartModPart[Icnt] = P.modulepart.name;
+ P.modulepart.instances(I) {
+ sprintf(SchPartSheet[Icnt], "%d", I.sheet);
+ if (I.sheet != 0) break;
+ }
+ }
+ else
+ P.instances(I) {
+ sprintf(SchPartSheet[Icnt], "%d", I.sheet);
+ if (I.sheet != 0) break;
+ }
+ SchPartName[Icnt] = P.name;
+ Icnt++;
+ int found = 0;
+ for (int n = 0; n < CntSchPart; n++)
+ if (P.value == SchPartValue[n] && P.device.package.name == SchPartPackage[n]) {
+ SchQuantPart[n]++;
+ SchParts[n] += " " + P.name;
+ found = 1;
+ break;
+ }
+ if (!found) {
+ SchParts[CntSchPart] = P.value + "\t" + P.name;
+ SchPartValue[CntSchPart] = P.value;
+ SchPartPackage[CntSchPart] = P.device.package.name;
+ SchPartDescription[n] = clipDeviceDescription(P.deviceset.description);
+ SchPartAttOC[CntSchPart] = P.attribute[DIAttOC];
+ SchPartAttMF[CntSchPart] = P.attribute[DIAttMF];
+ SchPartAttMPN[CntSchPart] = P.attribute[DIAttMPN];
+ SchQuantPart[CntSchPart] = 1; // Quantity
+ CntSchPart++;
+ }
+ }
+ }
+ GetOrderCode();
+ if (DIDebug) DbgWritePartCode();
+ string basket = GetBasket();
+ int pcsel = -1;
+ sprintf(NrPositions, "%s%d %s%d %s%d", tr("Anzahl Positionen: "), CntSchPart,
+ tr("Mit Ordercodes: "), CntBasketLines, tr("Auf Lager: "), CntInStock);
+ dlgDialog(DICompany + " DesignLink " + tr("Bestellliste für ") + SchFilename) {
+ dlgHBoxLayout dlgSpacing(800);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(400);
+ dlgVBoxLayout {
+ dlgListView(PartCodeHeader, PartCode, pcsel) {
+ NewSearch(pcsel);
+ basket = GetBasket(); // Warenkorb aktualisieren
+ }
+ dlgLabel(tr("Zur Detailansicht oder erneuten Suche der Artikel bitte diese doppelklicken !"));
+ dlgHBoxLayout {
+ dlgLabel(tr("Anzahl Leiterplatten:"));
+ dlgIntEdit(PCBcount, 1, 1000000);
+ dlgPushButton(tr("Aktualisieren")) {
+ UpdateQuantity(PCBcount);
+ basket = GetBasket();
+ }
+ dlgSpacing(10);
+ dlgVBoxLayout {
+ dlgHBoxLayout dlgSpacing(280);
+ dlgLabel(NrPositions, 1);
+ }
+ dlgSpacing(10);
+ dlgVBoxLayout {
+ dlgHBoxLayout dlgSpacing((DIDlgLang = "de") ? 160 : 150);
+ dlgLabel(basket, 1);
+ }
+ dlgCheckBox(tr("Ordercodes speichern"), saveatt);
+ dlgPushButton(tr("Exportieren") + "...") {
+ string file = dlgFileSave(tr("Bestellliste exportieren"), filesetext(filesetext(SCH.name,"") + "-order", ".txt"));
+ if (file) output(file, "wt") {
+ printf("Order list for %s\n", SCH.name);
+ printf("Exported from EAGLE with DesignLink\n\n");
+ printf("%s\n", PartCodeHeader);
+ for (int i = 0; i < CntSchPart; ++i) {
+ string str[];
+ strsplit(str, PartCode[i], '\t');
+ printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
+ str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7], str[8]);
+ }
+ }
+ }
+ dlgPushButton(tr("Hilfe") + "...")
+ dlgMessageBox(help[DILangIdx]);
+ dlgPushButton(tr("Beenden")) dlgAccept();
+ }
+ }
+ }
+ };
+ }
+ SaveCfg();
+ if (saveatt) {
+ status(tr("Ordercodes speichern") + "..."); // This can take a little time for large files
+ exit(SaveAttributes());
+ }
+}
+
+else if (OptGeneral) {
+ DIHtml = " " + tr("Bitte geben Sie unten einen Suchstring ein !") + " ";
+ DIMode = 0; // Display search message
+ dlgDialog(DICompany + " DesignLink " + tr("allgemeine Suche")) {
+ string keyword = "";
+ string url = GetShoppingURL();
+ dlgVBoxLayout {
+ dlgHBoxLayout dlgSpacing(800);
+ dlgHBoxLayout {
+ dlgTextView(DIHtml);
+ dlgVBoxLayout dlgSpacing(400);
+ }
+ dlgListView(DIProductListHead, DIProductList, DIProductSel)
+ if (dlgSelectionChanged()) {
+ ShowSelection();
+ url = GetShoppingURL();
+ }
+ dlgHBoxLayout {
+ dlgCheckBox(tr("Vorrätig"), DIInStock);
+ dlgCheckBox("RoHS", DIRoHS);
+ dlgStretch(1);
+ dlgPushButton(tr("Vorige"))
+ if (DIProductOffset > 0) {
+ DIProductOffset -= DINrProductsPerPage;
+ DoSearch(keyword);
+ url = GetShoppingURL();
+ }
+ dlgLabel(DIResInfo, 1);
+ dlgPushButton(tr("Nächste"))
+ if (DIProductOffset + DINrProductsPerPage < DINrAccessibleProducts) {
+ DIProductOffset += DINrProductsPerPage;
+ DoSearch(keyword);
+ url = GetShoppingURL();
+ }
+ else
+ dlgMessageBox(tr("Keine weiteren Produkte verfügbar!"));
+ dlgVBoxLayout {
+ dlgHBoxLayout dlgSpacing(238);
+ dlgHBoxLayout {
+ dlgSpacing(35);
+ dlgLabel(url, 1);
+ }
+ }
+ }
+ dlgHBoxLayout {
+ dlgStringEdit(keyword, DISearchHist, 9);
+ dlgPushButton(tr("+Suchen")) {
+ DoSearch(keyword);
+ url = GetShoppingURL();
+ }
+ dlgPushButton(tr("Beenden")) dlgReject();
+ }
+ }
+ }; // The ; is necessary here. Is this a bug of ULP ?
+ SaveCfg();
+}
+else
+ dlgMessageBox(tr("Bitte starten Sie vom Schaltplan aus !"));
+
diff --git a/trunk/ulp/dif40.ulp b/trunk/ulp/dif40.ulp
new file mode 100644
index 00000000..deb27056
--- /dev/null
+++ b/trunk/ulp/dif40.ulp
@@ -0,0 +1,441 @@
+#usage "Export DIF 4.0 format
"
+ "This format is used for production and test purposes. It has been defined by Digitaltest GmbH.
"
+ "Run the ULP from the board editor and get the file boardname.dif.
"
+ "Please have a look at the \"user definable parameters\" section of the program."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+
+// 2005-02-28: Corrected output for mirrored components
+// Added "File Save" dialog
+// by support@cadsoft.de
+// 2005-11-09: Corrected Y Coordinate, was always minus
+// 2008-05-27: Corrected relativ coordinates if package rotate in 0.1 degree
+// by alf@cadsoft.de
+
+
+string REVISION = "2.00";
+
+////////////////// user definable parameters ////////////////////////////////////////////////
+int pad_layer = 1; // change to 16 if pad parameters should be taken from bottom layer
+int nr_of_layers = 2;
+int fill_polygons = 1; // set to 0 if polygons are not to be filled
+ // if set to 1, please make sure the width parameter of the polygons
+ // is >> 0
+ // make also sure the polygon filling is visible in EAGLE
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+
+string difversion = "4.0";
+string jobname, pcbname,
+ shapename[], // package names
+ t[]; // padtypes
+
+real ang2, x, y;
+int nr_of_nets = 0, nr_of_comps = 0, i, new, sx, dummy_pad_code;
+
+//-----------------------------------------------------
+string validname (string s) {
+ int i;
+ for (i = 0; s[i]; i++) {
+ if (s[i] == ',') s[i] = '_';
+ if (s[i] == ';') s[i] = '_';
+ if (s[i] == ')') s[i] = '_';
+ // add further substitutions here
+ }
+ return s;
+}
+//-----------------------------------------------------
+int u2u(int x) { // resolution 1/10000 mm
+ // return u2mil(x); // mil
+ return x;
+}
+//-----------------------------------------------------
+int u2x(int x) {
+ return u2u(x);
+}
+//-----------------------------------------------------
+int u2y(int x) {
+ return u2u(x); // correct sign, was always minus 2005.11.09 alf@cadsoft.de
+}
+//-----------------------------------------------------
+real deg2arc(int x) { // degree to arc
+ return x*PI/180;
+}
+//-----------------------------------------------------
+int u2ang(real x) {
+ if (x > 360)
+ x = x -360;
+ return x;
+}
+//----------------------------------------------------
+void relco (UL_ELEMENT E, int xt, int yt) { // change if finer rotation possible
+ xt = xt - E.x; yt = yt - E.y; // move part origin to 0,0
+ if (E.mirror) { // flip back if mirrored
+ x = -x;
+ }
+ if (E.angle == 0) { // rotate to zero position
+ x = xt; y = yt;
+ }
+ if (E.angle == 90) {
+ x = yt; y = -xt;
+ }
+ if (E.angle == 180) {
+ x = -xt; y = -yt;
+ }
+ if (E.angle == 270) {
+ x = -yt; y = xt;
+ }
+ }
+//-----------------------------------------------------
+string padtype(UL_PACKAGE P, UL_CONTACT C) {
+ string s;
+ int pdi;
+ if (C.pad) {
+ pdi = u2u(C.pad.diameter[pad_layer]);
+ sprintf(s, "pad_%d_%d_%d", C.pad.shape[pad_layer], u2u(C.pad.diameter[pad_layer]), u2u(C.pad.drill));
+ }
+ if (C.smd) {
+ sprintf(s, "smd_%d_%d", u2x(C.smd.dx), u2y(C.smd.dy));
+ }
+ return s;
+}
+//-----------------------------------------------------
+int padindex(UL_PACKAGE P,UL_CONTACT C) {
+ int i = 0;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == padtype(P,C))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+//-----------------------------------------------------
+string viatype(UL_VIA V) {
+ string s;
+ int pdi;
+ pdi = u2u(V.diameter[pad_layer]);
+ sprintf(s, "pad_%d_%d_%d", V.shape[pad_layer], u2u(V.diameter[pad_layer]), u2u(V.drill));
+ return s;
+}
+//-----------------------------------------------------
+int viaindex(UL_VIA V) {
+ int i = 0;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == viatype(V))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+//-----------------------------------------------------
+int realnet(UL_SIGNAL S) {
+ S.contactrefs(S)
+ return 1;
+ return 0;
+}
+
+//////////////////////////////////////////////////////
+void create_environment () {
+ int t = time();
+ printf(" { ENVIRONMENT\n");
+ printf(" { SOURCE \"EAGLE %d.%02d %s Revision %s\" }\n", EAGLE_VERSION, EAGLE_RELEASE, filename(argv[0]),REVISION);
+ printf(" { VERSION %s }\n", difversion);
+ printf(" { DATE %d/%d/%d }\n", t2day(t),t2month(t)+1,t2year(t));
+ printf(" { TIME %d:%d:%d }\n", t2hour(t),t2minute(t),t2second(t));
+ printf(" { UNITS 1/10000 mm }\n");
+ printf(" { LAYER %d }\n", nr_of_layers);
+ printf(" { TOP_LAYER 1 }\n");
+ printf(" { BOTTOM_LAYER 16 }\n");
+ printf(" { NO_NET %d }\n", nr_of_nets);
+ printf(" { NO_COMP %d }\n", nr_of_comps);
+ printf(" }\n");
+}
+//////////////////////////////////////////////////////
+void board_data(UL_BOARD B) {
+ int i = 0;
+ printf (" { BOARD\n");
+ printf (" { F\n");
+ B.wires(W) { // if board outline as wires in board
+ i++;
+ if (W.layer == LAYER_DIMENSION) {
+ printf(" { L (%d,%d) (%d,%d) }\n", u2x(W.x1), u2y(W.y1), u2x(W.x2), u2y(W.y2));
+ }
+ }
+
+ if (i == 0) { // board contains no dim wires, try packages
+ B.elements(E) {
+ E.package.wires(W) {
+ if (W.layer == LAYER_DIMENSION) {
+ printf(" { L (%d,%d) (%d,%d) }\n", u2x(W.x1), u2y(W.y1), u2x(W.x2), u2y(W.y2));
+ }
+ }
+ }
+ }
+
+ printf (" }\n");
+ printf (" }\n");
+}
+//////////////////////////////////////////////////////
+void components(UL_BOARD B) {
+ int i, pic_nr;
+ string devname = "";
+ printf (" { COMPONENTS\n");
+ B.elements(E) {
+ if (E.package) {
+ printf(" { COMP\n");
+ printf(" { COMP_DEF\n");
+ printf(" { NAME %s }\n", E.name);
+ printf(" { PART_NR %s }\n", validname(E.package.name)+"_"+validname(E.package.library));
+ printf(" }\n");
+ printf(" { PIN_DEF\n");
+ int issmd = 0;
+ E.package.contacts(C) {
+ printf(" { PIN %s { NET %s } }\n", C.name, C.signal);
+ if (C.smd) issmd = 1;
+ }
+ // find picture code
+ for (i=0; shapename[i] != validname(E.package.name)+"_"+validname(E.package.library); i++) {
+ }
+ pic_nr = i;
+ printf(" }\n");
+ printf(" { PICTURE\n");
+ printf(" { ORIGIN (%d,%d) }\n", u2x(E.x), u2y(E.y));
+ printf(" { PIC %d }\n", pic_nr);
+ printf(" { ROTATION %d }\n", u2ang(E.angle));
+ int mside = 1;
+ if (E.mirror) {
+ mside = 2;
+ }
+ printf(" { M_SIDE %d }\n", mside);
+ if (issmd) {
+ printf(" { KIND SMD }\n");
+ }
+
+ /* implement later if necessary
+ E.texts(T) {
+ printf(" { TEXT\n");
+ printf(" }\n");
+ }
+ */
+
+ printf(" }\n");
+ printf(" }\n");
+ }
+ }
+ printf(" }\n");
+}
+//////////////////////////////////////////////////////
+void pad_symbols(UL_BOARD B) {
+ int i, j = 0, new; // j+1 = pad index; t[] contains padtypes
+ printf (" { PAD_DEF\n");
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (1 /* C.pad */) {
+ new = 1; // padtype not generated yet
+ for (i = 0; t[i]; i++) {
+ if (t[i] == padtype(E.package, C))
+ new = 0; // padtype exists
+ }
+ if (new) {
+ t[j] = padtype(E.package, C);
+ j++;
+ if (C.pad)
+ printf(" { PAD %d\n { SIZE %d }\n { DRILL %d }\n }\n",
+ j,abs(u2u(C.pad.diameter[pad_layer])),abs(u2u(C.pad.drill)));
+ if (C.smd)
+ printf(" { PAD %d\n { SIZE %d }\n { DRILL 0 }\n }\n",
+ j, min(abs(u2x(C.smd.dx)), abs(u2y(C.smd.dy))));
+ }
+ }
+ }
+ }
+ B.signals(S) {
+ S.vias(V) {
+ new = 1;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == viatype(V))
+ new = 0; // padtype exists
+ }
+ if (new) {
+ t[j] = viatype(V);
+ j++;
+
+ dummy_pad_code = j; // find pad code for dummy pad
+
+ printf(" { PAD %d\n { SIZE %d }\n { DRILL %d }\n }\n",
+ j,u2u(V.diameter[pad_layer]),u2u(V.drill));
+
+
+ }
+ }
+ }
+ printf (" }\n");
+}
+
+//////////////////////////////////////////////////////
+// 2008-05-27: Corrected relativ coordinates if package rotate in 0.1 degree alf@cadsoft.de
+
+void picturePackage(UL_PACKAGE P, int ox, int oy) {
+ real angle, delta = 15;
+
+ P.wires(W) {
+ if (W.layer == LAYER_TPLACE || W.layer == LAYER_TDOCU || W.layer == LAYER_BPLACE || W.layer == LAYER_BDOCU) {
+ if (W.arc) {
+ // process arcs (done with wire segments)
+ printf(" { L (%d,%d)\n", u2x(W.arc.x1-ox), u2y(W.arc.y1-oy));
+ angle = W.arc.angle1 + delta;
+ while (angle < W.arc.angle2) {
+ printf(" (%d,%d)\n",
+ u2x((W.arc.xc-ox+W.arc.radius) * cos(deg2arc(angle))),
+ u2y((W.arc.yc-oy+W.arc.radius) * sin(deg2arc(angle))));
+ angle += delta;
+ }
+
+ printf(" (%d,%d)\n }\n", u2x(W.arc.x2-ox), u2y(W.arc.y2-oy));
+ }
+ else {
+ printf(" { Linie (%d,%d) ", u2x(W.x1-ox), u2y(W.y1-oy));
+ printf("(%d,%d) }\n", u2x(W.x2-ox), u2y(W.y2-oy));
+ }
+ }
+ }
+ P.circles(W) {
+ if (W.layer == LAYER_TPLACE || W.layer == LAYER_TDOCU || W.layer == LAYER_BPLACE || W.layer == LAYER_BDOCU) {
+ printf(" { L (%d,%d)\n", u2x(W.x-ox+W.radius), u2y(W.y-oy));
+ angle = 0;
+ while (angle < 360) {
+ printf(" (%d,%d)\n", u2x((W.x-ox+W.radius) * cos(deg2arc(angle))), u2y((W.y-oy+W.radius) * sin(deg2arc(angle))));
+ angle += delta;
+ }
+ printf(" (%d,%d)\n }\n", u2x(W.x-ox+W.radius), u2y(W.y-oy));
+ }
+ }
+ P.rectangles(W) {
+ if (W.layer == LAYER_TPLACE || W.layer == LAYER_TDOCU || W.layer == LAYER_BPLACE || W.layer == LAYER_BDOCU) {
+ printf(" { L (%d,%d)\n", u2x(W.x1-ox), u2y(W.y1-oy));
+ printf(" (%d,%d)\n", u2x(W.x2-ox), u2y(W.y1-oy));
+ printf(" (%d,%d)\n", u2x(W.x2-ox), u2y(W.y2-oy));
+ printf(" (%d,%d)\n", u2x(W.x1-ox), u2y(W.y2-oy));
+ printf(" (%d,%d)\n }\n", u2x(W.x1-ox), u2y(W.y1-oy));
+ }
+ }
+ int nr_of_pins = 0;
+ P.contacts(C) { nr_of_pins++;}
+ if (nr_of_pins) {
+ printf(" { PINS %d\n", nr_of_pins);
+ }
+ P.contacts(C) {
+ printf(" (%d,%d) %d\n", u2x(C.x-ox), u2y(C.y-oy), padindex(P, C)); // Pin IDs
+ }
+ if (nr_of_pins) {
+ printf(" }\n");
+ }
+ printf(" { SPECIFIC \"%s\" }\n", validname(P.name)+"_"+validname(P.library)); // PACK.NAME
+ printf(" }\n"); // end pic n
+ return;
+}
+
+
+//////////////////////////////////////////////////////
+void pictures(UL_BOARD B) {
+ printf ("{ PIC_LIB\n");
+ sx=0;
+ B.elements(E) {
+ if (E.package) {
+ new = 1; // padtype not generated yet
+ for (i = 0; shapename[i]; i++) {
+ if (shapename[i] == validname(E.package.name)+"_"+validname(E.package.library))
+ new = 0; // ident. package exists
+ }
+ if (new) {
+ shapename[sx] = validname(E.package.name)+"_"+validname(E.package.library);
+ printf(" { PIC %d\n",sx++); // PACKAGE NR
+ picturePackage(E.package, E.x, E.y);
+ }
+ }
+ }
+
+ printf(" { PIC 999\n");
+ printf(" { R (0, 0) }\n");
+ printf(" { PINS 1 (0, 0) %d }\n", dummy_pad_code);
+ printf(" }\n");
+
+ printf("}\n");
+}
+
+//////////////////////////////////////////////////////
+void nets(UL_BOARD B) {
+ printf(" { NET_DEF\n");
+ B.signals(S) {
+ if (realnet(S)) {
+ printf(" { NET %s\n", S.name);
+ S.wires(W) {
+ printf(" { W (%d, %d) %d %d (%d %d) %d %d }\n", u2x(W.x1), u2y(W.y1), W.layer, u2u(W.width), u2x(W.x2), u2y(W.y2), W.layer, u2u(W.width));
+ }
+
+ S.polygons(P) {
+ P.contours(W) {
+ printf(" { W (%d, %d) %d %d (%d %d) %d %d }\n", u2x(W.x1), u2y(W.y1), W.layer, u2u(W.width), u2x(W.x2), u2y(W.y2), W.layer, u2u(W.width));
+ }
+ if (fill_polygons) {
+ P.fillings(W) {
+ printf(" { W (%d, %d) %d %d (%d %d) %d %d }\n", u2x(W.x1), u2y(W.y1), W.layer, u2u(W.width), u2x(W.x2), u2y(W.y2), W.layer, u2u(W.width));
+ }
+ }
+ }
+
+ S.vias(V) {
+ printf(" { V (%d, %d) %d 1, 15 }\n", u2x(V.x), u2y(V.y), viaindex(V));
+ }
+ printf(" }\n");
+ }
+ }
+ printf(" }\n");
+}
+
+//////////////////////////////////////////////////////
+void net_comp_count(UL_BOARD B) {
+ nr_of_nets = 0;
+ nr_of_comps = 0;
+ B.signals(S) {
+ if (realnet(S)) {
+ nr_of_nets++;
+ }
+ }
+ B.elements(E) {
+ if (E.package) {
+ nr_of_comps++;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////
+
+if (board) board(B) {
+ jobname = filename(filesetext(B.name, ""));
+ pcbname = filename(filesetext(B.name, ""));
+
+ string fileName = dlgFileSave("Save DIF 4.0 File", filesetext(B.name, ".dif"), "*.dif");
+ if (fileName == "") exit(0);
+
+ output(fileName) {
+ printf("{ JOB %s\n", jobname);
+ printf(" { PCB %s\n", pcbname);
+ net_comp_count(B);
+ create_environment();
+ board_data(B);
+ pad_symbols(B);
+ pictures(B);
+ nets(B);
+ components(B);
+ printf(" }\n");
+ printf("}\n");
+ }
+ }
+
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+ }
diff --git a/trunk/ulp/dl-Millefori.dru b/trunk/ulp/dl-Millefori.dru
new file mode 100644
index 00000000..759424d5
--- /dev/null
+++ b/trunk/ulp/dl-Millefori.dru
@@ -0,0 +1,69 @@
+description[de] = EAGLE Design Rules\n
\nDie Standard-Design-Rules sind so gewählt, dass sie für \ndie meisten Anwendungen passen. Sollte ihre Platine \nbesondere Anforderungen haben, treffen Sie die erforderlichen\nEinstellungen hier und speichern die Design Rules unter \neinem neuen Namen ab.
+description[en] = EAGLE Design Rules\n
\nDie Standard-Design-Rules sind so gewählt, dass sie für \ndie meisten Anwendungen passen. Sollte ihre Platine \nbesondere Anforderungen haben, treffen Sie die erforderlichen\nEinstellungen hier und speichern die Design Rules unter \neinem neuen Namen ab.
+description[en] = EAGLE Design Rules\n
"
+ "Generates data to control the solder cream dosage for the dispenser "
+ "unit of 'Martin' on 'Bungard' drill/milling machines."
+ "
"
+ "The file boardname.plt contains the coordinates of the SMD pads "
+ "in the top layer, while boardname.plb contains the coordinates of those in the "
+ "bottom layer."
+ "
"
+ "The file boardname.dod contains the information of the SMD pads "
+ "regarding tool number Txx."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+/*
+ Mit uval = 0 - 3 kann die Einheit ** der Daten eingestellt werden.
+
+ ** 0: 1/10 mil
+ ** 1: 1 mil
+ ** 2: 0.025 mm
+ ** 3: 0.01 mm
+
+ *06.12.2001 az
+*/
+
+int uval = 3;
+
+string Version = "1.0.4";
+
+int smdx[], smdy[]; // size of smd
+int x[], y[]; // coordinate of SMD
+int tb[]; // top or bottom side
+int index[];
+int c = 0; // counter
+
+void header(void) {
+ switch (uval) {
+ case 0 :
+ printf("1/10 mil\n%%\n");
+ break;
+
+ case 1 :
+ printf("1 mil\n%%\n");
+ break;
+
+ case 2 :
+ printf("0.025 mm\n%%\n");
+ break;
+
+ case 3 :
+ printf("0.01 mm\n%%\n");
+ break;
+ }
+}
+
+real value (int v) {
+ switch (uval) {
+ case 0 :
+ return (u2mil(v) * 10);
+
+ case 1 :
+ return (u2mil(v));
+
+ case 2 :
+ return (u2mm(v) * 40);
+
+ case 3 :
+ return (u2mm(v) * 100);
+ }
+}
+
+void genfiles(string file) {
+ sort(c, index, tb, smdx, smdy, x, y); // sortiere top/bottom, groesse, coord.
+
+ int tool = 0;
+ int ox =0;
+ int oy =0;
+
+ for (int n = 0; n < c; n++) {
+ if (smdx[index[n]] == ox && smdy[index[n]] ==oy) {
+ ;
+ }
+ else { // *** change tool #
+ ox = smdx[index[n]];
+ oy = smdy[index[n]];
+ tool++;
+
+ printf("T%02d\n", tool); // print tool change in file #1
+
+ output(filesetext(file, ".plb"), "at") {
+ printf("T%02d\n", tool); // print tool change in file #2
+ }
+
+ output(filesetext(file, ".dod"), "at") { // print in file #3
+ printf("T%02d X%06.0f Y%06.0f\t| %06.2f\n", tool,
+ value(smdx[index[n]]), value(smdy[index[n]]),
+ u2mm(smdx[index[n]]) * u2mm(smdy[index[n]]) );
+ }
+ }
+
+ if (tb[index[n]]) {
+ printf("X%06.0fY%06.0f\n",
+ value(x[index[n]]), value(y[index[n]]) );
+ }
+ else {
+ output(filesetext(file, ".plb"), "at") {
+ printf("X%06.0fY%06.0f\n",
+ value(x[index[n]]), value(y[index[n]]) );
+ }
+ }
+ }
+ }
+
+void trailer(void) { printf("M30\n"); }
+
+void menue(void) {
+ dlgDialog("Dose pro") {
+ dlgLabel (usage);
+ int align = 1;
+ dlgHBoxLayout {
+ dlgGroup("Data resolution") {
+ dlgRadioButton("1/10 mil", uval);
+ dlgRadioButton("1 mil", uval);
+ dlgRadioButton("0.025 mm", uval);
+ dlgRadioButton("0.01 mm", uval);
+ }
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+&OK") dlgAccept();
+ dlgPushButton("-&Cancel") exit (0);
+ dlgStretch(1);
+ }
+ };
+ return;
+ }
+
+// main
+if (board) {
+ board(B) {
+ menue();
+ output(filesetext(B.name, ".dod"), "wt") {
+ printf("This file is generated by %s %s, exported from:\n", filename(argv[0]), Version);
+ printf("%s at %s;\n", B.name, t2string(time()));
+ printf("%s;\n\n", EAGLE_SIGNATURE);
+ }
+ output(filesetext(B.name, ".plb"), "wt") {
+ header();
+ }
+ output(filesetext(B.name, ".plt"), "wt") {
+ header();
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.smd) {
+
+ // collect SMD-Pads
+ smdx[c] = C.smd.dx;
+ smdy[c] = C.smd.dy;
+ x[c] = C.smd.x;
+ y[c] = C.smd.y;
+
+ if (E.mirror) {
+ tb[c] = 0;
+ }
+ else {
+ tb[c] = 1;
+ }
+ c++;
+ }
+ }
+ }
+
+ output(filesetext(B.name, ".dod"), "at") {
+ printf("%d SMD-Pads\n\n", c);
+ header();
+ printf("Tool Pad-X Pad-Y Square mm^2\n");
+ }
+ genfiles(B.name);
+ trailer();
+ output(filesetext(B.name, ".plb"), "at") { trailer(); }
+ }
+ }
+}
+
+else dlgMessageBox("Start this ULP from a Board!", "OK");
diff --git a/trunk/ulp/drill-aid.ulp b/trunk/ulp/drill-aid.ulp
new file mode 100644
index 00000000..5c8f8231
--- /dev/null
+++ b/trunk/ulp/drill-aid.ulp
@@ -0,0 +1,75 @@
+#usage "Limit drill diameter of pads, vias and holes for easier manual drilling.\n"
+ "
"
+ "Draws small circles in layer 116 inside the drilling of pads, vias and holes, "
+ "which should make it easier to center the tool while drilling the "
+ "board manually."
+ "
"
+ "Usage: RUN drill-aid [ diameter ]"
+ "
"
+ "Activate layer 116 in addition to the bottom side layers in the "
+ "CAM processor or use the DISPLAY command to activate it for printing."
+ "
"
+ "To delete the elements in layer 116 afterwards, display it without "
+ "any other layers, and use GROUP and DELETE. Then remove the whole "
+ "layer with the command LAYER -116."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+real drilcent = 0.3; // center drill diameter
+
+string cmd = "GRID mm;\nLayer 116 centerDrill;\nchange layer 116;\n";
+
+void center(int x, int y, int drill) {
+ real width = (u2mm(drill) - drilcent) / 2 + 0.05; // overlap 0.05mm 2008-09-01 alf
+ real radius = width / 2 + (drilcent / 2);
+ if (radius < (drilcent / 2 + 0.025) ) return;
+ string h;
+ sprintf(h, "circle %.3f (%.3f %.3f) (%.3f %.3f) ;\n",
+ width,
+ u2mm(x), u2mm(y), u2mm(x) + radius, u2mm(y) );
+ cmd += h;
+ return;
+}
+
+if (board) board(B) {
+ if (argv[1]) drilcent = strtod(argv[1]);
+ else {
+ int Result = dlgDialog("Drill AID V2") {
+ dlgLabel(usage);
+ dlgLabel("&Drill center diameter mm");
+ dlgHBoxLayout {
+ dlgRealEdit(drilcent);
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgStretch(1);
+ dlgPushButton("-&Cancel") dlgReject();
+ }
+ };
+ if (!Result) exit (0);
+ }
+
+ B.holes(L) {
+ center(L.x, L.y, L.drill);
+ }
+ B.elements(E) {
+ E.package.holes(H) {
+ center(H.x, H.y, H.drill);
+ }
+ E.package.contacts(C) {
+ if (C.pad) {
+ center(C.pad.x, C.pad.y, C.pad.drill);
+ }
+ }
+ }
+ B.signals(S) {
+ S.vias(V) {
+ center(V.x, V.y, V.drill);
+ }
+ }
+ exit (cmd);
+}
+
+else dlgMessageBox("Start this ULP in a Board!", "OK");
+exit (0);
diff --git a/trunk/ulp/drillcfg.ulp b/trunk/ulp/drillcfg.ulp
new file mode 100644
index 00000000..11acba42
--- /dev/null
+++ b/trunk/ulp/drillcfg.ulp
@@ -0,0 +1,118 @@
+#usage "Export drill configuration\n"
+ "
"
+ "Generates a drill configuration file for the current board."
+ "
"
+ "Units: mm or inches can be chosen."
+ "
"
+ "The generated file can be edited before saving."
+ "
"
+ "Use this ULP also for checking the drills of a board."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+/*
+ * This EAGLE User Language Program generates
+ * a drill configuration file for the current
+ * board.
+ *
+ * Units can be switched between mm and inch.
+ */
+
+string unitName[] = { "mm", "in" };
+int Unit, unitPrec[] = { 2, 3 }, RoundFactor = pow(10, unitPrec[Unit]),
+ Result = 0, imax = 0;
+real Drilling[];
+string s, fileName, conf = "";
+enum { unitMM, unitINCH};
+
+ int getunit (void) {
+ string s;
+ int Unit = unitMM; // preset unit
+ Result = dlgDialog("Drill Configuration") {
+ dlgHBoxLayout {
+ dlgStretch(0);
+ dlgGroup("Select unit for output file") {
+ dlgStretch(0);
+ dlgGridLayout {
+ dlgCell(1, 0) dlgRadioButton("&mm", Unit);
+ dlgCell(2, 0) dlgRadioButton("&inch", Unit);
+ }
+ }
+ dlgStretch(0);
+ dlgVBoxLayout {
+ dlgHBoxLayout {
+ dlgSpacing(20);
+ dlgStretch(0);
+ dlgPushButton("+OK") dlgAccept();
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgSpacing(20);
+ dlgStretch(0);
+ dlgPushButton("-Quit") dlgReject();
+ dlgStretch(1);
+ }
+ }
+ dlgStretch(1);
+ }
+ dlgStretch(1);
+ };
+ RoundFactor = pow(10, unitPrec[Unit]);
+ return Unit;
+}
+
+void AddDrilling(int Size)
+{
+ real x;
+
+ switch (Unit) {
+ case unitMM: x = round(u2mm(Size) * RoundFactor) / RoundFactor;
+ break;
+ case unitINCH: x = round(u2inch(Size) * RoundFactor) / RoundFactor;
+ break;
+ }
+
+ for (int i = imax; --i >= 0; )
+ if (Drilling[i] == x)
+ return;
+ Drilling[imax++] = x;
+}
+
+Unit = getunit();
+if (Result == 0) exit(0);
+board(B) {
+ B.holes(H) AddDrilling(H.drill);
+ B.signals(S) S.vias(V) AddDrilling(V.drill);
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad)
+ AddDrilling(C.pad.drill);
+ }
+ E.package.holes(H) AddDrilling(H.drill);
+ }
+ sort(imax, Drilling);
+
+ for (int i = 0; i < imax; ++i) {
+ sprintf(s, "T%02d %5.*f%s\n", i + 1, unitPrec[Unit], Drilling[i], unitName[Unit]);
+ conf += s;
+ }
+
+ dlgDialog("Edit Drill Configuration") {
+ dlgVBoxLayout {
+ dlgLabel("Edit only if you are sure what you do!");
+ dlgTextEdit(conf);
+ dlgPushButton("+Ok") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ }
+ };
+
+
+ fileName = dlgFileSave("Save Configuration File", filesetext(B.name, ".drl"), "*.drl");
+ if (fileName == "") exit(0);
+
+ output(fileName) {
+ printf("%s",conf);
+ }
+ }
diff --git a/trunk/ulp/drillegend-stack.ulp b/trunk/ulp/drillegend-stack.ulp
new file mode 100644
index 00000000..95fb8b36
--- /dev/null
+++ b/trunk/ulp/drillegend-stack.ulp
@@ -0,0 +1,1213 @@
+#usage "Drill Legend for Eagle Board.
"
+ "This ULP adds a drill legend to a board in Layer 144 (default). "
+ "Sort both drill tools and drill diameters in the same ascending order as the drill legend. "
+ "You can also generate the drill configuration for the CamProcessor.
Enter here the name of your choice for the title field.
" +
+ "
Rank
"+
+ "
Choose here a number (from 1 to 8) for the position of each field in the drill legend. 0 = unselected.
" +
+ "
" +
+ "
Drill legend Orientation
"+
+ "
Horizontal
" +
+ "
Choose this option for horizontal drill legend.
"+
+ "
Vertical
" +
+ "
Choose this option for vertical drill legend.
";
+
+ string HelpSymbols = "
Symbols
Symbols Settings
" +
+ "
Symbol Layer
" +
+ "
Choose in this field the layer in which you want draw this drill legend.
" +
+ "
Symbol Size
" +
+ "
Enter in this field the symbol diameter (in mils).
" +
+ "
Symbol Width
" +
+ "
Enter in this field the symbol line width (in mils).
" +
+ "Nota: " +
+ "Drilegend.ulp drills symbols and Eagle drills symbols are associated with the same drill tool number " +
+ "in the same ascending order, so each drill tool number always is associated with the same drill symbol. " +
+ "But, they are not associated in the same manner with the holes diameters.
" +
+ "Drilegend.ulp sort the holes diameters (like drillcfg.ulp) in ascending order before to associate each with " +
+ "a drill tool number, so drill tools numbers and holes diameters are sorted together in a same increasing order. " +
+ "Eagle extract the holes diameters as is from the board, and give them a increasing tool number without sort before.
" +
+ "The result of each method is evidently different and that's why it's very important after each run of this ulp " +
+ "to open the \"Options>Settings>Drill\" and verify if it's necessary to update and sort holes diameters and tools numbers " +
+ "in the same ascending order like the drill legend.
";
+
+ string HelpTexts = "
Texts
Texts Settings
" +
+ "
Text Font
" +
+ "
Choose a text font in the list.
Text Size
" +
+ "
Enter in this field the font size (in mils).
" +
+ "
Text Ratio
" +
+ "
Enter in this field the font ratio (in %).
" +
+ "Nota: For printer output choose the font what you want but " +
+ "for gerber output keep VECTOR.
";
+
+ string HelpTable = "
Table
Cell Margin Factor
" +
+ "Enter in theses fields a value (from 1.0 to 9.9) for increase or decrease the space between texts and border cells.
" +
+ "
Horizontal
" +
+ "
Horizontal space between texts and border cells.
" +
+ "
Vertical
" +
+ "
Vertical space between texts and border cells.
" +
+ "Outline Width
" +
+ "
Cell
Enter in this field the outline width of a cell (in mils).
" +
+ "
Title
" +
+ "
Enter in this field the outline width of the title (in mils).
" +
+ "
Table
" +
+ "
Enter in this field the outline width of the table (in mils).
";
+
+ string HelpHoles = "
Holes
Non-Plated
" +
+ "All holes diameters (plated or not plated) are sorted in ascending mode.
" +
+ "
Alternate
" +
+ "
For each diameter, non-plated holes are treated after plated holes but before the following diameter.
" +
+ "
Mixed
" +
+ "
Only one diameter per column. Plated and non-plated holes with same diameter are added in the same column. " +
+ "In this case, plated status show: \"BOTH\".
" +
+ "
Last
" +
+ "
All plated holes diameter are treated first, then all non-plated are treated last.
" +
+ "Plated Status
" +
+ "
Not Plated
" +
+ "
Enter in this field a string meaning: not plated hole. Default: \"NOT\".
" +
+ "
Mixed
" +
+ "
Enter in this field a string meaning: plated and not plated use the same drill tool. Default: \"BOTH\".
" +
+ "
Plated
" +
+ "
Enter in this field a string meaning: plated hole. Default: \"YES\".
" +
+ "Nota: Avoid to use the same diameter for plated an non-plated holes.
" +
+ "Unit Precision
" +
+ "Choose here the number of unit after the decimal point." +
+ "
Mils
" +
+ "
Unit of precision for mils.
MM
" +
+ "
Unit of precision for millimeters.
Holes Tolerance
" +
+ "
Plated Holes
" +
+ "
Enter in this field your value for plated holes tolerance.
" +
+ "
Non-Plated Holes
" +
+ "
Enter in this field your value for non-plated holes tolerance.
" +
+ "Nota: Tolerance field is String type, so you can enter anything like: 0,02 or +/- 0.03
";
+
+ string HelpOutputs = "
Outputs
Drill Rack File for CAM Processor
" +
+ "
Create file
" +
+ "
Click on this check button for create the drill rack file used in the cam processor. " +
+ "Choose the output unit: milimeters or inches.
definiert einen Suffix, der an den Dateinamen angehängt wird
"
+ "
-u mm|inch
bestimmt die Einheit für Koordinaten und Abmessungen
"
+ "
-a
schaltet die Option 'Immer Vektor-Font' ein
"
+ "
-w
schaltet die Option 'Linienbreite benutzen' ein
"
+ "
-f
schaltet die Option 'Flächen füllen' ein
"
+ "
"
+ "Beispiel:"
+ "
"
+ "RUN dxf -s _s1 -u mm -w"
+ "
"
+ "Erzeugt eine DXF-Datei namens dateiname_s1.dxf, mit der Einheit Millimeter und "
+ "Linien die in ihrer wirklichen Breite dargestellt werden."
+ "
"
+ "Die generierte DXF-Syntax folgt der Spezification im Buch "
+ "
\nThis program can only work in the board or schematic editor."));
+ exit(1);
+ }
+
+OutputFileName = filesetext(OutputFileName, FileNameSuffix + ".dxf");
+
+if (DoDialog) {
+ dlgDialog(tr("DXF Converter")) {
+ dlgHBoxLayout dlgSpacing(400); // let's have some space for the file name
+ dlgHBoxLayout {
+ dlgLabel(tr("&Output file"));
+ dlgStringEdit(OutputFileName);
+ dlgPushButton(tr("&Browse")) {
+ string FileName = dlgFileSave(tr("Save DXF file"), OutputFileName, tr("DXF files (*.dxf)"));
+ if (FileName)
+ OutputFileName = FileName;
+ }
+ }
+ dlgCheckBox(tr("&Always vector font"), AlwaysVectorFont);
+ dlgLabel(tr("If checked, texts will always be drawn with the builtin vector font."));
+ dlgCheckBox(tr("&Use wire widths"), UseWireWidths) { UseWireWidths |= FillAreas; };
+ dlgLabel(tr("If checked, wires, arcs and circles will be generated as polygons showing their real widths. This, however, can cause the DXF file to become very large! Uncheck this if you do not need the real widths."));
+ dlgCheckBox(tr("&Fill areas"), FillAreas) { UseWireWidths |= FillAreas; }
+ dlgLabel(tr("If checked, wires, arcs etc. will be filled (implies 'Use wire widths'!)."));
+ if (VisibleSupplyLayer) {
+ dlgGroup(tr("Thermal Emulation")) {
+ dlgHBoxLayout {
+ dlgLabel(tr("Relative inner diameter"));
+ dlgRealEdit(AnnulusRelInnerDiameter, 0.5, 0.99);
+ }
+ dlgHBoxLayout {
+ dlgLabel(tr("Relative gap size"));
+ dlgRealEdit(AnnulusRelGap, 0.1, 0.5);
+ }
+ dlgLabel(tr("Only the outer diameter of Thermals is available. The inner diameter and gap size are calculated based on the outer diameters according to these factors."));
+ }
+ }
+ dlgGroup(tr("Unit")) {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgRadioButton("&mm", Unit);
+ dlgRadioButton("&inch", Unit);
+ }
+ dlgLabel(tr("Defines the unit used for coordinates and values in the DXF file"));
+ }
+ }
+ dlgStretch(1);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton(tr("+OK")) {
+ string a[];
+ if (!fileglob(a, OutputFileName) || dlgMessageBox(tr("File exists: ") + OutputFileName + tr("\n\nOverwrite?"), tr("+&Yes"), tr("-&No")) == 0)
+ dlgAccept();
+ }
+ dlgPushButton(tr("-Cancel")) { dlgReject(); exit(1); }
+ dlgPushButton(tr("About")) dlgMessageBox(usage);
+ }
+ };
+ }
+
+output(OutputFileName) {
+ DxfSection("HEADER");
+ DxfVersion();
+ if (board) board(B) Area(B.area);
+ else sheet(S) Area(S.area);
+ DxfEndSection();
+ DxfSection("TABLES");
+ DxfTable("LTYPE", 1);
+ DxfLineTypes();
+ DxfEndTable();
+ DxfTable("LAYER", 255);
+ if (board) board(B) B.layers(L) Layer(L);
+ else schematic(SCH) SCH.layers(L) Layer(L);
+ DxfEndTable();
+ DxfEndSection();
+ DxfSection("BLOCKS");
+ DxfBlocks();
+ DxfEndSection();
+ DxfSection("ENTITIES");
+ if (board) board(B) Board(B);
+ else sheet(S) Sheet(S);
+ DxfEndSection();
+ DxfTrailer();
+ }
diff --git a/trunk/ulp/e-attributverwaltung.ulp b/trunk/ulp/e-attributverwaltung.ulp
new file mode 100644
index 00000000..ae6c5568
--- /dev/null
+++ b/trunk/ulp/e-attributverwaltung.ulp
@@ -0,0 +1,1486 @@
+#usage "de:Attributverwaltung
"
+ "Mit diesem ULP können Sie Attribute anlegen und verwalten. Für einige "
+ "Bauteile (speziell für Zeichnungsrahmen aus der Bibliothek "
+ "e-elektro-zeichnungsrahmen) sind schon bei der Bibliotheksdefinition "
+ "Attribute und die entsprechenden Textplatzhalter angelegt worden.
"
+ "Es wird unterschieden zwischen lokalen und globalen Attributen: "
+ "Bei einem lokalen Attribut wurde in der Bibliothek im Symbol "
+ "ein Platzhaltertext (>ATTRIBUTNAME) angelegt und in der Devicedefinition "
+ "das entsprechende Attribut definiert. Der Attributwert ist üblicherweise "
+ "noch nicht festgelegt. "
+ "Ein Attribut gilt ebenfalls als lokal, wenn es erst im Schaltplan "
+ "für ein spezielles Bauteil angelegt wurde. Der Platzhaltertext muss "
+ "aber bereits bei der Bauteildefinition im Symbol angelegt worden sein, "
+ "ansonsten kann mit CHANGE DISPLAY OFF | VALUE | NAME | BOTH im SCH/BRD "
+ "die Anzeige des Attribute entsprechend eingestellt werden.
"
+ "Ein globales Attribut wird direkt im Schaltplan oder Board angelegt. "
+ "Es ist für alle Bauteile gültig, die bereits einen entsprechenden "
+ "Platzhaltertext haben. Dieser muss bereits bei der Bauteildefinition "
+ "im Symbol angelegt worden sein. Globale Attribute werden üblicherweise "
+ "für Zeichnugsrahmen verwendet.
"
+ "Das ULP hilft Ihnen beim Bearbeiten und Erstellen von Attributen. "
+ "Nach dem Start entscheiden Sie zuerst was Sie tun möchten. "
+ "Es gibt die Möglichkeiten LOKALE oder GLOBALE Attribute zu "
+ "bearbeiten oder anzulegen. "
+ "Wollen Sie zum Beispiel für einen Zeichnungsrahmen ein globales Attribut anlegen, "
+ "wählen Sie unter GLOBALE die Option anlegen. "
+ "Doppelklicken Sie dann auf den Rahmen in der Liste der Bauteile. "
+ "Es öffnet sich ein neues Fenster mit den vorhandenen Attributen. "
+ "Durch Doppelklick auf einen Eintrag in der Liste wählen Sie das Attribut, "
+ "das angelegt werden soll. Es öffnet sich ein weiteres Fenster, in dem Sie "
+ "den Wert für das Attribut definieren können. "
+ "Aktivieren Sie unter Attribut bearbeiten die Option ja, "
+ "wenn Sie die Änderung übernehmen wollen, nicht ändern, wenn Sie "
+ "keine Änderung machen wollen, oder löschen wenn sie das Attribut "
+ "löschen wollen. "
+ "Mit OK übernehmen Sie die Einstellungen. "
+ "Dieselbe Vorgehensweise gilt auch für das Bearbeiten und Anlegen "
+ "von lokalen Attributen.
"
+ "Das ULP kann auch in einer Bibliothek im Device-Editor zum einfachen "
+ "erstellen und bearbeiten von lokalen Attributen verwendet werden.
"
+ "Benutzung des ULP: "
+ "RUN e-attributverwaltung [+L | -L] | [+A | -A] | 1DESCRIPTION "
+ ""
+ "Option +L setzt die Attribute aus einer definierbaren Liste im Deviceset (direkt ohne Nachfragen). "
+ "Option -L löscht die Attribute aus einer definierbaren Liste im Deviceset (direkt ohne Nachfragen). "
+ "Option +A setzt die Attribute aus einer definierbaren Liste in allen Devicesets in der LBR (direkt ohne Nachfragen). "
+ "Option -A löscht die Attribute aus einer definierbaren Liste in allen Devicesets in der LBR (direkt ohne Nachfragen). "
+ ""
+ "Option 1DESCRIPTION erzeugt ein ATTRIBUTE 'A_DESCRIPTION' für jedes Bauteil (Part) und kopiert den Inhalt "
+ "der Kopfzeile der Description als Wert in das Attribut, um die Description am Symbol des Part anzeigen zu können. "
+ "Diese Option gibt es nur im Schaltplan.
"
+ "Author alf@cadsoft.de"
+ ,
+ "en:"
+ "Author alf@cadsoft.de"
+
+// 2.0.0 | 2008-11-07 - Globale Attribute von SCH -> BRD oder BRD -> SCH übertragen
+// bzw. zwischen SCH und BRD angleichen.
+// Technologien und Package-Varianten werden berücksichtigt
+// 2.0.1 | 2009-11-27 - Menü-Button mit ALT-Option
+//
+// 2.1.0 | 2009-12-17 - Es kann eine Liste von Attribute-Namen verwaltet werden,
+// um in Devices in der Bibliothek diese Attribute zu definieren.
+// Option +L setzt die Attribute aus der Liste ohne nachfragen
+// Option -L löscht die Attribute aus der Liste ohne nachfragen
+//
+// 2.1.1 | 2010-01-14 - Globale Attribute mit INDEX_Sxxx werden nicht berücksichtigt,
+// wegen e-seiten-index.ulp.
+//
+// 2.1.2 | 2010-02-10 - Liste erst in Funktion aus_liste_anlegen() laden.
+// 2.1.3 | 2010-08-17 - Option +A -A alf@cadsoft.de
+//
+// 2.1.4 | 2010-12-14 - Option 1DESCRIPTION erzeugt ein ATTRIBUTE A_DESCRIPT mit dem
+// Inhalt der Kopfzeile der Description des Parts (Devices).
+// Diese Optiopn ist nur im Schaltplan verfügbar.
+//
+// 2.1.5 | 2011-03-02 - Option Auch in Board übertragen.
+//
+// 2.1.6 | 2011-12-07 - Variablenname variant[] für Version 6 angepasst.
+// Reservierte Textplatzhalter erweitert.
+//
+// 2.1.7 | 2011-12-30 - Lösche selektierte Attribute in allen Devices
+//
+// 2.1.8 | 2013-08-21 - Bei konsistenten SCH/BRD bei TABs anzeigen.
+//
+// 2.1.9 | 2013-11-28 - Attribute Option constant variable
+// Die Option "Change Option" ist per Default auf ON gesetzt,
+// damit man constant bzw. variable einfacher editieren kann.
+//
+string Version = "Version 2.1.9"; // 1.0.0 - 2008-04-17 alf@cadsoft.de
+
+string cmd, s;
+string Pname[], Psheet[];
+int cntP = 0;
+int cntA = 0;
+string AttribPart[];
+string AttribWert[];
+numeric string ListAttrib[];
+string Platzhalter[];
+string LPlatzhalter[];
+string PacVariant[];
+string Techno[];
+string ReservedAttname = "INDEX_S"; // 2010-01-14
+string Description1[]; // 2010-12-14
+string DelAttrib[]; // 2011-12-30
+
+
+string setze[] = { "nicht ändern", "ja", "löschen" };
+enum { nein, ja, loeschen };
+string Edit[] = { "Device", "Part", "Element" };
+enum { Device, Part, Element };
+string aType[] = { "Lokale", "Globale" };
+enum { Lokal, Global };
+enum { neu, bearbeiten };
+string AttOption[] = { "variable", "constant" }; // 2013-09-02
+enum { ATTvariable, ATTconstant };
+
+// 2008-09-02
+enum { DEVeditor, SCHeditor, BRDeditor };
+int isBoard = 0;
+int isSchematic = 0;
+string Ename[];
+int cntE = 0;
+int cntEA = 0;
+string AttribElement[];
+string EAttribWert[];
+string EListAttrib[];
+string EPlatzhalter[];
+
+string sch_attributte[], brd_attributte[];
+string sch_attributteValue[], brd_attributteValue[];
+int cnt_schattr, cnt_brdattr;
+int in_brd_sch = 0;
+
+string attdiff_sch[], attdiff_brd[], attdiff_val[];
+int cntdiffs = 0;
+int cntdiffb = 0;
+int cntdiffval = 0;
+
+// 2009-12-15
+string attribute_list_datei = filesetext(argv[0], ".lst");
+string attribute_liste[];
+int cntattributelist = 0; // nicht verändern
+
+
+// ############## Funktionen ################
+string AttribT(string s) {
+ if (s[0] == '>') { // folgende Textplatzhalter sind keine Attribute
+ if (s == ">NAME" ||
+ s == ">VALUE" ||
+ s == ">PART" ||
+ s == ">GATE" ||
+ s == ">XREF" ||
+ s == ">CONTACT_XREF" ||
+ s == ">ASSEMBLY_VARIANT" ||
+ s == ">DRAWING_NAME" ||
+ s == ">LAST_DATE_TIME" ||
+ s == ">PLOT_DATE_TIME " ||
+ s == ">SHEETNR" ||
+ s == ">SHEETS" ||
+ s == ">SHEET"
+ ) s = "";
+ else s = strsub(s, 1);
+ }
+ else s = ""; // kein Attribut-Platzhalter, nur Text.
+ return s;
+}
+
+string changeAttribOption(string att) { // 2013-09-02
+ string s[];
+ int cnt = strsplit(s, att, '\t');
+ if (s[5] == AttOption[ATTvariable]) s[5] = AttOption[ATTconstant];
+ else if (s[5] == AttOption[ATTconstant]) s[5] = AttOption[ATTvariable];
+ return strjoin(s, '\t');
+}
+
+// ========== Unter-Menu Ändern ========== //
+string changeAttrib(string att, int Objekt, int newchange) {
+ string s[];
+ int setAttrib = -1;
+ int cnt = strsplit(s, att, '\t');
+ if (s[1] == setze[1]) setAttrib = ja;
+ int Result = dlgDialog("Attribut") {
+ dlgLabel(s[0]);
+ dlgHBoxLayout {
+ dlgLabel("&Wert ");
+ dlgStringEdit(s[2]);
+ }
+ if (newchange == bearbeiten) {
+ dlgGroup("Attribut bearbeiten") {
+ dlgRadioButton("&nicht ändern", setAttrib);
+ dlgRadioButton("&ja", setAttrib);
+ dlgRadioButton("&löschen", setAttrib);
+ }
+ }
+ else {
+ dlgGroup("Attribut anlegen") {
+ dlgRadioButton("&nein", setAttrib);
+ dlgRadioButton("&ja", setAttrib);
+ }
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") {
+ if (setAttrib < 0) {
+ if (newchange == bearbeiten) dlgMessageBox("Wählen Sie eine Option,\nnein, ja, löschen", "OK");
+ else dlgMessageBox("Wählen Sie eine Option,\nnein, ja", "OK");
+ }
+ else {
+ att = s[0] + "\t" + setze[setAttrib] + "\t" + s[2];
+ for (int n = 3; n < cnt; n++) att += "\t" + s[n];
+ dlgAccept();
+ }
+ }
+ dlgPushButton("-Abbruch") dlgReject();
+ dlgStretch(1);
+ }
+ };
+ return att;
+}
+
+
+void setzealle(int nein_ja) {
+ string s[];
+ for (int a = 0; a < cntP; a++) {
+ int cnt = strsplit(s, ListAttrib[a], '\t');
+ ListAttrib[a] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2];
+ for (int n = 3; n < cnt; n++) ListAttrib[a] += "\t" + s[n];
+ }
+ return;
+}
+
+
+void setze_attribut(int nein_ja, int sel) {
+//stop
+ string s[];
+ for (int n = 0; n < cntP; n++) {
+ if (AttribPart[n] == AttribPart[sel]) {
+ strsplit(s, ListAttrib[n], '\t');
+ ListAttrib[n] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2] + "\t" + s[3] + "\t" + s[4];
+ }
+ }
+ return;
+}
+
+
+
+void setze_variant(int nein_ja, int sel) {
+ string s[];
+ for (int n = 0; n < cntP; n++) {
+ if (PacVariant[n] == PacVariant[sel]) {
+ strsplit(s, ListAttrib[n], '\t');
+ ListAttrib[n] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2] + "\t" + s[3] + "\t" + s[4];
+ }
+ }
+ return;
+}
+
+
+void setze_techno(int nein_ja, int sel) {
+ string s[];
+ for (int n = 0; n < cntP; n++) {
+ if (Techno[n] == Techno[sel]) {
+ strsplit(s, ListAttrib[n], '\t');
+ ListAttrib[n] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2] + "\t" + s[3] + "\t" + s[4];
+ }
+ }
+ return;
+}
+
+
+void copyPlatzhalterList(int L) {
+ for (int n = 0; n < L; n++) {
+ ListAttrib[n] = LPlatzhalter[n] + "\t" + setze[ja] + "\t";
+ }
+ ListAttrib[L] = ""; // letzter Eintrag löschen
+ cntP = L;
+ return;
+}
+
+
+void generateAttribScript(int Objekt, int Editor, string PartName, string Sheet) {
+ string a[];
+ int cnt;
+ cmd = "";
+
+ for (int n = 0; n < cntP; n++) {
+ cnt = strsplit(a, ListAttrib[n], '\t');
+ if (a[1] == setze[ja]) {
+ if (deviceset) {
+ if(a[3][0] == '\'') sprintf(s, "PACKAGE %s;\n", a[3]);
+ else sprintf(s, "PACKAGE '%s';\n", a[3]); // 2013-09-02 Packagevariante kann mit "-" beginnen!
+ cmd += s;
+ sprintf(s, "TECHNOLOGY %s;\n", a[4]);
+ cmd += s;
+ sprintf(s, "ATTRIBUTE %s '%s' %s;\n", a[0], a[2], a[5]); // 2013-09-02 Option conctant/variable
+ }
+ else if (Objekt == Global) {
+ sprintf(s, "ATTRIBUTE * %s '%s';\n", a[0], a[2]);
+ }
+ else if (Objekt == Lokal) {
+ cmd += "CHANGE DISPLAY OFF;\n"; // | VALUE | NAME | BOTH
+ sprintf(s, "ATTRIBUTE %s %s '%s' %s;\n", PartName, a[0], a[2], a[5]);
+ }
+ else {
+ cmd += "CHANGE DISPLAY OFF;\n";
+ sprintf(s, "ATTRIBUTE %s %s '%s' %s;\n", PartName, a[0], a[2], a[5]);
+ }
+ cmd+=s;
+ }
+ else if (a[1] == setze[loeschen]) {
+ if (deviceset) {
+ sprintf(s, "PACKAGE %s;\n", a[3]);
+ cmd += s;
+ sprintf(s, "TECHNOLOGY %s;\n", a[4]);
+ cmd += s;
+ sprintf(s, "ATTRIBUTE %s DELETE;\n", a[0]);
+ }
+ else if (Objekt == Global) {
+ sprintf(s, "ATTRIBUTE * %s DELETE;\n", a[0]);
+ }
+ else {
+ sprintf(s, "ATTRIBUTE %s '%s' DELETE;\n", PartName, a[0]);
+ }
+ cmd+=s;
+ }
+ }
+ string ecmd;
+ if (Editor == SCHeditor && in_brd_sch) ecmd = "EDIT .SCH;\n" + cmd + "EDIT .BRD;\n" + cmd; // 2011-03-02 auch in Board übertragen
+ else if (Editor == BRDeditor && in_brd_sch) ecmd = "EDIT .BRD;\n" + cmd + "EDIT .SCH;\n" + cmd; // 2011-03-02 auch in Schaltplan übertragen
+ else if (Editor == BRDeditor || Editor == SCHeditor) ecmd = cmd;
+ else ecmd = cmd;
+ exit(ecmd);
+}
+
+
+void getTextPlatzhalterDS(UL_DEVICESET DS) {
+ cntP = 0;
+ DS.devices(D) {
+ string t[];
+ int n = strsplit(t, D.technologies, ' ');
+ n = 1; /************** nur eine Technologie behandeln, ********
+ ************** alle Technologien haben die gleichen Attribute ********/
+ for (int na = 0; na < n; na++) {
+ string la[]; // lokales attribute
+ int cntla = 0;
+ D.attributes(A, t[na]) {
+ la[cntla] = A.name;
+ cntla++;
+ }
+ D.gates(G) {
+ G.symbol.texts(T) {
+ string s = AttribT(strupr(T.value)); // keine reservierten Textplatzhalter >NAME >VALUE >PART >GATE ...
+ for (int n = 0; n < cntla; n++) {
+ if (s == la[n]) {
+ s = ""; // Textplatzhalter schon benutzt
+ break;
+ }
+ }
+ if (s) { // sammle Platzhalter
+ AttribPart[cntP] = s; // zum selektieren eines Attribut
+ Platzhalter[cntP] = s;
+ ListAttrib[cntP] = s + "\t" + setze[ja] + "\t" + "" + "\t" + D.name + "\t" + t[na] ;
+ Techno[cntP] = t[na];
+ PacVariant[cntP] = D.name;
+ cntP++;
+ }
+ }
+ }
+ }
+ }
+ ListAttrib[cntP] = "";
+ return;
+}
+
+
+void getAttributeDS(UL_DEVICESET DS) {
+ cntP = 0;
+ cntA = 0;
+ DS.devices(D) {
+ /*
+ string dname = D.name;
+ if (dname[0] == '-') { // 2013-09-02
+ if (dlgMessageBox("!Verbotenes Zeichen im Namen.
Package-Variante "+ D.name + " hat Minus-Zeichen an erster Position.", "OK", "CANCEL") != 0) exit(-379);
+ }
+ */
+ string t[];
+ int n = strsplit(t, D.technologies, ' ');
+ for (int na = 0; na < n; na++) {
+ D.attributes(A, t[na]) {
+ AttribPart[cntA] = A.name;
+ AttribWert[cntA] = A.value;
+ sprintf(ListAttrib[cntA], "%s\t%s\t%s\t%s\t%s\t%s", A.name, setze[ja], A.value, D.name, t[na], AttOption[A.constant]); // 2013-09-02
+ Techno[cntA] = t[na];
+ PacVariant[cntA] = D.name;
+ cntA++;
+ AttribPart[cntA] = "";
+ ListAttrib[cntA] = "";
+ }
+ }
+ cntP = cntA;
+ }
+ return;
+}
+
+
+void clear_list(void) { // zurück aus Untermenu löscht die Einträge aller Listen
+ cntP = 0;
+ cntA = 0;
+ cntE = 0;
+ ListAttrib[0] = "";
+ AttribPart[0] = "";
+ AttribWert[0] = "";
+ Platzhalter[0] = "";
+ EListAttrib[0] = "";
+ AttribElement[0] = "";
+ EAttribWert[0] = "";
+ EPlatzhalter[0] = "";
+ return;
+}
+
+
+int diff_attr_sch_brd(int menu_on) {
+ int notfound, n;
+ for (n = 0; n < cnt_schattr; n++) {
+ notfound = 1;
+ for (int x = 0; x < cnt_brdattr; x++) {
+ if (sch_attributte[n] == brd_attributte[x]) {
+ notfound = 0;
+ if (sch_attributteValue[n] != brd_attributteValue[x]) {
+ sprintf(attdiff_val[cntdiffval], "%s\t%s\t%s", sch_attributte[n], sch_attributteValue[n], brd_attributteValue[x]);
+ cntdiffval++;
+ }
+ break;
+ }
+ }
+ if (notfound) {
+ sprintf(attdiff_sch[cntdiffs], "%s\t'%s'", sch_attributte[n], sch_attributteValue[n]);
+ cntdiffs++;
+ attdiff_sch[cntdiffs] = ""; // letzen markieren
+ }
+ }
+ for (n = 0; n < cnt_brdattr; n++) {
+ notfound = 1;
+ for (int x = 0; x < cnt_schattr; x++) {
+ if (brd_attributte[n] == sch_attributte[x]) {
+ notfound = 0;
+ break;
+ }
+ }
+ if (notfound) {
+ sprintf(attdiff_brd[cntdiffb], "%s\t'%s'", brd_attributte[n], brd_attributteValue[n]);
+ cntdiffb++;
+ attdiff_brd[cntdiffb] = ""; // letzen markieren
+ }
+ }
+ if (!menu_on) return cntdiffs + cntdiffb;
+ return 0;
+}
+
+
+void hilfe(void) {
+ dlgDialog("Hilfe "+filename(argv[0])) {
+ dlgLabel(usage);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ return;
+}
+
+
+// ======== Unter-Menu ======== //
+// ### Attribute Menu zum Anlgen bzw. Ändern ###
+int menu(int Objekt, int Editor, string PartName, string Sheet, int newchange) {
+ int sel = -1;
+ int selp = -1;
+ int alle_setzen = -1;
+ int changeoption = 1; // 2013-09-02
+ string cnt_selAttrib = "";
+ string InfoCnt = " ";
+ string attmsg = " ";
+
+ switch(Editor) {
+ case Device : if (newchange == neu) sprintf(InfoCnt, "%d Textplatzhalter in %s %s verfügbar", cntP, Edit[Editor], PartName);
+ else sprintf(InfoCnt, "%d Attribute in %s %s", cntP, Edit[Editor], PartName);
+ break;
+ case Part : if (newchange == neu) sprintf(InfoCnt, "%d Textplatzhalter in %s %s sheet %s verfügbar", cntP, Edit[Editor], PartName, Sheet);
+ else sprintf(InfoCnt, "%d Attribute in %s %s sheet %s", cntP, Edit[Editor], PartName, Sheet);
+ attmsg = "Attribute auch in Board übertragen.";
+ break;
+ case Element : if (newchange == neu) sprintf(InfoCnt, "%d Textplatzhalter in %s %s verfügbar", cntE, Edit[Editor], PartName);
+ else sprintf(InfoCnt, "%d Attribute in %s %s", cntE, Edit[Editor], PartName);
+ attmsg = "Attribute auch in Schaltplan übertragen.";
+ break;
+ }
+ int srt = 1;
+ int RESULT = dlgDialog(aType[Objekt]+" Attribute") {
+ dlgHBoxLayout dlgSpacing(300);
+ dlgLabel(InfoCnt, 1);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(500);
+ switch(Editor) {
+ case Device : dlgListView("Attribute\tDefiniert\tWert\tVariant\tTechnologie\tOption", ListAttrib, sel, srt) { // 2013-09-02
+ if (changeoption) ListAttrib[sel] = changeAttribOption(ListAttrib[sel]); // 2013-09-02
+ else ListAttrib[sel] = changeAttrib(ListAttrib[sel], Objekt, newchange);
+ }
+ sprintf(InfoCnt, "DEVICE %d Attribute", cntP);
+ break;
+ case Part : dlgListView("Attribute\tDefiniert\tWert", ListAttrib, sel, srt) {
+ ListAttrib[sel] = changeAttrib(ListAttrib[sel], Objekt, newchange);
+ }
+ break;
+ case Element : dlgListView("Attribute\tDefiniert\tWert", ListAttrib, sel, srt) {
+ ListAttrib[sel] = changeAttrib(ListAttrib[sel], Objekt, newchange);
+ }
+ break;
+ }
+ }
+
+ dlgHBoxLayout {
+ if (newchange == bearbeiten) {
+ dlgGroup("Alle Attribute ändern") {
+ if (deviceset) {
+ dlgHBoxLayout {
+ dlgRadioButton("&nein", alle_setzen);
+ dlgRadioButton("&ja", alle_setzen);
+ dlgRadioButton("&löschen", alle_setzen);
+ dlgStretch(1);
+ }
+ dlgLabel("
"
+ "Starten Sie das Programm vom Bibliothekseditor aus."
+ "
"
+ "Sie können damit aus vorhandenen Symbolen ein fertiges Device mit "
+ "Dummy-Package erzeugen. Die Pad-Namen des Package lassen sich editieren. "
+ "Das ist deshalb wichtig, weil in den Devices der Elektro-Bibliotheken nicht die "
+ "Symbol-Pin-Namen, sondern die Package-Pad-Namen angezeigt werden."
+ "
"
+ "Das Programm erzeugt eine temporäre Script-Datei im ersten SCR-Pfad, die "
+ "nach Drücken des OK-Buttons sofort ausgeführt wird. Die Datei wird gelöscht, "
+ "sobald EAGLE beendet wird.
"
+"Wählen Sie im Bereich Symbolauswahl-Filter, welche Symbolart in der oberen Liste dargestellt "
+"werden soll. Ein Doppelklick auf einen Listeneintrag fügt dieses Symbol in die Device-Liste "
+"ein.
"
+"Wenn Sie ein Schütz entwerfen, wählen Sie zuerst eine Spule, dann die Kontakte und danach "
+"eventuell Zusatzsymbole ohne Kontakte. Das ganze Bauteil wird in dieser Reihenfolge im Schaltplan "
+"dargestellt. Die Reihenfolge ist wichtig, damit der Kontaktspiegel richtig dargestellt wird. "
+"Das erste GATE erhält den Addlevel Must, und nur unter diesem Must-Gate wird der Kontaktspiegerl erzeugt.
"
+"Die Zusatzsymbole werden nur auf Anforderung (mit INVOKE) in den Schaltplan geholt.
"
+"Danach können Sie nach Anklicken des entsprechenden Buttons die Kontaktnamen editieren.
"
+"Nach OK entsteht das Bauteil in der geladenen Bibliothek. Vergessen Sie nicht, sie danach abzuspeichern.
"
+"Wenn Sie Bauteile ohne Kontaktspiegel entwerfen wollen, selektieren Sie Alle Symbole und "
+"übertragen Sie die Symbole in die Device-Liste, die nicht mit _KS (Kontaktspiegel) enden. "
+;
+
+void ShowHelp(void) {
+ dlgDialog("Hilfe") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(300);
+ dlgVBoxLayout {
+ dlgLabel("&Hilfe");
+ dlgTextView(HelpAllgemein);
+ }
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+}
+
+string HelpTextKontaktnamen =
+"Tragen Sie die gewünschten Kontaktnamen durch Leerzeichen getrennt ein und kontrollieren Sie \
+die Namen in der Listenansicht.\n\
+Reihenfolge: links oben, links unten (Spule), erster Kontakt oben, erster Kontakt unten etc.";
+
+string ErrorCorrectNames =
+"Kontaktamen nicht korrekt oder kein Device-Listen-Eintrag!\n"
+"Jeder Kontaktname darf nur einmal vorkommen, und die Anzahl \n"
+"der Namen muss der Anzahl der Pins entsprechen.\n";
+
+
+// Debug-Routinen
+string DebugString = "";
+
+void DebugInt(string name, int n) {
+ string s;
+ sprintf(s, name + " %d\n", n);
+ DebugString += s;
+ return;
+}
+
+void DebugStr(string name, string v) {
+ DebugString += name + " " + v +"\n";
+ return;
+}
+
+void ShowInteger(string v, int n) {
+ string s;
+ sprintf(s, "%d", n);
+ dlgMessageBox(v + ": " + s);
+ return;
+}
+
+void ShowString(string label, string v) {
+ dlgMessageBox(label + ": " + v);
+ return;
+}
+
+// -----------------------------------------------------------------------------
+string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Blanks im Inneren werden 1 Blank
+ int i, n;
+ string t;
+
+ while (s && isspace(s[0]))
+ s = strsub(s, 1);
+ while (s && isspace(s[strlen(s) - 1]))
+ s = strsub(s, 0, strlen(s) - 1);
+ // Doppel-Blanks
+ for (i = 0; i < strlen(s); i++) {
+ if (!isspace(s[i])) t[n++] = s[i];
+ else {
+ if ((strlen(s) > i+1) && isspace(s[i+1]));
+ else t[n++] = s[i];
+ };
+ }
+ s = t;
+ return s;
+}
+
+// Erzeuge Symbolauswahlliste
+void MakeSymSelectList(void) {
+ int NumLines = 0;
+ int NrOfPins = 0;
+ int Xref = 0;
+ string PNam;
+ NrOfPins = 0;
+
+ library(L) {
+ f = filename(L.name);
+ f = filesetext(f, "$$$.scr");
+ f = path_scr[0] + '/' + f; // verwende Script-Pfad
+ L.symbols(S) {
+ NrOfPins = 0;
+ Xref = 0;
+ PinCount[NumLines] = "";
+ PinNames[NumLines] = "";
+ SymName[NumLines] = S.name;
+ S.texts(T) {
+ if (T.value == ">XREF") Xref++;
+ }
+ S.pins(P) {
+ NrOfPins++;
+ PinNames[NumLines] += StripWhiteSpace(P.name) + " ";
+ sprintf(PinCount[NumLines], "%d", NrOfPins);
+ PNam = P.name;
+ }
+ if ((strstr(S.name, "SPULE") >= 0) && SymDisplay == 0) {
+ Lines[NumLines++] = PinCount[NumLines] + // Spulen
+ "\t" + PinNames[NumLines] +
+ "\t" + SymName[NumLines];
+ }
+ if (strstr(S.name, "_KS", strlen(S.name) - 3) >= 0) { // nur wenn Symbolname auf xxxx_KS endet
+ if (NrOfPins && SymDisplay == 1 && strstr(S.name, "SPULE") == -1 && strstr(PNam, "_") == -1) {
+ Lines[NumLines++] = PinCount[NumLines] + // Hauptkontakte
+ "\t" + PinNames[NumLines] +
+ "\t" + SymName[NumLines];
+ }
+ if (NrOfPins && SymDisplay == 2 && strstr(S.name, "SPULE") == -1 && strstr(PNam, "_") == 0) {
+ Lines[NumLines++] = PinCount[NumLines] + // Hilfskontakte
+ "\t" + PinNames[NumLines] +
+ "\t" + SymName[NumLines];
+ }
+ }
+ if (!NrOfPins && !Xref && SymDisplay == 3) { // Symbole ohne Kontakte
+ Lines[NumLines++] = PinCount[NumLines] +
+ "\t" + PinNames[NumLines] +
+ "\t" + SymName[NumLines];
+ }
+ if (SymDisplay == 4) { // Symbole ohne Kontakte
+ Lines[NumLines++] = PinCount[NumLines] +
+ "\t" + PinNames[NumLines] +
+ "\t" + SymName[NumLines];
+ }
+ Lines[NumLines] = "";
+ }
+ }
+ return;
+}
+
+
+// Übertrage gewähltes Symbol in Symbolliste
+void SymEntry(void) { // Selected liefert aus ListView gewählten Symbol-Index
+ numeric string Rang;
+
+ RangDev++;
+ sprintf(Rang, "%d", RangDev);
+
+ DevRang[NumSyms] = Rang;
+ DevPinCount[NumSyms] = PinCount[Selected];
+ DevPinNames[NumSyms] = PinNames[Selected];
+ DevSymName[NumSyms] = SymName[Selected];
+
+ DevLines[NumSyms++] = Rang +
+ "\t" + PinCount[Selected] +
+ "\t" + PinNames[Selected] +
+ "\t" + SymName[Selected];
+
+ NumAllPins += strtol(PinCount[Selected]);
+
+ DevPinNamesAll += " " + PinNames[Selected];
+ DevPinNamesAll = StripWhiteSpace(DevPinNamesAll);
+ return;
+}
+
+void ClearDevList(void) {
+ int i;
+ for (i = 0; i <= NumSyms; i++) {
+ DevLines[i] = "";
+ }
+ NumSyms = 0;
+ RangDev = 0;
+ NumAllPins = 0;
+ MakeDevCmd = "";
+ DevPinNamesAll = "";
+ return;
+}
+
+// int ValidSymName(string symname) {
+// if (symname == "") return 0;
+// library(L) { // Symbol-Name schon vorhanden?
+// L.symbols(S) {
+// if (strupr(symname) == S.name) return 0;
+// }
+// }
+// return 1;
+// }
+
+string GetPinName(int PinIndex) { // Pin-Namen aus Listeneintrag extr., PinIndex 0...
+ string Pnames[];
+ strsplit(Pnames, DevPinNamesAll, ' ');
+ return Pnames[PinIndex];
+}
+
+int CorrectContactNames(void) { // Anzeige der Kontaktnamen aktualisieren
+ int i, j, n;
+ string pn = ""; // temp. Pin-Namen-String für 1 Symbol
+ string a[];
+
+ DevPinNamesAll = StripWhiteSpace(DevPinNamesAll);
+
+ // Prüfe Zahl der Pins
+ if (strsplit(a, DevPinNamesAll, ' ') != NumAllPins) return 0;
+
+ // Prüfe Doppelnamen
+ if (NumAllPins > 1) {
+ while (i < NumAllPins) {
+ j = i + 1;
+ while (j < NumAllPins) {
+ if (a[i] == a[j++]) return 0;
+ }
+ i++;
+ }
+ }
+ for (j = 0; j < NumSyms; j++) {
+ pn = "";
+ for (i = 0; i < strtol(DevPinCount[j]); i++) {
+ pn += " " + GetPinName(n++);
+ }
+ pn = StripWhiteSpace(pn);
+ DevPinNames[j] = pn;
+ DevLines[j] = DevRang[j] +
+ "\t" + DevPinCount[j] +
+ "\t" + pn +
+ "\t" + DevSymName[j];
+ }
+ return 1;
+}
+
+int OkToClose(void) {
+ if (!CorrectContactNames()) {
+ dlgMessageBox(ErrorCorrectNames);
+ return 0;
+ }
+ library(L) { // Device-Name schon vorhanden?
+ L.devicesets(D) {
+ if (strupr(NewDeviceName) == D.name) {
+ dlgMessageBox("Bitte wählen Sie einen anderen Namen\n (Device schon vorhanden)!\n");
+ return 0;
+ }
+ }
+ L.packages(P) {
+ if (strupr(NewDeviceName) == P.name) {
+ dlgMessageBox("Bitte wählen Sie einen anderen Namen\n (Package schon vorhanden)!\n");
+ return 0;
+ }
+ }
+ }
+ if (NewDeviceName == "" || !NumSyms) {
+ dlgMessageBox("Das Bauteil kann nur erzeugt werden, wenn Sie einen Namen eingeben\n und mindestens ein Symbol in der Device-Liste steht!");
+ return 0;
+ }
+ else return 1;
+}
+
+string GetPinNameFromLbr(string Sname, int i) { // Pinname, i-ter Pin
+ string pn = "";
+ int n;
+ library(L) {
+ L.symbols(S) {
+ if (S.name == Sname) {
+ n = 0;
+ S.pins(P) {
+ if (i == n++) {
+ pn = P.name;
+ return pn;
+ }
+ }
+ }
+ }
+ }
+ return "";
+}
+
+void GenerateDevice(void) {
+ string s;
+ int i, j, k;
+ int XOffset = 0; // virtuelle Y-Nulllinie: rechts daneben wird nächster Kontakt platziert
+ int SymOffset;
+ int CoordY;
+ // Erzeuge Device-Befehle
+ MakeDevCmd += "edit " + NewDeviceName + ".dev;\n";
+ MakeDevCmd += "value on;\n";
+ MakeDevCmd += "grid mil 100 on;\n";
+ MakeDevCmd += "prefix '" + DevicePrefix + "';\n";
+ MakeDevCmd += "description '" + DeviceDescription + "';\n";
+ MakeDevCmd += "package '" + NewDeviceName + "';\n";
+ sprintf(s, "add '%s' R0 must 0 (%d %d);\n", DevSymName[0], SpulenOffset, XrefOffset);
+ MakeDevCmd += s;
+ for (i = 1; i < NumSyms; i++) {
+ if (strtol(DevPinCount[i]) >= 9) SymOffset = 600;
+ if (strtol(DevPinCount[i]) < 9) SymOffset = 400;
+ if (strtol(DevPinCount[i]) < 7) SymOffset = 300;
+ if (strtol(DevPinCount[i]) < 5) SymOffset = 200;
+ if (strtol(DevPinCount[i]) < 3) SymOffset = 100; // Abstand zwischen Einzelkontaktsymbolen, mil
+
+ if (strtol(DevPinCount[i])) { // Symbol mit Pins, rechts der Reihe nach platzieren
+ sprintf(s, "add '%s' R0 next 0 (%d %d);\n", DevSymName[i], XOffset + SymOffset, XrefOffset);
+ }
+ else { // Symbol ohne Pins, unter Spule aufeinander platzieren
+ sprintf(s, "add '%s' R0 can 0 (%d %d);\n", DevSymName[i], SpulenOffset, ZeicheSymbolOffset + SymOffset);
+ }
+
+ MakeDevCmd += s;
+ XOffset += 2 * SymOffset;
+ }
+
+ // Erzeuge Connect-Befehle
+ i = 0;
+ while (DevSymName[i]) {
+ j = 0;
+ while (GetPinNameFromLbr(DevSymName[i], j) != "") {
+ if (GetPinName(k)) {
+ sprintf(s, "connect 'G$%d.%s' '%s';\n", i+1 , GetPinNameFromLbr(DevSymName[i], j++), GetPinName(k++));
+ MakeDevCmd += s;
+ }
+ }
+ i++;
+ }
+
+//MakeDevCmd += "value on;\n";
+ MakeDevCmd += "grid last;\n";
+
+ // Erzeuge Package-Befehle
+ MakePackCmd = "edit " + NewDeviceName + ".pac;\n";
+ MakePackCmd += "grid mil 100 on;\n";
+ for (i = 0; i < NumAllPins; i++) {
+ CoordY = i * PadOffset;
+ sprintf(s, "pad '%s' (%d 0);\n", GetPinName(i), CoordY);
+ MakePackCmd += s;
+ }
+
+ MakePackCmd += "grid last;\n";
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ // Ausgabe zuerst in Script-Datei, dann SCRIPT-Befehl ausführen
+ s = MakePackCmd + MakeDevCmd;
+ output(f, "wtD") printf("%s", s); // temporäre Script-Datei erzeugen
+ exit("SCRIPT '"+ f +"';");
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ }
+
+void EditSymParams(void) {
+ string a[];
+
+ dlgDialog("Kontaktnamen editieren") {
+ dlgHBoxLayout {
+ dlgLabel("Kontaktnamen");
+ dlgStringEdit(DevPinNamesAll);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("&Hilfe") dlgMessageBox(HelpTextKontaktnamen);
+ dlgPushButton("-Abbrechen") dlgReject();
+ dlgPushButton("+OK") if (CorrectContactNames()) dlgAccept();
+ else dlgMessageBox(ErrorCorrectNames);
+ }
+ };
+}
+
+//***************************************************************
+SymDisplay = 0;
+MakeSymSelectList();
+
+dlgDialog("Erzeuge Device") {
+ dlgLabel("Symbolauswahlliste");
+ dlgListView("Pins\tPin-Namen\tSymbol-Name", Lines, Selected) SymEntry();
+ dlgLabel("Device-Liste");
+ dlgListView("Rang\tPins\tKontakt-Namen\tSymbol-Name", DevLines, SelectedDev);
+ dlgHBoxLayout {
+ dlgGroup("Symbolauswahl-Filter") {
+ dlgRadioButton("Spulen", SymDisplay) MakeSymSelectList();
+ dlgRadioButton("Hauptkontakte mit Kontaktspiegel", SymDisplay) MakeSymSelectList();
+ dlgRadioButton("Hilfskontakte mit Kontaktspiegel", SymDisplay) MakeSymSelectList();
+ dlgRadioButton("Symbole ohne Kontakte", SymDisplay) MakeSymSelectList();
+ dlgRadioButton("Alle Symbole", SymDisplay) MakeSymSelectList();
+ }
+ dlgGroup("Device-Parameter") {
+ dlgHBoxLayout {
+ dlgLabel("&Device-Name");
+ dlgStringEdit(NewDeviceName);
+ }
+ dlgHBoxLayout {
+ dlgLabel("&Bauteil-Prefix ");
+ dlgStringEdit(DevicePrefix);
+ }
+ dlgHBoxLayout {
+ dlgLabel("&Beschreibung");
+ dlgStringEdit(DeviceDescription);
+ }
+ }
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("&Hilfe") ShowHelp();
+ dlgPushButton("&Device-Liste löschen") ClearDevList();
+ dlgPushButton("&Kontaktnamen ändern") EditSymParams();
+ dlgPushButton("-Abbrechen") dlgReject();
+ dlgPushButton("+OK") if (OkToClose()) GenerateDevice();
+ }
+ };
diff --git a/trunk/ulp/e-brueckenverwaltung.ulp b/trunk/ulp/e-brueckenverwaltung.ulp
new file mode 100644
index 00000000..d15198ad
--- /dev/null
+++ b/trunk/ulp/e-brueckenverwaltung.ulp
@@ -0,0 +1,934 @@
+#usage "Brückenklemmen-Verwaltung: Brücken eintragen und ändern\n
"
+"Brückenklemmen sind Bauteile mit Einzelklemmen, die jeweils zwei Kontakte "
+"mit Anschlussmöglichkeit für Drähte haben. Zusätzlich können die Klemmen "
+"untereinander mit gesteckten Brückenkämmen o.ä. verbunden werden. Mit diesem "
+"User-Language-Programm (ULP) definieren Sie auf bequeme Weise, welche Klemmen "
+"innerhalb eines Klemmenblocks gebrückt werden sollen. Die Brückendefinitionen "
+"werden als Liste in einer Datei (schaltungsname.brk) ausgegeben. Außerdem "
+"wird eine Log-Datei (schaltungsname.log) angelegt, aus der mögliche Probleme "
+"hervorgehen. Die Log-Datei wird gelöscht, nachem die EAGLE-Sitzung beendet ist.
"
+"Die erzeugte Liste (schaltungsname.brk) kann in einem Tabellenkalkulationsprogramm "
+"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die "
+"Schaltungszeichnung importiert werden.
"
+"Author: support@cadsoft.de"
+
+// Verwaltung von Brückenklemmen (nur für Devices KLEMME*BRUECKE in Bibliothek e-klemmen.lbr)
+// rudi hofer
+// Gate-Namen der Brücken-Devices müssen alphabetisch so geordnet sein, dass ihre Pins
+// der Reihe nach 1.x, 2.x etc. sind
+
+// todo
+// Anzeigen, welcher Klemmenblock gerade bearbeitet wird
+
+string Version = "Version 1.02";
+
+// History
+// 1.01 -- 2009-10-01 nicht benötigte "\t\t" in Kopfzeilen von dlgDialog() entfernt
+// 1.02 -- 2013-10-02 sheet aus der Instance, nicht über SCH.sheets()
+// die Sheet-Nummer entspr. jetzt der Klemme mit Space getrennt,
+// und mit TAB von den Klemmen selbst.
+
+#require 6.0500
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Vom Benutzer zu ändern:
+// Wenn verdrahteten Verbindungen keine Verweise bekommen sollen, setzen Sie den
+// Wert für ExcludeDrahtverbindungen in der folgenden Zeile auf 1;
+int ExcludeDrahtverbindungen = 0;
+/////////////////////////////////////////////////////////////////////////////////
+
+string s, cmd, f, LogCmd, DoCmd, ListCmd;
+string PartDatabase[], CurrentPart;
+numeric string ChangeString, SheetsUsedInEdit[];
+int maxklemmen, LogOn, ErrOn, CurrentPartIndex;
+
+string scrfile, listfile, errorfile, pinfile, vbdfile, klpfile, kapfile, brpfile, pfad;
+numeric string sh, PartPin, SigName, col, row, PartName, PinName;
+numeric string pindatabase[], b[];
+string PartPinSep = " ";
+int YRef[];
+int distY, netnr, n, i;
+// Debug
+string DebugString;
+// Variablen für main
+int SelAll = -1, SelConnected = -1, Sort = 0, SortAll = 0, NrLinesListAll;
+numeric string ListAll[], ListAllSheet[], ListSel[], ListUndo[]; //, ListUndoOben[];
+string h[];
+// Header-Variablen -------------------------------------------------------------------------------------------
+string head [], SelParam[], ChangeParam[];
+int NrHeader; // Zahl der Rubriken
+// head [] enthält ListHeader-Einträge:
+// head[Draehte].. v
+enum {Draehte, Bruecken};
+numeric string ListHeader = "Drähte \tBrücken";
+
+enum {Name, Anz, Verwendet, Verdrahtet};
+numeric string ListHeaderMain = "Name\tAnz.\tVerwendet\tVerdrahtet";
+// Ende Header-Variablen --------------------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+string HelpText =
+
+
+"Brückenklemmen-Verwaltung: Brücken eintragen und ändern
"
+
+"Brückenklemmen sind Bauteile mit Einzelklemmen, die jeweils zwei Kontakte "
+"mit Anschlussmöglichkeit für Drähte haben. Zusätzlich können die Klemmen "
+"untereinander mit gesteckten Brückenkämmen o.ä. verbunden werden. Mit diesem "
+"User-Language-Programm (ULP) definieren Sie auf bequeme Weise, welche Klemmen "
+"innerhalb eines Klemmenblocks gebrückt werden sollen. Die Brückendefinitionen "
+"werden als Liste in einer Datei (schaltungsname.brk) ausgegeben. Außerdem "
+"wird eine Log-Datei (schaltungsname.log) angelegt, aus der mögliche Probleme "
+"hervorgehen. Die Log-Datei wird gelöscht, nachem die EAGLE-Sitzung beendet ist. "
+"Die erzeugte Liste (schaltungsname.brk) kann in einem Tabellenkalkulationsprogramm "
+"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die "
+"Schaltungszeichnung importiert werden.
"
+
+"Klemmenbibliothek
"
+
+"Dieses Programm berücksichtigt nur Brückenklemmen, wie sie in der "
+"Bibliothek e-klemmen.lbr unter den Device-Namen KLEMME*BRUECKE definiert sind. "
+"In der Schaltung muss der Bauteilname mit X beginnen, und in der Bibliothek "
+"muss der Namensbestandteil BRUECKE vorhanden sein. "
+"In der Bibliothek e-klemmen.lbr befinden sich vordefinierte Brückenklemmen. "
+"Bitte lesen Sie die Bibliotheksbeschreibung (z.B. im Control-Panel), wenn Sie "
+"eigene Brückenklemmen definieren wollen.
"
+
+"Prinzip
"
+
+"Klemmen werden behandelt, wie jedes andere Bauteil auch: Kontakte, die mit "
+"anderen verbunden sind, erscheinen im Klemmenplan. Eine Verbindung entsteht, "
+"wenn die Kontakte über eine Netzlinie verbunden sind oder wenn an den Kontakten "
+"jeweils ein Netz mit gleichem Namen hängt. Letzteres ist insbesondere dann "
+"der Fall, wenn Kontakte auf unterschiedlichen Schaltplanseiten verbunden sind.
"
+
+"Brückenklemmen bieten darüber hinaus eine weitere Möglichkeit, Verbindungen "
+"innerhalb desselben Klemmenblocks zu definieren. Man bringt einen "
+"Verweis (Referenz) im Brückenklemmen-Symbol an, der auf die vorherige bzw. nächste "
+"Klemme zeigt, mit der die Klemme verbunden werden soll. Damit vermeidet man ein "
+"Wirrwarr von gezeichneten Brücken bei größeren Plänen. Die Verweise verwenden "
+"Attribute, die in der Bibliothek festgelegt sind. Der Benutzer hat damit aber "
+"nichts zu tun, solange er für die Definition der Brücken dieses ULP verwendet.
"
+
+"Was steht im Klemmenplan und im Brückenplan?
"
+
+"Der Klemmenplan stellt alle Draht- und Kabelverbindungen in einer Liste dar. "
+"Der Brückenplan enthält die (üblicherweise mit Brückenkämmen ausgeführten) "
+"Verbindungen innerhalb eines Klemmenblocks, die mit Hilfe dieses Programms "
+"erstellt wurden.
"
+
+"Werden Kontakte eines Brückenklemmenblocks über ein Netz verbunden, erscheint diese "
+"Verbindung im Klemmenplan als Drahtverbindung. Sie sollten das dann tun, wenn "
+"Sie darauf hinweisen wollen, dass hier tatsächlich ein Draht von einer Klemme "
+"zur anderen verlegt werden soll.
"
+
+"Werden Kontakte eines Brückenklemmenblocks über Klemmen-Referenzen (mit diesem "
+"Programm) verbunden, erscheint diese Verbindung im Brückenplan (ebenso wie "
+"Verbindungen zwischen unterschiedlichen Klemmenblöcken, etwa eine Klemme "
+"von X1 mit einer von X2).
"
+
+"Falls Kontakte auf beide Arten verbunden sind (was keinen Sinn macht), "
+"erscheinen sie im Klemmenplan und im Brückenplan.
"
+
+"Wie werden Brücken im Stromlaufplan dargestellt?
"
+
+"Im Brückenklemmen-Symbol weisen (maximal) zwei Zahlen auf die nächsten Klemmen hin, "
+"mit denen es verbunden ist. Da Referenzverbindungen nicht über die Draht-Anschlüsse "
+"realisiert werden, erscheint als Referenz nicht der jeweilige Kontaktname "
+"(1.1, 1.2 etc.), sondern die Klemmennummer (1, 2, 3 etc.). Klemme 5 etwa "
+"ist die Klemme mit den Kontakten 5.1 und 5.2.
"
+
+"Beispiel: In einem Block mit sechs Einzelklemmen, sollen die Klemmen 1, 3 und 5 "
+"miteinander verbunden sein: Klemme 1 verweist auf 3, Klemme 3 verweist auf 1 und 5, "
+"und Klemme 5 verweist auf Klemme 3.
"
+
+"Bedienung
"
+
+"In jeder Programmsitzung können Sie nur die Brücken eines Klemmenblocks (also etwa X1) "
+"bearbeiten.
"
+
+"Typischer Ablauf einer Programmsitzung:
"
+
+"Log-Datei: Dieser Button öffnet ein Textfenster, in dem Sie die vorhandenen "
+"Draht- und Referenz-Brücken sowie Warnungen zu eventuellen Fehlern finden.
"
+
+"Doppelklick auf obere Liste: Wählen Sie den zu bearbeitenden Klemmenblock. "
+"Dargestellt sind die Anzahl und die Nummern der in der Schaltung platzierten "
+"Klemmen sowie die Klemmen, die mit Drähten (Netzen) verbunden sind. "
+"Mit dem Doppelklick wird dieser Klemmenblock in die untere Liste zur Bearbeitung "
+"übertragen.
"
+
+"Untere Liste: Links sind Drahtverbindungen dargestellt, sie können nicht "
+"verändert werden (nur in der Schaltung). Rechts sind die Einzelbrücken "
+"in jeweils einer Zeile dargestellt.
"
+
+"Doppelklick auf untere Liste: Die verbundenen Klemmen einer Einzelbrücke "
+"wandern in das Editier-Fenster (Verbinden). Dort können Sie eintragen, "
+"welche Klemmen verbunden werden sollen (durch Leerzeichen getrennt). "
+"Die Eingabetaste oder ein Klick auf Anwenden ändert die selektierte "
+"Zeile entsprechend. Falls Sie Klemmen gewählt haben, die nicht in der "
+"Schaltung platziert sind, erscheint eine Fehlermeldung.
"
+
+"Speichern: Dieser Button beendet das Programm und führt die Änderungen "
+"an der zuletzt bearbeiteten Klemme durch. Der aktuelle Brückenplan "
+"wird als schaltungsname.brk abgespeichert, zusätzlich die Log-Datei "
+"(*.log) und eine Script-Datei (*.scr), aus der die EAGLE-Befehle zur Änderung "
+"der Referenzen hervorgehen. Um den endgültigen Brückenplan für ihre "
+"Projektunterlagen zu erstellen, sollten Sie das Programm starten und "
+"ohne eine Änderung durchzuführen den Button Speichern betätigen, dann "
+"ist die Liste richtig sortiert.
"
+
+"Undo: Dieser Button bringt nach einer Änderung den letzten Zustand in die "
+"untere Liste (nur eine Undo-Stufe).
"
+
+"Unbenutzte: Dieser Button bringt alle Klemmen in das Editier-Feld, die "
+"als Eingabe möglich sind, da sie gegenwärtig keiner anderen Brücke angehören. "
+"Am besten, sie betätigen diesen Button und löschen dann die Klemmen heraus, "
+"die nicht mit der zu erstellenden Brücke verbunden werden sollen.
"
+
+"Löschen: Löscht eine komplette Brückenzeile.
"
+
+"Neu: Erzeugt eine neue Brückenzeile, in die Sie den Inhalt des Editier-Fensters "
+"übertragen können.
"
+
+"Abbrechen: Programm ohne Änderungen verlassen."
+;
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SetFileNames(void) { // in Schematic-Kontext aufrufen
+
+ if (!schematic) {
+ // dlgMessageBox("Dieses Programm muss vom Schaltplan-Editor aus aufgerufen werden");
+ exit(1);
+ }
+ schematic(SCH) {
+ scrfile = filesetext(SCH.name, ".scr");
+ errorfile = filesetext(SCH.name, ".log");
+ listfile = filesetext(SCH.name, ".brk");
+ }
+}
+
+string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Whitespaces im Inneren werden 1 Whitespace
+ int i, n;
+ string t;
+
+ while (s && isspace(s[0]))
+ s = strsub(s, 1);
+ while (s && isspace(s[strlen(s) - 1]))
+ s = strsub(s, 0, strlen(s) - 1);
+// Doppel-Blanks
+ for (i = 0; i < strlen(s); i++) {
+ if (!isspace(s[i])) t[n++] = s[i];
+ else {
+ if ((strlen(s) > i+1) && isspace(s[i+1]));
+ else t[n++] = s[i];
+ };
+ }
+ s = t;
+ return s;
+}
+
+string SortBlankSeparatedString(string s) {
+ int nb;
+ numeric string b[];
+ s = StripWhiteSpace(s);
+ nb = strsplit(b, s, ' ');
+ sort(nb, b);
+ s = strjoin(b, ' ');
+ return s;
+}
+
+// Lösche Mehrfacheinträge aus blanksepariertem String und sortiere
+string DelMultiples(string st) {
+ string s, h[], ht[];
+ int i, n, np;
+ st = SortBlankSeparatedString(st);
+ np = strsplit(h, st, ' ');
+ for (i = 0; i < np; i++) {
+ ht[n] = h[i];
+ if (ht[n] == h[i+1]) {
+ i++;
+ }
+ n++;
+ }
+ s = strjoin(ht, ' ');
+ return StripWhiteSpace(s);
+}
+
+// Liefert einen kommaseparierten String mit allen verdrahteten Brücken eines Klemmenblocks
+// Für Log werden die Brücken nach Netzen getrennt ausgegeben
+string GetConnectedOnePart(string pname) {
+ int klnr, nrnetpins;
+ string s, t, connects, allconnects;
+ schematic(SCH) {
+ SCH.nets(N) {
+ nrnetpins = 0;
+ N.pinrefs(P) {
+ if (P.part.name == pname && P.pin.contact) {
+ nrnetpins++;
+ if (nrnetpins == 2) {
+ sprintf(s, "%s\tNetz: %s\tKlemmen: ", P.part.name, N.name); LogCmd += s;
+ break;
+ }
+ }
+ }
+ t = ""; connects = ""; nrnetpins = 0;
+ N.pinrefs(P) {
+ s = "";
+ if (P.part.name == pname && P.pin.contact) {
+ if(strtol(P.pin.contact.pad.name)) klnr = strtol(P.pin.contact.pad.name);
+ else sprintf(s, "\n%s: Fehler in Bibliothek! Pad-Name muss mit Ziffer beginnen!\n", P.pin.contact.pad.name); LogCmd += s;
+ sprintf(s, "%d ", klnr); connects += s; t += s; // nur wegen \n
+ nrnetpins++;
+ }
+ }
+ if (nrnetpins == 1) connects = ""; // nur ein Pin an Netz
+ LogCmd += SortBlankSeparatedString(connects);
+ if (t && nrnetpins > 1) LogCmd += "\n";
+ allconnects += " " + connects;
+ }
+ }
+ return SortBlankSeparatedString(allconnects);
+}
+
+void PackListsel (int ix, int pos, string s) {
+ int np;
+ if (ix < 0 || pos < 0) return;
+ numeric string h[];
+ strsplit(h, ListSel[ix], '\t');
+ h[pos] = s;
+ ListSel[ix] = strjoin(h, '\t');
+}
+
+string UnpackListsel (int ix, int pos) {
+ if (ix < 0) return "";
+ numeric string h[];
+ strsplit(h, ListSel[ix], '\t');
+ return h[pos];
+}
+
+void PackListall (int ix, int pos, string s) {
+ int np;
+ if (ix < 0 || pos < 0) return;
+ numeric string h[];
+ strsplit(h, ListAll[ix], '\t');
+ h[pos] = s;
+ ListAll[ix] = strjoin(h, '\t');
+}
+
+string UnpackListall (int ix, int pos) {
+ if (ix < 0) return "";
+ numeric string h[];
+ strsplit(h, ListAll[ix], '\t');
+ return h[pos];
+}
+
+int IsInBlankStr (string item, string st) { // ist item in blanksep. String st vorhanden?
+ int i, np;
+ numeric string h[];
+ st = StripWhiteSpace(st);
+ np = strsplit(h, st, ' ');
+ for (i = 0; i < np; i++) {
+ if (item == h[i]) return 1;
+ }
+ return 0;
+}
+
+// Löscht Edit-Liste
+void DelListsel(void) {
+ for (i = 0; i < maxklemmen; i++) {
+ ListSel[i] = "";
+ }
+}
+
+// Ref-Verbindungen für Editierliste erstellen: blank/tab separated string (ordered)
+// 1 2 5 \n 4 6 Zeilen mit \t getrennt
+string GetConnectedRefwise(string pname){
+ numeric string s, klemmenused[], ku, c1, c2, bridges[], h[], lastline[], prevline[];
+ int i, j, k, u, v, w, np, np1, np2, bx, found;
+ schematic(SCH) {
+ SCH.sheets(SH) {
+ SH.parts(P) {
+ if (P.name == pname) {
+ if (LogOn) LogCmd += P.name + " ";
+ np = strsplit(klemmenused, StripWhiteSpace(lookup(PartDatabase, P.name, "Verwendet", '\t')) ,' ');
+ i = 0; bx = 0; found = 0;// Brückenindex, trennt Einzelpotentiale
+ for (i = 0; i < np; i++) {
+ ku = klemmenused[i];
+ c1 = P.attribute[klemmenused[i]+"1"];
+ c2 = P.attribute[klemmenused[i]+"2"];
+ if (P.attribute[klemmenused[i]+"1"] || P.attribute[klemmenused[i]+"2"]) {
+ sprintf(s, "%d: %s %s %s\n", bx, ku, c1, c2);
+ sprintf(s, "%s %s %s", ku, c1, c2);
+ if (StripWhiteSpace(s)) bridges[bx++] = StripWhiteSpace(s);
+ }
+ }
+ // bx Zahl der Klemmen mit Ref (höchster Index ist bx-1); max drei Klemmen pro Eintrag
+ for (j = bx-1; j > 0; j--) { // Fasse Potentiale in bridges[] zusammen
+ np1 = strsplit(lastline, bridges[j], ' '); // bis zu drei Klemmen in lastline
+ v = j - 1;
+ while (v >= 0) { // vorherige Zeilen
+ strsplit(prevline, bridges[v], ' ');
+ w = 0;
+ while(prevline[w]) {
+ u = 0;
+ while (lastline[u]) {
+ if (lastline[u] == prevline[w]) {
+ bridges[v] += " " + StripWhiteSpace(bridges[j]);
+ bridges[j] = "";
+ found = 1;
+ break;
+ }
+ u++;
+ }
+ if (found) break;
+ w++;
+ }
+ v--;
+ }
+ } // Ende Zusammenfassen der Potentiale (Mehrfacheinträge hier noch möglich)
+ i = 0; n = 0;
+ while (h[i]) h[i++] = "";
+ for (i = 0; i < maxklemmen; i++) {
+ if (StripWhiteSpace(bridges[i])){
+ h[n] = DelMultiples(bridges[i]);
+ n++;
+ }
+ }
+ sort(n, h);
+ i = 0; s = "";
+ while (StripWhiteSpace(h[i])) {
+ h[i] = DelMultiples(h[i]);
+ s += h[i] + "\n";
+ if (LogOn) LogCmd += " : " + h[i];
+ i++;
+ }
+ if (LogOn) LogCmd += "\n";
+ }
+ }
+ }
+ }
+ return s;
+}
+
+// Editier-Liste (Drähte) für einen Klemmenblock erstellen: blank/tab separated string (ordered)
+// 1 2 5 \n 4 6 Zeilen mit \t getrennt
+string GetConnectedNetwise(string pname){
+ int klnr, nrnetpins;
+ string s, t, connects, allconnects;
+ schematic(SCH) {
+ SCH.nets(N) {
+ t = ""; connects = ""; nrnetpins = 0;
+ N.pinrefs(P) {
+ s = "";
+ if (P.part.name == pname && P.pin.contact) {
+ klnr = strtol(P.pin.contact.pad.name); // trennt .x ab von x.x
+ sprintf(s, "%d ", klnr); connects += s; t += s; // t nur wegen \n erforderlich
+ nrnetpins++;
+ }
+ }
+ connects = SortBlankSeparatedString(connects);
+ if (nrnetpins == 1) connects = ""; // nur ein Pin an Netz
+ if (t && nrnetpins > 1) {
+ allconnects += connects + "\n";
+ }
+ }
+ }
+ return allconnects;
+}
+
+// Ermittelt Wired-Brücken an und schreibt Log nach Startvorgang
+// Part \t Klemmen
+// wobei Klemmen blanksepariert sind (alle fest verdrahteten Klemmen)
+// z. B.: X1 1 3 4 5 9
+void GetConnectedAllParts(void) {
+ int i, np;
+ string h[];
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+ LogCmd += "Mit Netzen realisierte Brücken: nicht mit diesem ULP zu verändern!\n";
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+ while (ListAll[i]) {
+ np = strsplit(h, ListAll[i], '\t');
+// Wired Connections
+ h[Verdrahtet] = DelMultiples((GetConnectedOnePart(h[Name])));
+ ListAll[i] = strjoin(h, '\t');
+ i++;
+ }
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+ LogCmd += "Mit Referenzen realisierte Brücken: mit diesem ULP zu verändern!\n";
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+// Ref Connections
+ i = 0;
+ while (ListAll[i]) {
+ np = strsplit(h, ListAll[i], '\t');
+ LogOn = 1;
+ GetConnectedRefwise(h[Name]);
+ LogOn = 0;
+ i++;
+ }
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+}
+
+
+int CheckOKBridgeLine(string st) { // lässt nur in schematic vorhandene Klemmen zu
+ int i, np;
+ string s, h[];
+ s = StripWhiteSpace(st);
+ if (st == "") return 1;
+ char c;
+ for (i = 0; i < strlen(s); i++) {
+ c = s[i];
+ if (isdigit(c) || c == ' ') {
+ }
+ else return 0;
+ }
+ np = strsplit(h, st, ' ');
+ if (np == 1) return 0;
+ for (i = 0; i < np; i++) {
+ if (!IsInBlankStr(h[i], UnpackListall(CurrentPartIndex, Verwendet))) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void MakeEditListOnePart(int Sel) {
+ int i, ErrPrinted;
+ string wirelines[], reflines[], h[], x[];
+ if (Sel < 0) return;
+ strsplit(h, ListAll[Sel], '\t');
+ CurrentPartIndex = Sel;
+ CurrentPart = h[Name];
+ DelListsel();
+ strsplit(wirelines, GetConnectedNetwise(h[Name]), '\n'); // alle Br. als Einzelzeilen
+ strsplit(reflines, GetConnectedRefwise(h[Name]), '\n'); // alle Br. als Einzelzeilen
+ while(wirelines[i] || reflines[i]) {
+ ListSel[i] = DelMultiples(wirelines[i]) + "\t" + DelMultiples(reflines[i]);
+ if (!CheckOKBridgeLine(reflines[i])) {
+ if (ErrOn && !ErrPrinted) {
+ dlgMessageBox( "Unzulässige Brückenbezeichnung, siehe Log-Liste!
"
+ "Bitte tragen Sie in die Brückenzeilen nur erlaubte Bezeichnungen ein "
+ "und speichern Sie das Ergebnis ab!"
+ );
+ ErrPrinted = 1;
+ }
+ if (!ErrOn)
+ if (strsplit(x, reflines[i], ' ') == 1)
+ LogCmd += UnpackListall(Sel, Name) + ": " + reflines[i] +
+ "\tNur ein Klemmenverweis (min. 2 erforderlich)!\n";
+ else
+ LogCmd += UnpackListall(Sel, Name) + ": " + reflines[i] +
+ "\tNicht alle Klemmen in Schaltung vorhanden!\n";
+ }
+ i++;
+ }
+ return;
+}
+
+// void MakeEditListPerName(string pname) {
+// int i;
+// pname = StripWhiteSpace(pname);
+// while (UnpackListall(i, Name)) {
+// if (pname == UnpackListall(i, Name)) {
+// MakeEditListOnePart(i);
+// SelAll = i;
+// return;
+// }
+// i++;
+// }
+// dlgMessageBox("Kein Klemmenblock mit diesem Namen vorhanden!
");
+// return;
+// }
+
+// Sammle Brückenklemmen (Part-Name: X...; Device-Name: ..BRUECKE..)
+// Fülle obere Liste und lege identische Datenbank mit Header an (PartDatabase[])
+void CollectX(void) {
+ numeric string s, sheetgate;
+ int cntpart;
+ PartDatabase[0] = ListHeaderMain + "\tSeite(n)"; // 2013 die Seiten sind pro gate eingetragen
+ schematic(SCH) {
+ SCH.parts(P) { // 2013-10-02 nicht durch die sheets
+ if (strchr(P.name, 'X') == 0) {
+ if (strstr(P.device.name, "BRUECKE") >= 0) {
+ int cntmaxklem = 0;
+ string listallsheet = "";
+ P.instances(I) if (I.sheet) cntmaxklem++;
+ maxklemmen = max(maxklemmen, cntmaxklem);
+ sprintf(ListAll[cntpart], "%s\t%d\t", P.name, cntmaxklem);
+
+ P.instances(I) {
+ if (I.sheet) {
+ ListAll[cntpart] += I.gate.name + " ";;
+ sprintf(sheetgate, "%d ", I.sheet); // 2013-10-02 sheet aus der Instance
+ listallsheet += sheetgate;
+ }
+ }
+ ListAllSheet[cntpart] = listallsheet;
+ PartDatabase[cntpart+1] = ListAll[cntpart];// + "\t" + listallsheet; // die sheets zu den Gates
+ LogCmd += PartDatabase[cntpart+1] + "\n";
+ cntpart++;
+ }
+ }
+ }
+ }
+}
+
+void PushUndo(void) {
+ int i;
+ while (ListUndo[i]) {
+ ListUndo[i] = "";
+ i++;
+ }
+ i = 0;
+ while (ListSel[i]) {
+ ListUndo[i] = ListSel[i];
+ i++;
+ }
+}
+
+void PullUndo(void) {
+ int i;
+ while (ListSel[i]) {
+ ListSel[i] = "";
+ i++;
+ }
+ i = 0;
+ while (ListUndo[i]) {
+ ListSel[i] = ListUndo[i];
+ i++;
+ }
+}
+
+void ShowLog(void) {
+ dlgDialog("Brückendaten aus der Schaltung") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout{
+ dlgTextEdit(LogCmd);
+ }
+ dlgHBoxLayout {
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("&Hilfe") dlgMessageBox( "Die Liste gibt Hinweise auf mögliche Probleme beim Einlesen\n"
+ "der Brückenverbindungen."
+ );
+ dlgPushButton("+OK") dlgAccept();
+ }
+ };
+}
+
+// liefert alle a, die nicht in b sind; a,b und return-Wert sind blanksep. Strings
+string AllAnotinB(string a, string b) {
+ int i, na;
+ numeric string ha[];
+ a = StripWhiteSpace(a);
+ b = StripWhiteSpace(b);
+ na = strsplit(ha, a, ' ');
+ a = "";
+ for (i = 0; i < na; i++) {
+ if (!IsInBlankStr(ha[i], b)) {
+ a += ha[i] + " ";
+ }
+ }
+ return StripWhiteSpace(a);
+}
+
+string GetUnused(int Sel) { // liefert unbenutzte Klemmen als blanksep. String
+ int i, n;
+ string h[], s, usedB, usedD, t; // von Brücken benutzt; von Drähten benutzt
+ if (Sel < 0 || CurrentPartIndex < 0) return "";
+ PushUndo();
+ s = UnpackListall(CurrentPartIndex, Verwendet);
+ while (ListSel[i]) {
+ if (Sel != i) usedB += UnpackListsel(i, Bruecken) + " ";
+ usedD += UnpackListsel(i, Draehte) + " ";
+ i++;
+ }
+ s = AllAnotinB(s, usedB);
+ if (ExcludeDrahtverbindungen) s += " " + AllAnotinB(s, usedD);
+ return StripWhiteSpace(s);
+}
+
+int CheckOKChangeString(string st) { // lässt nur solche zu, die noch nicht in anderer Br. verwendet
+ int i, np;
+ string s, h[];
+ s = StripWhiteSpace(st);
+ char c;
+ for (i = 0; i < strlen(s); i++) {
+ c = s[i];
+ if (isdigit(c) || c == ' ') {
+ }
+ else return 0;
+ }
+ np = strsplit(h, st, ' ');
+ if (np == 1) return 0;
+ for (i = 0; i < np; i++) {
+ if (!IsInBlankStr(h[i], GetUnused(SelConnected))) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void ClearGarbageListsel() { // löscht leere Einträge am Ende von ListSel
+ int i;
+ while (ListSel[i]) {
+ if (UnpackListsel(i, Draehte) == "" && UnpackListsel(i, Bruecken) == "") ListSel[i] = "";
+ i++;
+ }
+}
+
+// Lösche eine Verbindung aus Auswahlliste
+void DelOneEntry(int Sel) {
+ int i, n, imax;
+ string x[];
+ PushUndo();
+ if (Sel < 0) return;
+ SelConnected = -1;
+ while(UnpackListsel(i, Bruecken)) i++; // # Einträge feststellen
+ imax = i;
+ for (i = 0; i < imax; i++) {
+ if (i <= Sel) {
+ x[i] = UnpackListsel(i, Bruecken);
+ }
+ else {
+ x[i-1] = UnpackListsel(i, Bruecken);
+ }
+ }
+ if (imax != 0) PackListsel(imax-1, Bruecken, "");
+
+ if (Sel == 0 && imax == 0) {
+ PackListsel(0, Bruecken, "");
+ }
+ else {
+ imax = imax -1;
+ for (i = 0; i < imax; i++) {
+ PackListsel(i, Bruecken, x[i]);
+ }
+ }
+ if (Sel > 0) SelConnected = Sel-1;
+ else SelConnected = 0;
+ ClearGarbageListsel(); // entferne leere Zeilen aus ListSel
+}
+
+void CreateBridge(void) {
+ int i;
+ while(UnpackListsel(i, Bruecken)) i++; // # Einträge feststellen
+ PackListsel(i, Bruecken, "");
+ ChangeString = "";
+ SelConnected = i;
+}
+
+void EditOneEntry(int Sel) {
+ string h[];
+ if (Sel < 0) return;
+ strsplit(h, ListSel[Sel], '\t');
+ ChangeString = SortBlankSeparatedString(h[Bruecken]);
+}
+
+void TransferEditLine (int Sel) {
+ string h[];
+ if (Sel < 0) return;
+ PushUndo();
+ if (StripWhiteSpace(ChangeString) == "") {
+ DelOneEntry(Sel);
+ return;
+ }
+ ChangeString = SortBlankSeparatedString(ChangeString);
+ if (CheckOKChangeString(ChangeString)) {
+ PackListsel(Sel, Bruecken, ChangeString);
+ }
+ else dlgMessageBox("Ungültige Klemmennummern im Editier-Feld!
"
+ "Erlaubt sind Klemmennummern, die in der selektierten Brücke verwendet wurden, "
+ "aber in keiner anderen (nur Leerzeichen und 0-9).
");
+// return;
+// }
+ strsplit(h, ListAll[CurrentPartIndex], '\t');
+ string pname = h[Name];
+ //sht = lookup(PartDatabase, pname, "Seite", '\t');
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+ LogCmd += "Befehle zum Eintragen der neuen Verweise\n";
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+ DoCmd += "change display off;\n";
+ line = StripWhiteSpace(UnpackListall(CurrentPartIndex, Verwendet));
+ np = strsplit(klemme, line, ' ');
+ ns = strsplit(klemmsheet, ListAllSheet[CurrentPartIndex], ' ');
+ for (k = 0; k < np; k++) { // alle Attr. der verwendeten Klemmen löschen
+ DoCmd += "edit .s" + klemmsheet[k] + ";\n";
+ DoCmd += "change display off;\n";
+ DoCmd += "attribute " + pname + " " + klemme[k] + "1 " + "'';\n";
+ DoCmd += "change display off;\n";
+ DoCmd += "attribute " + pname + " " + klemme[k] + "2 " + "'';\n";
+ }
+ i = 0; k = 0;
+ while (StripWhiteSpace(UnpackListsel(i, Bruecken))) { // alle Brückenzeilen in Att. eintragen
+ line = StripWhiteSpace(UnpackListsel(i, Bruecken));
+ np = strsplit(klemme, line, ' ');
+ for (k = 1; k < np; k++) { // alle Klemmen pro Brücke
+ DoCmd += "change display off;\n";
+ DoCmd += "attribute " + pname + " " + klemme[k-1] + "2 " + "'" + klemme[k] + "';\n";
+ }
+ for (k = np - 2; k >= 0; k--) { // alle Klemmen pro Brücke
+ DoCmd += "change display off;\n";
+ DoCmd += "attribute " + pname + " " + klemme[k+1] + "1 " + "'" + klemme[k] + "';\n";
+ }
+ i++;
+ }
+ LogCmd += DoCmd;
+ LogCmd += "---------------------------------------------------------------------------------------------\n";
+
+ output(errorfile, "wtD") printf("%s", LogCmd);
+ output(scrfile, "wtD") printf("%s", DoCmd);
+ ListCmd = MakeList();
+ output(listfile, "wt") printf("%s", ListCmd);
+
+ exit(DoCmd);
+}
+
+void ShowHelp(void) {
+ dlgDialog("Hilfe") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout{
+ dlgVBoxLayout dlgSpacing(600);
+ dlgTextView(HelpText);
+ }
+ dlgHBoxLayout {
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ }
+ };
+}
+
+//*****************************************************
+void ShowUserInterface(void) {
+ dlgDialog("Brückenklemmen verwalten - (" + filename(argv[0]) + ") " + Version) {
+ dlgHBoxLayout dlgSpacing(300);
+ dlgGroup("") {
+ dlgLabel("Vorhandene Klemmenblöcke");
+ dlgListView(ListHeaderMain, ListAll, SelAll, SortAll) MakeEditListOnePart(SelAll);
+ dlgSpacing(10);
+ }
+ dlgGroup("") {
+ dlgHBoxLayout {
+ dlgLabel(CurrentPart, 1) ;
+ dlgLabel(": Brücken dieses Klemmenblocks editieren");
+ dlgStretch(1);
+ }
+ dlgListView(ListHeader, ListSel, SelConnected, Sort) EditOneEntry(SelConnected);
+ dlgHBoxLayout {
+ dlgLabel("Verbinden");
+ dlgStringEdit(ChangeString);
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("Undo") PullUndo();
+ dlgStretch(1);
+ dlgPushButton("Unbenutzte") ChangeString = GetUnused(SelConnected);
+ dlgPushButton("Löschen") DelOneEntry(SelConnected);
+ dlgPushButton("Neu") CreateBridge();
+ dlgPushButton("+Anwenden") TransferEditLine(SelConnected);
+ }
+ }
+ dlgSpacing(10);
+ dlgHBoxLayout {
+ }
+ dlgHBoxLayout {
+ dlgPushButton("&Hilfe") ShowHelp();
+ dlgStretch(1);
+ dlgPushButton("Log-Datei") ShowLog();
+ dlgPushButton("-Abbrechen") dlgReject(); // if (CancelOk()) dlgReject();
+ dlgPushButton("Speichern") SaveList();
+ }
+ };
+}
+//***************** Main ******************************
+SetFileNames();
+NrHeader = strsplit(head, ListHeader, '\t');
+CollectX();
+GetConnectedAllParts();
+WriteAttributeLog();
+output(errorfile, "wtD") printf("%s", LogCmd);
+ShowUserInterface();
+
diff --git a/trunk/ulp/e-klemmenplan.ulp b/trunk/ulp/e-klemmenplan.ulp
new file mode 100644
index 00000000..2e95b771
--- /dev/null
+++ b/trunk/ulp/e-klemmenplan.ulp
@@ -0,0 +1,1113 @@
+// Klemmenplan/Kabelplan/Brückenplan für Elektro-Projekte
+
+// todo
+// Prüfen ob Netz auf Pin und nicht angeschlossen (pindatabase)
+// x-Verbindungen nach Namen sortieren
+
+string Version = "Version 1.03";
+
+// History
+// 1.03 -- 2009-10-01
+// nicht benötigte "\t\t" im Titel von dlgDialog() entfernt
+//
+// 1.02
+// Verbindungen von Netzen mit mehr als zwei Kontakten werden jetzt in anderer Reihenfolge
+// erstellt (siehe Help)
+//
+// Ist auf einer Seite keine Klemme (Prefix X) vorhanden, werden alle Verbindungen als d
+// (Drahtverbindung) gekennzeichnet
+//
+// 1.01 Keine Fehlermeldung mehr, wenn Packages Smds enthalten
+
+#require 4.9206
+
+#usage "Erstellen eines Klemmenplans\n
"
+
+"Mit diesem ULP erstellen Sie einen Klemmenplan, der alle Zweipunktverbindungen "
+"der geladenen Schaltung enthält, also Verbindungen im Schaltschrank, die "
+"üblicherweise mit Drähten realisert werden, und externe, die mit Kabeln "
+"realisiert werden. Interne, externe und Brücken-Verbindungen erscheinen nacheinander in der Liste.
"
+"Das Programm sollte erst dann verwendet werden, wenn die "
+"Schaltung nicht mehr oder nur noch geringfügig verändert wird.
"
+"Die erzeugte Liste (schaltungsname.vbd) kann in einem Tabellenkalkulationsprogramm "
+"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die "
+"Schaltungszeichnung importiert werden.
"
+
+"Mit diesem ULP erstellen Sie einen Klemmenplan, der alle Zweipunktverbindungen "
+"der geladenen Schaltung enthält, also Verbindungen im Schaltschrank, die "
+"üblicherweise mit Drähten realisert werden, und externe, die mit Kabeln "
+"realisiert werden. Das Programm sollte erst dann verwendet werden, wenn die "
+"Schaltung nicht mehr oder nur noch geringfügig verändert wird.
"
+
+"Die obere Liste (Verbindungsliste) enthält immer alle Verbindungen mit diversen "
+"Parametern. Sie wird abgespeichert, wenn Sie den Button Speichern "
+"anklicken. Der Benutzer hat die Aufgabe, jeder Verbindung die passenden "
+"Parameter (Farbe, Kabeltyp etc.) zuzuordnen. Dabei unterstützt ihn dieses "
+"ULP.
"
+"Die erzeugte Liste (schaltungsname.vbd) kann in einem Tabellenkalkulationsprogramm "
+"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die "
+"Schaltungszeichnung importiert werden.
"
+
+"Regeln für das Zeichnen von Mehrfachverbindungen
"
+
+"Sind mehr als zwei Klemmen im Schaltplan miteinander verbunden, dann gelten folgende Regeln:
"
+"Die Klemmen werden der Reihe nach von oben nach unten und von links nach rechts verbunden. "
+"Das heißt, wenn sich auf diese Weise eine Reihenfolge der Klemmen von A, B, C, D ergibt, "
+"dann entstehen die Drahtverbindungen A-B, B-C, C-D. Die Art, wie die Netzlinien gezeichnet sind, "
+"spielt dabei keine Rolle. Sollen die Einzelverbindungen auf andere Art realisiert werden, "
+"etwa A-C, C-B, B-D, dann müssen die Klemmen im Schaltplan entsprechend platziert werden. "
+"Erstreckt sich ein Netz über mehrere Seiten, dann wird die Klemme rechts unten mit der "
+"Klemme rechts oben auf der Folgeseite verbunden.
"
+
+"Bedeutung der Spalten
"
+
+"Die Spalten der beiden dargestellen Listen haben folgende Bedeutung:
"
+
+"Nummer: Laufende Nummer, die vom Programm automatisch erzeugt wird.
"
+"Von/Nach: 1.A1 bedeutet, die Verbindung startet/endet auf Seite 1, "
+"Rahmenkoordinaten A1.
"
+"Quelle/Ziel: F1 1 bedeutet, die Verbindung beginnt/endet an Bauteil F1, Kontakt 1.
"
+"Art: "
+"\td = Drahtverbindung (intern, im Schaltschrank) "
+"\tk = Kabelverbindung (extern, außerhalb des Schaltschranks) "
+"\tx = Brücke (Klemme zu Klemme im gleichen Klemmenblock)
"
+
+"Das Programm kennzeichnet alle Verbindungen als extern, die auf einer Seite "
+"unterhalb der untersten Klemme (Präfix X..) beginnen.
"
+
+"Die Spalteneinträge bis Art werden vom Programm automatisch erzeugt. Die "
+"Spalten rechts davon trägt der Benutzer ein. Art kann ebenfalls verändert werden, "
+"dieser Parameter ist dafür verantwortlich, wo die Verbindung in der Ausgabeliste "
+"erscheint (wenn das Feld leer ist, wird die Zeile nicht ausgegeben).
"
+
+"Bedienung des Programms
"
+
+"In die untere Liste (Auswahlliste) holen Sie eine Gruppe von Verbindungen, die "
+"gemeinsame Parameter erhalten sollen, abhängig davon, welche Auswahl-Parameter "
+"eingetragen sind (Button Holen). Danach setzen sie für die ganze Gruppe "
+"die Werte, die Sie unter Parameter ändern eingetragen haben (Button "
+"Alle eintragen oder Alle außer leere). Dann übertragen Sie die "
+"Parameter in die obere Liste mit dem Button Anwenden. "
+"Sie können die Parameter der selektierten Auswahllisten-Zeile auch in einem "
+"separaten Fenster editieren, das sich nach einem Doppelklick auf diese Zeile öffnet.
"
+
+"Beispiel: Es sollen alle Bauteile als Farbe rot erhalten, die mit F "
+"beginnen.
"
+"Löschen Sie zunächst die Auswahlliste mit dem Button Alle löschen.
"
+"Klicken Sie dann Alle * an, damit das Wildcard-Zeichen * in alle "
+"Suchfelder eingetragen wird. In die Felder kann ein sogenannter Wildcard-Text "
+"eingegeben werden, bei dem das Zeichen * beliebige Zeichen ersetzt. Ein Stern "
+"bedeuted, es spielt keine Rolle, wie der Eintrag lautet.
"
+"Jetzt tippen Sie in das Feld Quelle/Ziel der Gruppe Auswahl-Parameter F* ein und "
+"klicken dann auf Holen. Alle F..-Bauteile erscheinen jetzt in der "
+"unteren Liste.
"
+"Tragen Sie jetzt rot im Feld Farbe des Blocks Parameter "
+"ändern ein, und klicken Sie auf den Button Anwenden. Die Parameter "
+"werden dann in die obere Liste übertragen.
"
+
+"Bedeutung der Buttons
"
+
+"Undo oben: Die letzte Veränderung der Verbindungsliste wird "
+"rückgängig gemacht (nur ein Schritt möglich).
"
+
+"Nach oben/Nach unten: Die in der Verbindungsliste selektierte Zeile wird nach "
+"oben oder unten verschoben. Damit ändert sich die laufende Nummer der Zeile. Auf "
+"diese Weise lässt sich die Ausgabereihenfolge verändern.
"
+
+"Quelle - Ziel: Quelle und Ziel des selektierten Eintrags in der "
+"Verbindungsliste werden vertauscht.
"
+
+"Undo unten: Die letzte Veränderung der Auswahlliste wird "
+"rückgängig gemacht (nur ein Schritt möglich).
"
+
+"Eintrag löschen: Die in der Auswahlliste selektierte Zeile wird gelöscht.
"
+
+"Alle löschen: Alle Zeilen der Auswahlliste werden gelöscht.
"
+
+"Anwenden: Die Parameter der Auswahlliste werden in die entsprechenden "
+"Verbindungen der Verbindungsliste eingetragen: Dabei werden die bisherigen "
+"Parameter (einschließlich leere Felder) überschrieben.
"
+
+"Löschen: Alle Felder der Blöcke Auswahl-Parameter und Parameter "
+"ändern werden gelöscht.
"
+
+"Alle *: Setze alle Suchfelder auf das Wildcard-Zeichen *. Es sind auch Muster "
+"wie *F* oder *F*1* erlaubt.
"
+
+"Holen: Hole alle Verbindungen, bei denen die eingetragenen Suchparameter "
+"zutreffen. Die Felder untereinander sind UND-Verknüpft, das heißt nur wenn bei "
+"allen Feldern ein entsprechender Eintrag in der Verbindungsliste gefunden wird, "
+"wird die Verbindung in die Auswahlliste geholt. Wenn Sie etwa alle Verbindungen "
+"auf Seite 1 mit der Farbe rot holen wollen, dann tragen Sie in Von/Nach "
+"1.* ein und in das Feld Farbe rot. Alle anderen Felder enthalten *. "
+"Ein Doppelklick auf einen Eintrag in der Verbindungsliste bringt diese "
+"eine Verbindung in die Auswahlliste.
"
+
+"Alle eintragen: Die in den Feldern eingetragenen Parameter werden in alle "
+"Verbindungen der Auswahlliste eingetragen (auch leere Felder).
"
+
+"Alle außer leere: Die in den Feldern eingetragenen Parameter werden in alle "
+"Verbindungen der Auswahlliste eingetragen. Ist ein Feld im Block Parameter "
+"ändern leer, dann wird das entsprechende Feld in der Auswahlliste nicht "
+"verändert.
"
+
+"Fehlerliste: Zeigt eine Liste mit möglichen Fehlern in der Schaltung.
"
+
+"Lade ext. Liste: Falls Sie bereits einen Klemmenplan erstellt haben und "
+"anschließend nur noch geringfügige Änderungen durchgeführt wurden (Namen der "
+"Bauteile im Wesentlichen gleich), dann starten Sie das ULP und klicken als "
+"erstes auf diesen Button, damit die bisherigen Parameter in die Verbindungsliste "
+"übernommen werden. Verbindungen, die aufgrund von Schaltungsänderungen nicht "
+"zugeordnet werden können, erscheinen in der Auswahlliste.
"
+
+"Abbrechen: Programm ohne Abspeichern des Klemmenplans verlassen. Achtung, Sie "
+"verlieren alle Änderungen am Klemmenplan.
"
+
+"Speichern: Abspeichern des Klemmenplans.
"
+
+"Ausgabe
"
+
+"In der vorliegenden Version wird eine tabulatorseparierte Liste ausgegeben, "
+"die Sie entweder in einem Texteditor (mit passend gesetzten Tabulatorwerten) "
+"oder z. B. mit Excel oder OpenOffice weiterverarbeiten können.
"
+
+"Verändern der Spaltenüberschriften
"
+
+"Wenn Sie die Spaltenüberschriften an eigene Bedürfnisse anpassen wollen, "
+"verändern Sie im Programm die Zeile:
"
+
+"Sie können zwischen den Tabulatorzeichen (\\t) die Texte verändern oder neue "
+"Texte hizufügen, z.B.:
"
+
+"\"...\\tFunktion\\tBeschreibung\";
"
+
+"Achtung: Die Bedeutung der Spalten von Nummer bis Art bleibt "
+"unverändert!
"
+;
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SetFileNames(void) { // in Schematic-Kontext aufrufen
+
+ if (!schematic) {
+ // dlgMessageBox("Dieses Programm muss vom Schaltplan-Editor aus aufgerufen werden");
+ exit(1);
+ }
+ schematic(SCH) {
+ tmpfile = filesetext(SCH.name, ".$$$");
+ listfile = filesetext(SCH.name, ".kp$");
+ errorfile = filesetext(SCH.name, ".log");
+ pinfile = filesetext(SCH.name, ".pi$");
+ vbdfile = filesetext(SCH.name, ".vbd");
+ klpfile = filesetext(SCH.name, ".klp");
+ kapfile = filesetext(SCH.name, ".kap");
+ brpfile = filesetext(SCH.name, ".brp");
+ }
+}
+
+string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Whitespaces im Inneren werden 1 Whitespace
+ int i, n;
+ string t;
+
+ while (s && isspace(s[0]))
+ s = strsub(s, 1);
+ while (s && isspace(s[strlen(s) - 1]))
+ s = strsub(s, 0, strlen(s) - 1);
+// Doppel-Blanks
+ for (i = 0; i < strlen(s); i++) {
+ if (!isspace(s[i])) t[n++] = s[i];
+ else {
+ if ((strlen(s) > i+1) && isspace(s[i+1]));
+ else t[n++] = s[i];
+ };
+ }
+ s = t;
+
+ return s;
+}
+
+void ErrorMessage(string PartPin, string msg) {
+ string s, sh, col, row;
+ sh = lookup(pindatabase, PartPin, "Sheet", '\t');
+ col = lookup(pindatabase, PartPin, "Column", '\t');
+ row = lookup(pindatabase, PartPin, "Row", '\t');
+ sprintf(s, "S. %s/%s-%s \tKontakt %s: \t%s", sh, row, col, PartPin, msg);
+ ErrCmd += s + "\n";
+}
+
+/////////////////////////////////////////
+// pindatabase anlegen
+//
+// ermittle Zahl der Wires, die von Pin bzw. x,y aus starten
+int NrOfWiresFromPin(string net, int shnr, int x, int y) {
+ string s;
+ int n;
+ schematic(SCH) {
+ SCH.sheets(SH) {
+ if (SH.number == shnr) {
+ SH.nets(N) {
+ if (N.name == net) {
+ N.segments(SEG) {
+ SEG.wires(W) {
+ if (x == W.x1 && y == W.y1 || x == W.x2 && y == W.y2) { // Wire beginnt an x, y
+ n++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (net && !n) n = 1; // wenn Pin auf Pin, net vorhanden, deshalb n auf 1
+ return n;
+}
+
+// ermittle Zahl der Wires, die nach dem ersten Wire-Segment vom Pin aus starten
+// Wire vom Pin weg wird mitgezählt
+int NrOfWiresAfterPin(string net, int shnr, int x, int y) {
+ string s;
+ int n, n1, u;
+ schematic(SCH) {
+ SCH.sheets(SH) {
+ if (SH.number == shnr) {
+ SH.nets(N) {
+ if (N.name == net) {
+ N.segments(SEG) {
+ n1 = 0;
+ SEG.wires(W) {
+ if (x == W.x1 && y == W.y1 || x == W.x2 && y == W.y2) { // suche ersten Wire
+ if (x == W.x1 && y == W.y1) { // stelle Endkoordinaten des Wires fest
+ x = W.x2; y = W.y2;
+ }
+ else {
+ x = W.x1; y = W.y1;
+ }
+ if (y == W.y1 || y == W.y2) { // Wire-Anfang zweigt nach erstem Wire-Segment über/unter Pin ab
+ n1 = NrOfWiresFromPin(net, shnr, x, y); // x, y nach erstem Wire-Stück
+ distY = y; // global, Distanz des Abzweigs in vertikaler Richtung
+ if (n1) break;
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return n1;
+}
+
+void SetupPinDatabase(void) {
+ string s, cmd, pname;
+ int np, nw;
+ schematic(SCH) {
+ cmd = "PartContact\tNet\tSheet\tRow\tColumn\tx\ty\tNP\tNW\tdistY\n";
+ SCH.sheets(SH) { // # Wires ab Pin
+ SH.parts(PRT) { // # Wires nach erstem Wire
+ PRT.instances (I) { // Abstand des Abzweigs vertikal
+ I.gate.symbol.pins(P) {
+ if (P.contact) {
+ pname = P.contact.name;
+ }
+ else {
+ pname = P.name;
+ }
+ np = NrOfWiresFromPin(P.net, SH.number, P.x, P.y); nw = NrOfWiresAfterPin(P.net, SH.number, P.x, P.y);
+ sprintf(s, "%s%s%s\t%s\t%d\t%s\t%s\t%d\t%d\t", PRT.name, PartPinSep, pname, P.net, SH.number, I.row, I.column, P.x, P.y); cmd += s;
+ sprintf(s, "\t%d\t%d\t%d\n", np, nw, distY); cmd += s;
+ // Hier lassen sich alle Pin-Parameter prüfen
+ if (nw > 3 || np > 2) {
+ sprintf(s, "S. %d/%s-%s \tKontakt %s %s: \tMehr als zwei Abzweigungen vom Kontakt!", SH.number, I.row, I.column, PRT.name, pname);
+ ErrCmd += s + "\n";
+ }
+ // todo: Prüfen, ob ein nicht angeschlossenes Netz auf dem Pin liegt
+ }
+ }
+ }
+ }
+ }
+ strsplit(pindatabase, cmd, '\n');
+ output(pinfile, "wtD") {
+ printf(cmd);
+ }
+}
+//ende pindatabase /////////////////////////////////
+
+void ReadConnects(void) {
+ int i, n, x[], y[], index[], loopcnt;
+ numeric string Part_Pin[];
+ schematic(SCH) {
+ SCH.nets(NET) {
+ loopcnt = 0;
+ SCH.sheets(SH) {
+ SH.nets(N) {
+ if (NET.name == N.name) {
+ loopcnt++;
+ if (loopcnt == 1) {
+ cmd += "\n";
+ }
+ n = 0;
+ N.segments(SEG) {
+ SEG.pinrefs(P) {
+ if (P.pin.contact) {
+ Part_Pin[n] = P.part.name + "\t" + P.pin.contact.name;
+ }
+ else {
+ Part_Pin[n] = P.part.name + "\t" + P.pin.name;
+ }
+ x[n] = P.pin.x; y[n] = INT_MAX - P.pin.y; // scanne Klemmen von oben nach unten
+ ++n;
+ }
+ }
+ sort(n, index, x, y, Part_Pin); // sortiere PartPin innerhalb eines Segments nach Position
+ // scanne Klemmen: erst alle y auf x = 0 etc.
+ for (int i = 0; i < n; ++i) {
+ sprintf(s, "%s\t", Part_Pin[index[i]]); cmd += s;
+ }
+ }
+ }
+ }
+ }
+ }
+ output(tmpfile, "wtD") {
+ printf(cmd);
+ }
+}
+
+// Ermittle y-Wert für Trennung zwischen interner und externer Verdrahtung
+// Hier: Klemme mit niedrigstem y pro Sheet
+void GetYReference(void) { // YRef[] liefert: #sheets, yref-sh1, yref-sh2 ..
+ int sn, ymin, klemme_exists;
+ schematic(S) {
+ S.sheets(SH) {
+ sn++;
+ ymin = INT_MAX;
+ klemme_exists = 0;
+ SH.parts(P) {
+ P.instances(I) {
+ if (strchr(I.name, 'X') == 0) { // Alle, die mit X beginnen
+ ymin = min(ymin, I.y); // sprintf(s, "%s: %d\n", I.name, ymin); ErrCmd += s;
+ klemme_exists = 1;
+ }
+ }
+ }
+ YRef[SH.number] = ymin; // sprintf(s, " %d: %d\n", SH.number, YRef[SH.number]); ErrCmd += s;
+ if (klemme_exists == 0) {
+ YRef[SH.number] = 0;
+ }
+ }
+ YRef[0] = sn;
+ }
+}
+
+string AssembleNetLine(string line){
+ int i, j, n, npar, snr;
+ string s, st, lxy, rxy;
+ string ps[]; // Einzelparameter, Source
+ string pair[]; // Name-Pin-Paar mit Blank
+ string x[];
+ string y[];
+ string distY[];// Distanz der Abzweigung vom Pin
+ string np[]; // # Wires ab Pin
+ string nw[]; // # Wires ab erstem Wire-Segment nach Pin
+ string Sep = "\t";
+ string net[];
+ string sht[];
+ string row[];
+ string col[];
+
+ npar = strsplit(ps, line, '\t');
+ for (j = 0; j < npar/2;) { // Zusammenfassen von Part und Pin mit Blank
+ pair[j++] = ps[n++] + " " + ps[n++];
+ }
+ n = 0;
+ while (pair[n]) { // Sammeln der Pin-Informationen
+// np[n] = lookup(pindatabase, PartPin, "NP", '\t');
+ x[n] = lookup(pindatabase, pair[n], "x", '\t');
+ y[n] = lookup(pindatabase, pair[n], "y", '\t');
+ net[n] = lookup(pindatabase, pair[n], "Net", '\t');
+ sht[n] = lookup(pindatabase, pair[n], "Sheet", '\t');
+ row[n] = lookup(pindatabase, pair[n], "Row", '\t');
+ col[n] = lookup(pindatabase, pair[n], "Column", '\t');
+ if (!sht[n]) {
+ sht[n] = "?";
+ col[n] = "?";
+ row[n] = "?";
+ }
+ n++;
+ }
+ if (npar <= 2) {
+ ErrorMessage(pair[0], "Netz nicht abgeschlossen!");
+ return "";
+ }
+
+ netnr++;
+ sprintf (lxy, "%08d %08d", strtol(x[0]), strtol(y[0]));
+ sprintf (rxy, "%08d %08d", strtol(x[1]), strtol(y[1]));
+
+ // Art voranstellen
+ snr = min (strtol(sht[0]), strtol(sht[1])); // Sheetnr
+ if (strtol(y[0]) <= YRef[snr] && strtol(y[1]) > YRef[snr]) ErrorMessage(pair[0], "Verbindung nicht eindeutig (intern oder extern?)");
+ if (strtol(y[0]) > YRef[snr]) s = "d\t";
+ if (strtol(y[0]) <= YRef[snr]) s = "k\t";
+ if (strsub(pair[0], 0, 1) == "X" && ps[0] == ps[2]) s = "x\t";
+ st += s;
+
+ if ((lxy > rxy && strtol(sht[0]) == strtol(sht[1])) || (strtol(sht[0]) > strtol(sht[1]))) { // Reihenfolge Quelle-Ziel etc. tauschen
+ sprintf(s, "%03d%s", strtol(sht[1]), Sep); st+= s;
+ sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[1]), strtol(y[1]), Sep, strtol(x[0]), strtol(y[0]), Sep); st += s;
+ sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[1], Sep, sht[1], row[1], col[1], Sep); st += s + pair[1] + Sep + pair[0];
+ sprintf(s, "%s%s.%s%s", Sep, sht[0], row[0], col[0]); st += s;
+ }
+ else {
+ sprintf(s, "%03d%s", strtol(sht[0]), Sep); st+= s;
+ sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[0]), strtol(y[0]), Sep, strtol(x[1]), strtol(y[1]), Sep); st += s;
+ sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[0], Sep, sht[0], row[0], col[0], Sep); st += s + pair[0] + Sep + pair[1];
+ sprintf(s, "%s%s.%s%s", Sep, sht[1], row[1], col[1]); st += s;
+ }
+
+ st += "\n";
+ if (npar <= 4) return st; // nur Zweipunktverbindung
+ if (npar > 4) { // jeden mit dem Nachbarn verbinden (gleiches y hat Vorrang)
+ n = 2;
+ while (pair[n]) {
+ netnr++;
+ sprintf (lxy, "%08d %08d", strtol(x[n-1]), strtol(y[n-1]));
+ sprintf (rxy, "%08d %08d", strtol(x[n]), strtol(y[n]));
+
+ // Art voranstellen
+ snr = min (strtol(sht[n-1]), strtol(sht[n])); // Sheetnr
+ if (strtol(y[n-1]) <= YRef[snr] && strtol(y[n]) > YRef[snr]) ErrorMessage(pair[n-1], "Verbindung nicht eindeutig (intern oder extern?)");
+ if (strtol(y[n-1]) > YRef[snr]) s = "d\t";
+ if (strtol(y[n-1]) <= YRef[snr]) s = "k\t";
+ if (strsub(pair[n-1], 0, 1) == "X" && ps[(n-1)*2] == ps[n*2]) s = "x\t";
+ st += s;
+
+ if ((lxy > rxy && strtol(sht[n-1]) == strtol(sht[n])) || (strtol(sht[n-1]) > strtol(sht[n]))) {
+ sprintf(s, "%03d%s", strtol(sht[n]), Sep); st+= s;
+ sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[n]), strtol(y[n]), Sep, strtol(x[n-1]), strtol(y[n-1]), Sep); st += s;
+ sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[n], Sep, sht[n], row[n], col[n], Sep); st += s + pair[n] + Sep + pair[n-1];
+ sprintf(s, "%s%s.%s%s", Sep, sht[n-1], row[n-1], col[n-1]); st += s;
+ }
+ else {
+ sprintf(s, "%03d%s", strtol(sht[n-1]), Sep); st+= s;
+ sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[n-1]), strtol(y[n-1]), Sep, strtol(x[n]), strtol(y[n]), Sep); st += s;
+ sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[n-1], Sep, sht[n-1], row[n-1], col[n-1], Sep); st += s + pair[n-1] + Sep + pair[n];
+ sprintf(s, "%s%s.%s%s", Sep, sht[n], row[n], col[n]); st += s;
+ }
+ st += "\n";
+ n++;
+ }
+ }
+ return st;
+}
+
+// Verbindungsliste aufbereiten
+void ChangeList(void) {
+ int i, j, nl, np;
+ numeric string a[], c[], s, sh;
+ GetYReference(); // YRef[sheet] enthält y von unterstem Klemmenkontakt
+
+ nl = fileread(a, tmpfile);
+ // sort(n, a);
+ output(tmpfile, "wtD") { // leere Zeilen entfernen
+ for (i = 0; i < nl; i++) {
+ if (a[i]) printf("%s\n",a[i]);
+ }
+ }
+ nl = fileread(a, tmpfile);
+ if (nl > 0) {
+ output(listfile, "wtD") { // sheetnr \t x y \t x y \t Nummer \t Netz \t Von ..
+ for (i = 0; i < nl; i++) {
+ a[i] = StripWhiteSpace(a[i]); // a[] enthält urspr. Connect-Zeilen
+ b[i] = a[i]; // b[] enthält Zeilen eines Signals und wird verändert (global)
+ b[i] = AssembleNetLine(b[i]);
+ if (b[i]) printf("%s", b[i]); // b[0..nl] -> alle Zeilen eines Signals geordnet nach Pos.
+ }
+ }
+ }
+ nl = fileread(a, listfile); // sortieren nach sheetnr und erstem x y \t xy
+ sort(nl, a);
+ output(listfile, "wtD") {
+ for (i = 0; i < nl; i++) {
+ strsplit(c, a[i], '\t');
+ printf("%d\t%s\t%s\t%s\t%s\t%s\n", i + 1, c[6], c[7], c[8], c[9], c[0]);
+// printf("%s\n", a[i]);
+ }
+ }
+}
+
+//************** von Main benutzt **********************
+
+void PushUndo(void) {
+ int i;
+ while (listundo[i]) {
+ listundo[i] = "";
+ i++;
+ }
+ i = 0;
+ while (listsel[i]) {
+ listundo[i] = listsel[i];
+ i++;
+ }
+}
+
+void PullUndo(void) {
+ int i;
+ while (listsel[i]) {
+ listsel[i] = "";
+ i++;
+ }
+ i = 0;
+ while (listundo[i]) {
+ listsel[i] = listundo[i];
+ i++;
+ }
+}
+
+void PushUndoOben(void) {
+ int i;
+ while (listundoOben[i]) {
+ listundoOben[i] = "";
+ i++;
+ }
+ i = 0;
+ while (listall[i]) {
+ listundoOben[i] = listall[i];
+ i++;
+ }
+}
+
+void PullUndoOben(void) {
+ int i;
+ while (listundoOben[i]) {
+ i++;
+ }
+ if (i == 0) return; // wenn alte Liste leer (nach dem Start)
+ i = 0;
+ while (listall[i]) {
+ listall[i] = "";
+ i++;
+ }
+ i = 0;
+ while (listundoOben[i]) {
+ listall[i] = listundoOben[i];
+ i++;
+ }
+}
+
+// Lies rohe Verbindungsliste
+void ReadList(void) {
+ int i, j, np;
+ numeric string h[];
+ NrLinesListAll = fileread(listall, listfile) -1;
+ for (i = 0; i < NrLinesListAll; i++) {
+ while (strsplit(h, listall[i], '\t') < NrHeader) listall[i] += "\t";
+ listsel[i] = listall[i]; // erst, Auswahliste füllen, damit Listen gleich formatiert werden
+ }
+}
+
+void ShowErrorList(void) {
+ dlgDialog("Fehlerliste") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout{
+ dlgTextEdit(ErrCmd);
+ }
+ dlgHBoxLayout {
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("&Hilfe") dlgMessageBox( "Überprüfen Sie die in der Liste aufgeführten Kontakte!\n"
+ "Sie können die Fehlerliste auch editieren und mit Cut&Paste \n"
+ "zu einem Texteditor übertragen."
+ );
+ dlgPushButton("+OK") dlgAccept();
+ }
+ };
+}
+
+// Übertrage eine Verbindung in Auswahlliste, wenn noch nicht vorhanden
+void TransferOneEntry(int Sel) {
+ int i, n;
+ string h1[], h2[];
+ PushUndo();
+ strsplit(h1, listall[Sel], '\t');
+ while(listsel[i]) {
+ strsplit(h2, listsel[i], '\t');
+ if (h1[Nummer] == h2[Nummer] &&
+ h1[Von] == h2[Von] &&
+ h1[Quelle] == h2[Quelle] &&
+ h1[Ziel] == h2[Ziel] &&
+ h1[Nach] == h2[Nach]
+ )
+ return; // Zeilen identisch -> kein neuer Eintrag (nur feste Felder bis Nach geprüft)
+ i++;
+ }
+ i = 0;
+ while(listsel[i++]) { // finde letzte Zeile
+ }
+ listsel[i-1] = listall[Sel];
+}
+
+// Lösche eine Verbindung aus Auswahlliste
+void DelOneEntry(int Sel) {
+ int i, n, imax;
+ string x[];
+ PushUndo();
+ if (Sel < 0) return;
+ //SelConnection = -1;
+ while(listsel[i++]) {
+ }
+ imax = i;
+ for (i = 0; i < imax; i++) {
+ if (i <= Sel) {
+ x[i] = listsel[i];
+ }
+ else {
+ x[i-1] = listsel[i];
+ }
+ }
+ listsel[imax-1] = ""; listsel[imax] = "";
+ imax = imax -1;
+ for (i = 0; i < imax; i++) {
+ listsel[i] = x[i];
+ }
+}
+
+void SetSelParams(string c) {
+ int i;
+ for (i = 1; i < NrHeader; i++) {
+ SelParam[i] = c; // einige nicht relevant
+ }
+}
+
+void SetChangeParams(string c) {
+ int i;
+ for (i = 1; i < NrHeader; i++) {
+ ChangeParam[i] = c; // einige nicht relevant
+ }
+}
+
+// Suche mit Wildcard *
+int WildMatch(string wild, string st) { // wild = Suchmuster, st = zu durchsuchender Sting
+ int wx, sx, pos;
+ string sw, ss;
+ wild = StripWhiteSpace(wild);
+ st = StripWhiteSpace(st);
+ if (wild == st || wild == "*") return 1;
+ if (!wild && st) return 0;
+ if (strchr(wild, '*') < 0 && strlen(wild) > 0 && st == "") return 0; // wild exist., aber kein *
+ if (strlen(wild) > 0 && st == "") { // wild exist. mit Nicht-*-Zeichen, st = ""
+ pos = 0;
+ sw = wild;
+ while (sw[pos]) { // Zeichen außer * in wild vorhanden -> return 0
+ if (sw[pos] != '*') return 0;
+ pos++;
+ }
+ return 1; // wild ist **...
+ }
+ while (wild[wx] && st[sx]) {
+ while (wild[wx] != '*') { // vgl. bis zum nächsten *
+ if (wild[wx++] != st[sx++]) return 0;
+ if (sx == strlen(st) && !(wx == strlen(wild))) { // Ende von st erreicht aber nicht Ende von wild
+ if (wild[wx] == '*' && !wild[wx+1]) return 1; // nächstes Zeichen von wild ist *, dann Stringende
+ else return 0;
+ }
+ if (wx == strlen(wild) && !(sx == strlen(st))) return 0; // Ende von wild erreicht aber nicht Ende von st
+ if (wx == strlen(wild) && (sx == strlen(st))) return 1; // Ende von wild erreicht aber nicht Ende von st
+ }
+ // jetzt kommt zwingend ein *, wx steht auf Index von *
+ if (wx == strlen(wild) - 1) return 1; // Ende von wild erreicht und *
+ wx++;
+ while (st[sx] != wild[wx] && wild[wx] != '*') { // bis zum Match nach Stern
+ if (sx == strlen(st) -1) return 0; // Ende von st erreicht ohne Match
+ sx++;
+ }
+ }
+ return 1;
+}
+
+// Von Verbindungs- in Auswahlliste
+void TransferMatchingEntries(void) {
+ int iall, i, match1, match2, np;
+ string h[]; // Einzelparameter
+ PushUndo();
+ SelParam[Quelle] = strupr(SelParam[Quelle]);
+ SelParam[Von] = strupr(SelParam[Von]);
+ while (listall[iall]) {
+ match1 = 0;
+ np = strsplit(h, listall[iall], '\t'); // bisherige Einzelpar. in h[]
+ if ((WildMatch(SelParam[Quelle], h[Quelle]) || WildMatch(SelParam[Quelle], h[Ziel])) &&
+ (WildMatch(SelParam[Von], h[Von]) || WildMatch(SelParam[Von], h[Nach]))
+ ) match1 = 1;
+ match2 = 0;
+ for (i = Nach + 1; i < NrHeader; i++) {
+ if (WildMatch(SelParam[i], h[i]) ) {
+ match2 = 1;
+ }
+ else {
+ match2 = 0;
+ break;
+ }
+ }
+ if (match1 && match2) { // nach break
+ TransferOneEntry(iall);
+ }
+ iall++;
+ }
+ SelAll = -1;
+}
+
+// Lösche alle Verbindungen aus Auswahlliste
+void DelAllEntries(void) {
+ int i;
+ PushUndo();
+ while(listsel[i]) {
+ listsel[i] = "";
+ i++;
+ }
+}
+
+void ChangeOneEntry(int Sel) {
+ int i;
+ PushUndo();
+ for (i = Nach + 1; i < NrHeader; i++) {
+ h[i] = ChangeParam[i];
+ }
+ listsel[Sel] = strjoin(h, '\t');
+}
+
+void EditOneEntry(int Sel) {
+ int i, np;
+ np = strsplit(h, listsel[Sel], '\t');
+ for (i = np; i < NrHeader; i++) h[i] = "";
+ dlgDialog("Editiere Verbindungs-Parameter") {
+ for (i = Nach + 1; i < NrHeader; i++) {
+ ChangeParam[i] = h[i];
+ }
+ for (i = Nach + 1; i < NrHeader; i++) {
+ dlgHBoxLayout {
+ dlgLabel(head[i] + "\t");
+ dlgStringEdit(ChangeParam[i]);
+ }
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("-Abbrechen") dlgReject();
+ dlgPushButton("+OK") {dlgAccept(); ChangeOneEntry(Sel);}
+ }
+ };
+}
+
+void CopyChangeParams(int all) {
+ int i, j;
+ string h[];
+ PushUndo();
+ while (listsel[j]) {
+ strsplit(h, listsel[j], '\t');
+ for (i = Nach + 1; i < NrHeader; i++) {
+ if (ChangeParam[i] != "" || all)
+ h[i] = ChangeParam[i];
+ }
+ listsel[j] = strjoin(h, '\t');
+ j++;
+ }
+}
+
+void ApplyChanges(void) {
+ int j, k;
+ string ls[], la[];
+ PushUndoOben();
+ while (listall[j]) {
+ strsplit(la, listall[j], '\t'); // bisherige Zeile in la[]
+ k = 0;
+ while (listsel[k]) {
+ strsplit(ls, listsel[k], '\t'); // neue Zeile in ls[]
+ if ((la[Quelle] == ls[Quelle] && la[Ziel] == ls[Ziel]) ||
+ (la[Quelle] == ls[Ziel] && la[Ziel] == ls[Quelle])
+ ) { // Match-Zeile gefunden
+ ls[0] = la[0]; // alte Nummer verwenden
+ listall[j] = strjoin(ls, '\t');
+ }
+ k++;
+ }
+ j++;
+ }
+}
+
+// Übertrage Parameter der externen Liste nach listall und lösche die verwendeten aus listsel
+void ApplyChangesOldList(void) {
+ int j, k;
+ string ls[], la[];
+ while (listall[j]) {
+ strsplit(la, listall[j], '\t'); // bisherige Zeile in la[]
+ k = 0;
+ while (listsel[k]) {
+ strsplit(ls, listsel[k], '\t'); // neue Zeile in ls[]
+ if ((la[Quelle] == ls[Quelle] && la[Ziel] == ls[Ziel]) ||
+ (la[Quelle] == ls[Ziel] && la[Ziel] == ls[Quelle])
+ ) { // Match-Zeile gefunden
+ ls[0] = la[0]; // alte Nummer verwenden
+ listall[j] = strjoin(ls, '\t');
+ DelOneEntry(k);
+ break;
+ }
+ k++;
+ }
+ j++;
+ }
+}
+
+int LoadOldListOk(void) {
+ int LoadOk;
+ dlgDialog("Verbindungsliste laden") {
+ dlgHBoxLayout dlgSpacing(400);
+ dlgHBoxLayout {
+ dlgTextView ( "Achtung, wenn Sie eine vorhandene Verbindungsliste laden, "
+ "werden alle bisher definierten Parameter der Verbindungen "
+ "überschrieben, die in der aktuellen und der gespeicherten "
+ "Liste vorhanden sind!\n\n"
+ "Nicht gefundene Verbindungen sind im Auswahlfenster aufgelistet.\n\n"
+ );
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+Abbrechen") dlgReject();
+ dlgPushButton("-Weiter") {LoadOk = 1; dlgAccept();}
+ }
+ };
+ if (LoadOk) return 1;
+ else return 0;
+}
+
+int CancelOk(void) {
+ int CancelOk;
+ dlgDialog("Programm verlassen") {
+ dlgHBoxLayout dlgSpacing(400);
+ dlgHBoxLayout {
+ dlgTextView ( "Wenn Sie das Programm abbrechen, verlieren Sie alle veränderten Parametereinträge!\n\n"
+ "Abbrechen?"
+ );
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+Nein") dlgReject();
+ dlgPushButton("-Ja") {CancelOk = 1; dlgAccept();}
+ }
+ };
+ if (CancelOk) return 1;
+ else return 0;
+}
+
+
+void ApplyOldList(void) {
+ int NrLines;
+ string FileName = dlgFileOpen("Verbindungsliste/Klemmenplan/Kabelplan/Brückenplan wählen", vbdfile, "Klemmenplan-Dateien (*.vbd);;Alle Dateien (*)");
+ if (FileName) {
+ PushUndo();
+ PushUndoOben();
+ DelAllEntries();
+ NrLines = fileread(listsel, FileName);
+ DelOneEntry(0); // Header löschen
+ ApplyChangesOldList();
+ }
+}
+
+void SaveList(void) {
+ int i;
+ schematic(SCH) vbdfile = filesetext(SCH.name, ".vbd");
+ string FileName = dlgFileSave("Speichere Verbindungsliste", vbdfile);
+ if (FileName) {
+ string a[];
+ output(FileName, "wt") {
+ printf ("%s\n", ListHeader);
+ while (listall[i]) {
+ printf("%s\n", listall[i]); // "%s" um Probleme zu vermeiden, wenn listall '%' enthält
+ i++;
+ }
+ }
+ }
+}
+
+void MoveDown(int Sel) {
+ int i;
+ string hi[], lo[], tmp;
+ if (listall[Sel + 1]) {
+ PushUndoOben();
+ while (listsel[i]) listsel[i++] = "";
+ strsplit(hi, listall[Sel + 1], '\t');
+ strsplit(lo, listall[Sel], '\t');
+ tmp = hi[Nummer]; hi[Nummer] = lo[Nummer]; lo[Nummer] = tmp; // vertausche Rang
+ listall[Sel] = strjoin(hi, '\t');
+ listall[Sel + 1] = strjoin(lo, '\t');
+ SelAll = Sel + 1;
+ }
+}
+
+void MoveUp(int Sel) {
+ int i;
+ string hi[], lo[], tmp;
+ if (Sel > 0) {
+ PushUndoOben();
+ while (listsel[i]) listsel[i++] = "";
+ strsplit(hi, listall[Sel], '\t');
+ strsplit(lo, listall[Sel - 1], '\t');
+ tmp = hi[Nummer]; hi[Nummer] = lo[Nummer]; lo[Nummer] = tmp; // vertausche Rang
+ listall[Sel] = strjoin(lo, '\t');
+ listall[Sel - 1] = strjoin(hi, '\t');
+ SelAll = Sel - 1;
+ }
+}
+
+void ChangeSourceDest (int Sel) {
+ string h[], s;
+ if (Sel < 0) return;
+ PushUndoOben();
+ strsplit(h, listall[Sel], '\t');
+ s = h[Quelle]; h[Quelle] = h[Ziel]; h[Ziel] = s;
+ listall[Sel] = strjoin(h, '\t');
+}
+
+void ShowHelp(void) {
+ dlgDialog("Hilfe") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout{
+ dlgVBoxLayout dlgSpacing(600);
+ dlgTextView(HelpText);
+ }
+ dlgHBoxLayout {
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ }
+ };
+}
+
+//*****************************************************
+void ShowUserInterface(void) {
+dlgDialog("Klemmenplan/Kabelplan erstellen - " + Version) {
+ dlgHBoxLayout dlgSpacing(800);
+ dlgGroup("") {
+ dlgLabel("Verbindungsliste");
+ dlgListView(ListHeader, listall, SelAll, SortAll) TransferOneEntry(SelAll);
+ dlgSpacing(10);
+ }
+ dlgGroup("") {
+ dlgLabel("Auswahlliste");
+ dlgListView(ListHeader, listsel, SelConnection, Sort) EditOneEntry(SelConnection);
+ dlgHBoxLayout {
+ dlgPushButton("Undo oben") PullUndoOben();
+ dlgPushButton("Nach oben") MoveUp(SelAll);
+ dlgPushButton("Nach unten") MoveDown(SelAll);
+ dlgPushButton("Quelle <-> Ziel") ChangeSourceDest(SelAll);
+ dlgStretch(1);
+ dlgPushButton("Undo unten") PullUndo();
+ dlgPushButton("Eintrag löschen") DelOneEntry(SelConnection);
+ dlgPushButton("Alle löschen") DelAllEntries();
+ dlgPushButton("Anwenden") ApplyChanges();
+ }
+ }
+
+ dlgSpacing(10);
+ dlgHBoxLayout {
+ dlgGroup("Auswahl-Parameter") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgHBoxLayout {
+ dlgLabel(head[Quelle] + "/" + head[Ziel] + "\t");
+ dlgStringEdit(SelParam[Quelle]);
+ }
+ dlgHBoxLayout {
+ dlgLabel(head[Von] + "/" + head[Nach] + "\t");
+ dlgStringEdit(SelParam[Von]);
+ }
+ dlgGroup("") {
+ }
+ }
+ dlgVBoxLayout {
+ for (i = Nach + 1; i < NrHeader; i++) {
+ dlgHBoxLayout {
+ dlgLabel(head[i] + "\t");
+ dlgStringEdit(SelParam[i]);
+ }
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("Löschen") SetSelParams("");
+ dlgPushButton("Alle *") SetSelParams("*");
+ dlgPushButton("Holen") TransferMatchingEntries();
+ }
+ }
+ }
+ }
+ dlgGroup("Parameter ändern") {
+ for (i = Nach + 1; i < NrHeader; i++) {
+ dlgHBoxLayout {
+ dlgLabel(head[i] + "\t");
+ dlgStringEdit(ChangeParam[i]);
+ }
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("Löschen") SetChangeParams("");
+ dlgPushButton("Alle eintragen") CopyChangeParams(1);
+ dlgPushButton("Alle außer leere") CopyChangeParams(0);
+ }
+ }
+ }
+
+ dlgHBoxLayout {
+ dlgPushButton("&Hilfe") ShowHelp();
+ dlgStretch(1);
+ dlgPushButton("Fehlerliste") ShowErrorList();
+ dlgPushButton("Lade ext. Liste") if (LoadOldListOk()) ApplyOldList();
+ dlgPushButton("-Abbrechen") if (CancelOk()) dlgReject();
+ dlgPushButton("+Speichern") SaveList();
+ }
+ };
+}
+//***************** Main ******************************
+NrHeader = strsplit(head, ListHeader, '\t');
+SetFileNames();
+SetupPinDatabase();
+ReadConnects();
+ChangeList();
+output(errorfile, "wt") printf(ErrCmd + "\n"); // hier sind alle Listen fertig (*.kp$ ohne Parameter-Einträge
+// Oberfläche
+ReadList();
+ShowUserInterface();
+
diff --git a/trunk/ulp/e-makelist.ulp b/trunk/ulp/e-makelist.ulp
new file mode 100644
index 00000000..6ada49aa
--- /dev/null
+++ b/trunk/ulp/e-makelist.ulp
@@ -0,0 +1,285 @@
+// Generiere Liste als EAGLE-Script
+
+string Version = "Listenausgabe Version 1.0";
+
+#require 4.9206
+
+#usage "Erstellen von Listen auf EAGLE-Schaltplanseiten (nicht mit EAGLE Light)\n
"
+
+"Mit diesem ULP erstellen Sie aus den Dateien, die von den Programmen "
+"e-klemmenplan und e-brueckenverwaltung erzeugt wurden, "
+"Listen, die Bestandteil eines Schaltplans sind.
"
+
+"Außerdem können Sie mit diesem Programm Schaltplanseiten ab einer "
+"bestimmten Seite bequem löschen.
"
+
+"Author: support@cadsoft.de"
+
+int NrLines, i, j, np, maxlen[], PrintOff[], xstart, ystart, xtextpos, ypos, size;
+int shnr, linedist, layer, lowmargin, linelength, fieldmarginchar, width, width_head;
+int x_margin, y_margin, xright, MaxSize, linemil, delpage;
+numeric string lines[], head[], item[];
+string FileName, FileTmp, Cmd, s, t, headline, fext, MaxSizeStr, CmdDel;
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Folgende Parameter können vom Benutzer angepasst werden
+// Alle Maße in mil = 1/1000 Zoll; 40 mil ist ca. 1 mm
+fext = ".vbd";
+xstart = 150; // Trennlinien-Abstand vom linken Rand
+xright = 11200; // x-Koordinate für Trennlinie rechts
+ystart = 7750; // y-Koordinate für erste (obere) Trennlinie
+lowmargin = 435; // y-Koordinate für letztmögliche (unterste) Trennlinie
+linedist = 200; // Zeilenabstand
+fieldmarginchar = 2; // zusätzliche Zeichen pro Feld (Abstand)
+size = 140; // Texthöhe (wird intern optimiert)
+width = 7; // Strichstärke für Trennlinien
+width_head = 10; // Strichstärke für Trennlinien der Kopfzeile
+layer = 94; // wenn ein anderer Layer angegeben wird, muss er definiert sein
+///////////////////////////////////////////////////////////////////////////////////////
+
+xtextpos = xstart + size;
+ypos = ystart;
+x_margin = size * fieldmarginchar/2; // Abstand zu Linien in mil
+y_margin = (linedist - size)/2; // Versatz der Linien gegen Text vertikal
+// shnr wird in SetFileNames auf höchste Seitennummer + 1 gesetzt
+
+string HelpText =
+
+"Erstellen von Listen auf EAGLE-Schaltplanseiten (nicht mit EAGLE Light)
"
+
+"Mit diesem ULP erstellen Sie aus den Dateien, die von den Programmen "
+"e-klemmenplan und e-brueckenverwaltung erzeugt wurden, "
+"Listen, die Bestandteil eines Schaltplans sind.
"
+
+"Nach dem Start des Programms wählen Sie, ob Sie eine Liste erstellen "
+"oder eine vorher erstellte Liste ab einer bestimmten Seite löschen wollen.
"
+
+"Liste erstellen
"
+
+"Wählen Sie eine Datei, die Sie vorher mit den oben genannten Programmen erzeugt haben "
+"(*.brk oder *.vbd).
"
+
+"Im Menü links können Sie selektieren, welche Spalten der Datei nicht ausgegeben werden sollen. "
+"Das Programm errechnet den Maximalwert der Textgröße (in mil), damit die Tabelle auf eine "
+"Schaltplanseite passt. "
+"Sie können den Wert innerhalb bestimmter Grenzen im Menü rechts verändern. "
+"Ein Klick auf Liste erzeugen hängt die Liste an den bisherigen Schaltplan an. "
+"Dabei wird auf den neuen Seiten jeweils der Rahmen von Seite 1 des Schaltplans verwendet. "
+"Voraussetzung: er muss am Koordinatennullpunkt platziert sein.
"
+
+"Anpassungen an andere Rahmen können Sie direkt im Programm vornehmen (siehe Kommentare).
"
+
+"Achtung! Alle Maße in mil (40 mil ist ca. 1 mm)
"
+
+"Seiten löschen
"
+
+"Tragen Sie in das Textfeld die Seitennummer ein, ab der (inklusive) die restlichen Seiten "
+"des Schaltplans gelöscht werden sollen, und klicken Sie auf Seiten löschen. "
+"Bestätigen Sie dann die Fragen des Programms alle mit Ja, bis alle Seiten gelöscht sind.
"
+ "Für Elektro-Bauteile empfiehlt es sich, dass Symbol-Pins und Package-Pads gleiche "
+ "Namen haben. Dieses Programm erzeugt ein Package mit identischen Pad-/Pin-Namen, "
+ "falls kein Pin-Name doppelt vorkommt.
"
+ "Starten Sie das Programm im Bibliothekseditor, sobald Sie ein Device angelegt "
+ "und die Symbole mit dem Add-Befehl geholt haben. Es wird ein Package angelegt, "
+ "dessen Name dem des Device entspricht (falls noch nicht vorhanden) und dessen "
+ "Pads entsprechend den Pins benannt sind. Pins und Pads sind mit dem Connect-Befehl "
+ "verbunden.
"
+ "Author: support@cadsoft.de"
+
+string Version = "1.0.2"; // 2012-03-23 Behandlung der Apostrophen in Pin/Pad-Namen berichtig.
+ // 2013-01-25 Bei nur einem Gate den Gate-Namen nicht benutzen um die Pad-Namen zu erzeugen
+string cmd, concmd, s;
+string f;
+string PadName;
+string CurrentDevice;
+int PackagePresent = 0;
+int PADname;
+
+int test = 0;
+
+// Da der ganze String in ' eingeschlossen wird,
+// müssen die Apostrophen verdoppelt werden.
+string addApostroph(string name) { // 2012-03-23
+ string t[];
+ int cnt = strsplit(t, name, '\''); // check Apostroph
+ if (cnt > 1) {
+ name = "";
+ for (int i = 0; i < cnt; i++) {
+ if (i == 0) {
+ if (t[i]) name += t[i];
+ }
+ else if (i) name += "''" + t[i];
+ }
+ }
+ return name;
+}
+
+if (library) {
+ library(L) {
+ f = filename(L.name);
+ f = filesetext(f, "$$$.scr");
+ f = path_scr[0] + '/' + f; // verwende Script-Pfad
+ if (deviceset) {
+ deviceset(DS) {
+ CurrentDevice = DS.name;
+ DS.devices(D) {
+ if (!D.package && CurrentDevice == DS.name) {
+ sprintf(s, "EDIT %s.PAC;\n", DS.name);
+ cmd += s;
+ sprintf(s, "DESCRIPTION 'Dummy';\n");
+ cmd += s;
+ sprintf(s, "GRID MM; CHANGE DRILL 0.5; CHANGE DIAMETER 1.0;\n");
+ cmd += s;
+ sprintf(s, "EDIT %s.DEV;\n", DS.name);
+ concmd += s;
+ sprintf(s, "PAC '%s' '';\n", DS.name);
+ concmd += s;
+ int cntg = 0;
+ DS.gates(G) {
+ cntg++;
+ }
+ DS.gates(G) {
+ string gname = addApostroph(G.name);
+ if (cntg == 1) gname = ""; // 2013-01-25 bei nur einem Gate, nur den Pin-Namen beutzen.
+ G.symbol.pins(P) {
+ PadName = (P.name);
+ sprintf(s, "PAD '%s%s' (%.4f %.4f);\n",
+ gname, addApostroph(PadName),
+ u2mm(P.x),
+ u2mm(P.y)-7.62
+ ); // Pin-Offset im Device in Y-Richtung
+ cmd += s;
+ sprintf(s, "CONNECT '%s.%s' '%s%s';\n",
+ addApostroph(G.name),
+ addApostroph(P.name),
+ gname,
+ addApostroph(PadName)
+ );
+ concmd += s;
+ }
+ }
+ }
+ }
+ }
+ }
+ L.packages(P) {
+ if (CurrentDevice == P.name) PackagePresent = 1;
+ }
+ }
+ cmd += concmd;
+ if (cmd && !PackagePresent) {
+ if (test) {
+ dlgDialog("Check") {
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(500);
+ dlgTextEdit(cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("Abbrechen") { dlgReject(); exit(-1); }
+ }
+ };
+ }
+ output(f, "wtD") printf("%s", cmd); // temporäre Script-Datei erzeugen
+ exit("SCRIPT '"+ f +"'");
+ }
+ else dlgMessageBox("Device hat schon ein Package oder Package mit dem Namen des Device schon vorhanden.", "OK");
+}
+
+else dlgMessageBox("Das ULP kann nur vom Bibliothekseditor aus geladen werden!", "OK");
\ No newline at end of file
diff --git a/trunk/ulp/eagle.bmp b/trunk/ulp/eagle.bmp
new file mode 100644
index 00000000..a016d3a7
Binary files /dev/null and b/trunk/ulp/eagle.bmp differ
diff --git a/trunk/ulp/eagleidfexporter.ulp b/trunk/ulp/eagleidfexporter.ulp
new file mode 100644
index 00000000..864a7c58
--- /dev/null
+++ b/trunk/ulp/eagleidfexporter.ulp
@@ -0,0 +1,2872 @@
+#usage "Generate IDF files from CADSoft Eagle
\n"
+"Run ULP on board file to generate IDF board and library files for import to CAD tools. "
+"Version: 0.1 - Development Started - 12-8-13 "
+"Version: 0.2 - Bug fix and cleanup - 12-21-13 "
+"Version: 0.3 - Added in logic to lookup height if set - 1-29-14 "
+"Version: 0.4 - Added validations on height values to ensure only number values are passed - 2-7-14 "
+"Version: 0.5 - Baseline commit before code style changes - 3-20-14 "
+"Version: 0.6 - Code style Issues addressed - 3-20-14 "
+"Version: 0.7 - Updated component outline bounding box logic - 4-13-14 "
+"Version: 0.8 - Cleanup of unused functions - 5-3-14 "
+"Version: 0.9 - Fixed minor GUI issues related to reset of html table values - 5-6-14 "
+"Version: 0.10 - Added logic for varied heights in packages on board - 5-6-14 "
+"Version: 0.11 - Fixed bug in logic to handle HEIGHT attributes set with numbertext value.- 5-13-14 "
+"Version: 1.0 - Initial production release.- 5-21-14 "
+"Version: 1.1 - Change to consider circles on layer 20 regardless of other lines. Improved arc/circle processing logic. - 9-6-14 "
+"Version: 2.0 - Updated to integrate with SSI IDF site - 3-25-15 "
+"Version: 2.1 - Updates to include banner and links - 3-29-15 "
+"Version: 2.2 - Updates to logic to open links in browser - 4-7-15 "
+"
"
+"Author: marc.battistello@gmail.com"
+
+#require 5.1000
+string version = "2.2"; //ulp version
+
+//vars used for the text dialog
+string TextMessageDialog; //used to store text shown to user
+
+string HeightHtmlTable = "";
+
+string BoardThickness = "1.6"; //mm
+string WireLayer = "20";
+//string DummyHistory[];
+
+string LibraryLookup = "RCL:RESISTOR:TRANSISTOR:PINHEAD:RESISTOR-DIL:SMARTPRJ:C5B2,5A:CAP-WI:POLCAP:ELKO:CON-PTR500:SPECIAL:LED:CAPACITOR-WIMA:CON-WAGO-500:CON-HARTING-ML:ST-ML:CON-ML:CON-LSTB:CON-BERG:CON-SUBD:POLCAP";
+string Libraries[]; //used to hold Libraries
+string PackageOutlines[]; //used to hold outlines of packages
+int PackageCounter = 0; //keeps track of how many entries in packages outline array
+
+string NULL_HEIGHT = "0.000000"; //used for null heights
+
+//web request urls
+string Host = "http://www.simplifiedsolutionsinc.com";
+string Service_port = "8080";
+//string service_port = "80";
+string Static_port = "80";
+string Service_name = "EMN-EMPAdvancedApp/EagleTo3DSSIServlet";
+string Login_name = "EMN-EMPAdvancedApp/LinkLoginServlet";
+string Static_name = "EagleTo3D/";
+string Service_url = Host + ":" + Service_port + "/" + Service_name;
+string Login_url = Host + ":" + Service_port + "/" + Login_name;
+string Static_url = Host + "/" + Static_name;
+
+int useSecondaryMappings = 1;
+int useSuggestionMappings = 1;
+
+//debug flags
+int Debug = 1; //general Debug flag
+
+
+//-----------------------------------------------------------------------------
+// subroutines
+//-----------------------------------------------------------------------------
+
+string itos(int num) {
+ string temp;
+
+ sprintf(temp, "%d", num);
+
+ return temp;
+}
+
+string rtos(real num) {
+ string temp;
+
+ sprintf(temp, "%f", num);
+
+ return temp;
+}
+
+int IsInt(string str) {
+ //returns 1 if int. 0 if not string
+
+ //first check to make sure its not "0" which Is the fail mode for the cast
+ if (str == "0") {
+ return 1;
+ } else if (strtol(str) != 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+} //end IsInt
+
+int IsReal(string str) {
+ //returns 1 if int. 0 if not string
+
+ //first check to make sure its not "0.0" which Is the fail mode for the cast
+ if (str == "0.0") {
+ return 1;
+ } else if (strtod(str) != 0.0) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+} //end IsInt
+
+int CompareReals(real n1, real n2) {
+ string n1s;
+ string n2s;
+
+ sprintf(n1s, "%1.2f", n1);
+ sprintf(n2s, "%1.2f", n2);
+
+ if (n1s == n2s) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+string GetBoardThickness() {
+ //make sure there Is value for board thickness
+ if (BoardThickness == "") {
+ BoardThickness = "1.6";
+ }
+
+ //check if first char Is decimal and if it Is then add 0
+ char dec = '.';
+ int pos = strchr(BoardThickness, dec);
+
+ if (pos == 0) {
+ BoardThickness = "0" + BoardThickness;
+ }
+
+ //return form value
+ return BoardThickness;
+} //end func
+
+string GetBoardUnits() {
+
+ /*
+ GRID_UNIT_MIC microns
+ GRID_UNIT_MM millimeter
+ GRID_UNIT_MIL mil
+ GRID_UNIT_INCH inch
+ */
+
+ /* force to mm
+ string unitsMap[] = { "MIC", "MM", "MIL", "IN" };
+
+ board(B) {
+ return unitsMap[ B.grid.unit ];
+ }
+ */
+
+ return "MM";
+}
+
+real BackConvertDimensions(real mmDim) {
+ real boardDim;
+ int unitsInt;
+
+ //get board dimensions
+ board(B)
+ {
+ unitsInt = B.grid.unit;
+ }
+
+ /*
+ GRID_UNIT_MIC microns
+ GRID_UNIT_MM millimeter
+ GRID_UNIT_MIL mil
+ GRID_UNIT_INCH inch
+ */
+
+ switch (unitsInt) {
+ case 0:
+ //micron
+ boardDim = mmDim * 1000;
+ break;
+ case 1:
+ //mm
+ boardDim = mmDim;
+ break;
+ case 2:
+ //mil
+ boardDim = mmDim * 39.3700787;
+ break;
+ case 3:
+ //inch
+ boardDim = mmDim * 0.0393701;
+ break;
+
+ } //end switch
+
+ //string unitsMap[] = { "MIC", "MM", "MIL", "IN" };
+
+ //dlgMessageBox( "MM:" + rtos( mmDim ) + ", " + unitsMap[ unitsInt ] + ": " + rtos( boardDim ) );
+
+ return boardDim;
+
+} //end func
+
+real GetDimInBoardUnits(int dim) {
+ int unitsInt;
+ real convDim;
+
+ /* removed for force to mm
+ board(B) {
+ unitsInt = B.grid.unit;
+ }
+
+ switch( unitsInt ){
+ case 0:
+ convDim = u2mic( dim );
+ break;
+ case 1:
+ convDim = u2mm( dim );
+ break;
+ case 2:
+ convDim = u2mil( dim );
+ break;
+ case 3:
+ convDim = u2inch( dim );
+ break;
+
+ } //end switch
+ */
+
+ convDim = u2mm(dim);
+
+ return convDim;
+} //end func
+
+real GetTolerance() {
+ int unitsInt;
+ real Tolerance;
+
+ /* removed to force to mm
+ board(B) {
+ unitsInt = B.grid.unit;
+ }
+
+ switch( unitsInt ){
+ case 0:
+ Tolerance = 100;
+ break;
+ case 1:
+ Tolerance = 0.05;
+ break;
+ case 2:
+ Tolerance = 3.9;
+ break;
+ case 3:
+ Tolerance = 0.004;
+ break;
+
+ } //end switch
+ */
+
+ Tolerance = 0.05;
+
+ return Tolerance;
+} //end func
+
+string GetBoardFilename() {
+ board(BRD)
+ {
+ return filename(BRD.name);
+ } //end board
+}
+
+string GetBoardDir() {
+
+ board(BRD)
+ {
+ return filedir(BRD.name);
+ } //end board
+}
+
+string GetBoardPath() {
+
+ return GetBoardDir() + GetBoardFilename();
+
+}
+
+string PadBRs( int count ){
+
+ string padding = "";
+
+ for( int i; i < count; i++ ){
+
+
+ padding += " ";
+ }
+
+ return padding;
+}
+
+int IsWindows() {
+ //Returns 1, if EAGLE Is running under Windows (0 for Linux/Mac)
+ if ((strsub(argv[0], 0, 1) == "/") && (strsub(argv[0], 0, 2) != "//"))
+ return 0;
+
+ return 1;
+} //end sub
+
+
+int IsMac(){
+ if( (strsub( OS_SIGNATURE, 0, 3 ) == "Mac") || (strsub( OS_SIGNATURE, 0, 3 ) == "MAC") )
+ return 1;
+
+ return 0;
+
+}
+
+void LaunchBrowser( string url ){
+
+ string launchCmd = "";
+
+ if( IsWindows() ){
+ launchCmd = "explorer \"" + url + "\"";
+ }
+ else if( IsMac() ){
+ launchCmd = "open " + url;
+ }
+ else{
+ //assume all others linux
+ //if you are on linux then change this line if the buttons dont work
+ launchCmd = "xdg-open " + url;
+ }
+
+
+ //run system command
+ system( launchCmd );
+ } //end launch browser
+
+string GetFileSeperator() {
+
+ if (IsWindows()) {
+ return "\\";
+ } else {
+ return "/";
+ }
+
+}
+
+// Removes carriage returns from a string and replaces with
+string RemoveCarriageReturns(string dirtyString) {
+
+ string cleanedString;
+
+ for (int i = 0; dirtyString[i]; ++i) {
+ if (dirtyString[i] == '\n') {
+ cleanedString += " ";
+ } else {
+ cleanedString += dirtyString[i];
+ } //end if-else
+ } //end for
+
+ return cleanedString;
+} //end sub
+
+// Removes spaces in string and replaces with
+string RemoveSpaces(string dirtyString) {
+
+ string cleanedString;
+
+ for (int i = 0; dirtyString[i]; ++i) {
+ if (dirtyString[i] == ' ') {
+ cleanedString += "";
+ } else {
+ cleanedString += dirtyString[i];
+ } //end if-else
+ } //end for
+
+ return cleanedString;
+} //end sub
+
+string CleanString(string dirtyString) {
+
+ dirtyString = strupr(dirtyString);
+
+ string cleanedString;
+
+ for (int i = 0; dirtyString[i]; ++i) {
+ if (dirtyString[i] == '0' || dirtyString[i] == '1'
+ || dirtyString[i] == '2' || dirtyString[i] == '3'
+ || dirtyString[i] == '4' || dirtyString[i] == '5'
+ || dirtyString[i] == '6' || dirtyString[i] == '7'
+ || dirtyString[i] == '8' || dirtyString[i] == '9'
+ || dirtyString[i] == 'A' || dirtyString[i] == 'B'
+ || dirtyString[i] == 'C' || dirtyString[i] == 'D'
+ || dirtyString[i] == 'E' || dirtyString[i] == 'F'
+ || dirtyString[i] == 'G' || dirtyString[i] == 'H'
+ || dirtyString[i] == 'I' || dirtyString[i] == 'J'
+ || dirtyString[i] == 'K' || dirtyString[i] == 'L'
+ || dirtyString[i] == 'M' || dirtyString[i] == 'N'
+ || dirtyString[i] == 'O' || dirtyString[i] == 'P'
+ || dirtyString[i] == 'Q' || dirtyString[i] == 'R'
+ || dirtyString[i] == 'S' || dirtyString[i] == 'T'
+ || dirtyString[i] == 'U' || dirtyString[i] == 'V'
+ || dirtyString[i] == 'W' || dirtyString[i] == 'X'
+ || dirtyString[i] == 'Y' || dirtyString[i] == 'Z'
+ || dirtyString[i] == '_' || dirtyString[i] == '-'
+ || dirtyString[i] == ' ') {
+
+ cleanedString += dirtyString[i];
+ } else {
+ cleanedString += "_";
+ } //end if-else
+ } //end for
+
+ return cleanedString;
+} //end sub
+
+// Removes spaces in string and replaces with
+string ReplaceSpaceWithUnderscore(string dirtyString) {
+
+ string cleanedString;
+
+ for (int i = 0; dirtyString[i]; ++i) {
+ if (dirtyString[i] == ' ') {
+ cleanedString += "_";
+ } else {
+ cleanedString += dirtyString[i];
+ } //end if-else
+ } //end for
+
+ return cleanedString;
+} //end sub
+
+// 0-9, letters, dashes, and underscores are always safe.
+
+// Reads in file and converts it to be used in a html form submit
+string ParseFileToHtmlForm(string filePath) {
+
+ string fileContents;
+
+ int in = fileread(fileContents, filePath);
+
+ fileContents = RemoveCarriageReturns(fileContents);
+
+ fileContents = RemoveSpaces(fileContents);
+
+ //dlgMessageBox( "File input value:" + in );
+
+ return fileContents;
+} //end sub
+
+string ParseStringToHtmlForm(string input) {
+
+ return RemoveSpaces(RemoveCarriageReturns(input));
+
+} //end sub
+
+//this function Is used to Get the html to show in the UI.
+//it uses a fixed header and footer and the call sets the body.
+string GetHtmlText(string body) {
+
+ string os;
+
+ //build header html
+ string htmlHeader =
+ "
\
+
\
+
\
+
\
+
\
+
EAGLE IDF Exporter
\
+
\
+
\
+
\
+
";
+
+ string htmlFooter = ""; //footer will be built later including OS padding
+
+ //detect if windows or other
+ if (IsWindows()) {
+ os = "Windows";
+ } else {
+ os = "Mac/Linux";
+ }
+
+ //build footer and include OS specific padding for formatting.
+ if (IsWindows()) {
+ htmlFooter += "
( ULP Version: "
+ + version + "\t, OS: " + os
+ + " )
\
+
\
+
\
+
\
+
\
+
";
+
+ return htmlHeader + "
" + body + "
"
+ + htmlFooter;
+} //end sub
+
+real GetDistBetweenPts(real x1, real y1, real x2, real y2) {
+ //dist = sqrt( ( x2 - x1 )^2 + ( y2 - y1 )^2 )
+
+ return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2));
+
+} //end sub
+
+void WriteToFile(string filePath, string fileContents) {
+
+ output(filePath, "wt")
+ {
+ printf(fileContents);
+ }
+} //end sub
+
+
+string GetElementHeightAttr( UL_ELEMENT E ){
+ /* checks for attribute named HEIGHT.
+ * casts height string to real to handle any invalid values. sets to 0 if not value.
+ * returns height
+ */
+
+ string height = NULL_HEIGHT;
+
+ //check for element height
+ E.attributes(A)
+ {
+ if (strupr(A.name) == "HEIGHT") {
+ if ( strtod(A.value) <= 0.0) {
+ height = NULL_HEIGHT;
+ } else {
+ height = rtos( strtod( A.value ) );
+ } //end if-else
+ } //end if
+ } //end loop thru attributes
+
+ return height;
+} //end sub
+
+//-----------------------------------------------------------------------------
+// emp subroutines
+//-----------------------------------------------------------------------------
+
+
+
+
+
+string GetDateTime() {
+
+ //time for date.time in header
+ int now = time();
+ string dateStr;
+
+ sprintf(dateStr, "%d/%02d/%02d.%02d:%02d:%02d", t2year(now), t2month(now),
+ t2day(now), t2hour(now), t2minute(now), t2second(now));
+
+ return dateStr;
+
+} //end sub
+
+//looks up package outline and generates text for .electical section entry
+string GetComponentOutline(string footprint, string altname, string packageName,
+ string units, string height) {
+
+ //package array = [ { packname1, maxX, maxY, minX, minY },
+ // { packname2, maxX, maxY, minX, minY }
+ // ]
+
+ //board->Library->Package->Wires
+
+ int foundPackage = 0;
+
+ //lookup package name in array
+ string packageNameLookup = lookup(PackageOutlines, packageName, 0);
+
+ //check if found in lookup. if not then generate and put in array
+ if (packageNameLookup == "") {
+ //if package not in lookup then generate it
+
+ //init max/min values
+ real maxX = 0, maxY = 0, minX = 0, minY = 0;
+
+ //loop thru all Libraries to find packagename
+ board(B)
+ {
+
+ //go into library
+ B.libraries(LBR)
+ {
+
+ //loop thru packages in library
+ LBR.packages(P)
+ {
+ //if package name matches the one we are looking for then process it
+ if (P.name == packageName) {
+ //check min/ax for each of
+ //circles() UL_CIRCLE - C.x, C.y, C.radius, C.width)
+ //holes() UL_HOLE
+ //polygons() UL_POLYGON -> wires()
+ //rectangles() UL_RECTANGLE - R.x1, R.y1, R.x2, R.y2);
+ //wires() UL_WIRE
+
+ //set found package flag
+ foundPackage = 1;
+
+ //used to capture first loop of data
+ int loopCounter = 0;
+ real w2; //holds 1/2 of width
+
+ //loop thru wires and Get max/min x/y
+ //do wires first to take care of loopCounter == 0 case
+ P.wires(W)
+ {
+ //get first data point
+ if (loopCounter == 0) {
+ w2 = W.width / 2;
+ minX = GetDimInBoardUnits(
+ min(W.x1 - w2, W.x2 - w2));
+ minY = GetDimInBoardUnits(
+ min(W.y1 - w2, W.y2 - w2));
+ maxX = GetDimInBoardUnits(
+ max(W.x1 + w2, W.x2 + w2));
+ maxY = GetDimInBoardUnits(
+ max(W.y1 + w2, W.y2 + w2));
+ }
+
+ if (W.arc) {
+ w2 = W.width / 2;
+ if (W.arc.angle2 > 360)
+ maxX = max(maxX,
+ GetDimInBoardUnits(
+ W.arc.xc + W.arc.radius));
+ else if (((W.arc.angle1 < 90)
+ && (W.arc.angle2 > 90))
+ || (W.arc.angle2 > 450))
+ maxY = max(maxY,
+ GetDimInBoardUnits(
+ W.arc.yc + W.arc.radius
+ + w2));
+ else if (((W.arc.angle1 < 180)
+ && (W.arc.angle2 > 180))
+ || (W.arc.angle2 > 540))
+ minX = min(minX,
+ GetDimInBoardUnits(
+ W.arc.xc - W.arc.radius
+ - w2));
+ else if (((W.arc.angle1 < 270)
+ && (W.arc.angle2 > 270))
+ || (W.arc.angle2 > 630))
+ minY = min(minY,
+ GetDimInBoardUnits(
+ W.arc.yc - W.arc.radius
+ - w2));
+ }
+ else {
+ //handle non arc wires
+ minX = min(minX, GetDimInBoardUnits(W.x1));
+ minY = min(minY, GetDimInBoardUnits(W.y1));
+ maxX = max(maxX, GetDimInBoardUnits(W.x1));
+ maxY = max(maxY, GetDimInBoardUnits(W.y1));
+ } //end if-else
+
+ loopCounter++;
+ } //end wires
+
+ //UpdateBBoxBox(C.x - C.radius - w2, C.y - C.radius - w2, C.x + C.radius + w2, C.y + C.radius + w2);
+ // xmin, ymin, xmax, ymax
+ P.circles(C)
+ {
+ w2 = C.width / 2;
+ minX = min(minX,
+ GetDimInBoardUnits(C.x - C.radius - w2));
+ minY = min(minY,
+ GetDimInBoardUnits(C.y - C.radius - w2));
+ maxX = max(maxX,
+ GetDimInBoardUnits(C.x + C.radius + w2));
+ maxY = max(maxY,
+ GetDimInBoardUnits(C.y + C.radius + w2));
+
+ loopCounter++;
+ } //end circles
+
+ //P.holes(){} - Not required. These are solder masks
+
+ P.polygons(POLY)
+ {
+ POLY.wires(PW)
+ {
+ minX = min(minX, GetDimInBoardUnits(PW.x1));
+ minY = min(minY, GetDimInBoardUnits(PW.y1));
+ maxX = max(maxX, GetDimInBoardUnits(PW.x1));
+ maxY = max(maxY, GetDimInBoardUnits(PW.y1));
+ loopCounter++;
+ } //end wires in polygon
+ } //end polgons
+
+ P.rectangles(R)
+ {
+ minX = min(minX,
+ min(GetDimInBoardUnits(R.x1),
+ GetDimInBoardUnits(R.x2)));
+ minY = min(minY,
+ min(GetDimInBoardUnits(R.y1),
+ GetDimInBoardUnits(R.y2)));
+ maxX = max(maxX,
+ max(GetDimInBoardUnits(R.x1),
+ GetDimInBoardUnits(R.x2)));
+ maxY = max(maxY,
+ max(GetDimInBoardUnits(R.y1),
+ GetDimInBoardUnits(R.y2)));
+
+ loopCounter++;
+ } //end rectangles
+
+ //break out of loop since match found
+ break;
+
+ } //end if for package name match
+ } //end packages loop
+ } //end Libraries loop
+ } //end board loop
+
+ //make sure found match. if not then put in default values
+ string temp;
+
+ if (foundPackage) {
+ //load to array
+ sprintf(temp, "%s\t%f\t%f\t%f\t%f", packageName, maxX, maxY, minX,
+ minY);
+
+ } else {
+ sprintf(temp, "%s\t%f\t%f\t%f\t%f", packageName, maxX, maxY, minX,
+ minY);
+ } //end if-else for found package check
+
+ //add data to package outline so it can be reused in future
+ PackageOutlines[PackageCounter] = temp;
+
+ PackageCounter++;
+ } //end if for lookup check
+
+ //generate outline data. first line is footpring, name, and units
+ string outline = footprint + " " + altname + " " + units;
+
+ //set default height based on units
+ if (units == "MM") {
+ outline += " " + height + "\n";
+
+ //check if height set. if not set to 1.0
+ /*if (height == "1.0") {
+ outline += " 1.00\n";
+ }
+ else {
+ outline += " " + height + "\n";
+ }*/
+ }
+ /*else if (units == "THOU") {
+ //check if
+ if (height == "0.0") {
+ outline += " 39.37\n";
+ }
+ else {
+ outline += " " + height + "\n";
+ }
+ }
+ */
+ else {
+ //treat as MM
+ //check if
+ if (height == "1.0") {
+ outline += " 1.00\n";
+ } else {
+ outline += " " + height + "\n";
+ }
+ } //end if-else
+
+ //map in max/min data
+ string maxX = lookup(PackageOutlines, packageName, 1);
+ string maxY = lookup(PackageOutlines, packageName, 2);
+
+ string minX = lookup(PackageOutlines, packageName, 3);
+ string minY = lookup(PackageOutlines, packageName, 4);
+
+ /*rectangle based on max/min values. start in upper left and move clockwise
+ 0 minX maxY
+ 0 maxX maxY
+ 0 maxX minY
+ 0 minX minY
+ 0 minX maxY
+ */
+
+ //if max/min are all zeros then put in 1x1 block
+ if (maxX == "0.000000" && maxY == "0.000000" && minX == "0.000000"
+ && minX == "0.000000") {
+ outline += "0 1.00 -1.00 0.0\n" + "0 -1.00 -1.00 0.0\n"
+ + "0 -1.00 1.00 0.0\n" + "0 1.00 1.00 0.0\n"
+ + "0 1.00 -1.00 0.0\n";
+ }
+ //if they are all the same they also set in 1x1 block so that something is shown
+ else if (maxX == minX || maxY == minY) {
+ outline += "0 1.00 -1.00 0.0\n" + "0 -1.00 -1.00 0.0\n"
+ + "0 -1.00 1.00 0.0\n" + "0 1.00 1.00 0.0\n"
+ + "0 1.00 -1.00 0.0\n";
+ }
+ //otherwise actual coords provided. use those in output
+ else {
+ outline += "0 " + minX + " " + maxY + " 0.0\n" + "0 " + maxX
+ + " " + maxY + " 0.0\n" + "0 " + maxX + " " + minY
+ + " 0.0\n" + "0 " + minX + " " + minY + " 0.0\n"
+ + "0 " + minX + " " + maxY + " 0.0\n";
+ } //end if-else
+
+ return outline;
+} //end sub
+
+string GetEmpHeader() {
+ /*
+ .HEADER
+ LIBRARY_FILE 3.0 "Commend International >generate_3d_data_v10-5_MJB.ulp V0.9<" 2012/03/21.12:23:09 1
+ .END_HEADER
+ */
+
+ return ".HEADER\n" + "LIBRARY_FILE 3.0 \"Eagle IDF Exporter " + version
+ + "\" " + GetDateTime() + "\n" + ".END_HEADER\n";
+
+} //end sub
+
+string GetEmpElectrical() {
+ /*
+ .ELECTRICAL
+ TSSOP16 NOREFDES MM 4876.80
+ 0 -2.51 -2.28 0
+ 0 2.51 -2.28 0
+ 0 2.51 2.28 0
+ 0 -2.51 2.28 0
+ 0 -2.51 -2.28 0
+ .END_ELECTRICAL
+ */
+
+ string electricalSection;
+
+ string footprint;
+ string altname;
+ string height = NULL_HEIGHT;
+
+ string LibraryLookup;
+
+ string components[];
+
+ string component;
+
+ //loop thru elements on board
+ board(BRD)
+ {
+
+ int i = 0;
+
+ BRD.elements(E)
+ {
+
+ height = NULL_HEIGHT;
+
+ //check if library in lookup
+ LibraryLookup = lookup(Libraries, strupr(E.package.library), 0);
+
+ //set footprint and altname based on logic
+ if (LibraryLookup != "") {
+ footprint = E.package.name;
+ altname = E.package.name;
+
+ //add comment to emn for debuggin
+ //placementSection += "#Resistor or rcl library found\n";
+ } else if (E.value != "") {
+ altname = E.value;
+ footprint = E.package.name;
+
+ //add comment to emn for debuggin
+ //placementSection += "#E.value present\n";
+ } else {
+ //if library Is not in list and the E.value Is blank then concat refid and package name
+ altname = E.name + "_" + E.package.name;
+ footprint = E.package.name;
+
+ //add comment to emn for debuggin
+ //placementSection += "#Fallback logic applied. Not res/rcl and E.value not found.\n";
+ }
+
+ altname = CleanString(altname);
+ footprint = CleanString(footprint);
+
+ //check for element height
+ /*
+ E.attributes(A)
+ {
+ if (strupr(A.name) == "HEIGHT") {
+
+ if (strtod(A.value) < 0) {
+ height = "0.000000";
+ } else {
+ height = rtos(strtod(A.value));
+ } //end if-else
+
+ } //end if
+ } //end loop thru attributes
+ */
+
+ //check if height set for element. if not set then set to NULL_HEIGHT
+ height = GetElementHeightAttr( E );
+
+ //add component to height lookup table
+ HeightHtmlTable = HeightHtmlTable + "
" + E.name
+ + "
" + altname + "
" + E.package.name
+ + "
";
+
+ //if height is not set then set to default
+ if (height == NULL_HEIGHT) {
+ height = "1.0"; //set to value of 1.0
+ HeightHtmlTable = HeightHtmlTable + "
Generating data complete: A session to map your components with our 3D database is ready.
\
+ The picture shows your board and components that could be mapped automatically. \
+
\
+
\
+
" + thumbnailImg + " Important: Automatic component mapping works only with the original EAGLE Library. Components shown in red can be mapped manually.
\
+
\
+ " + complete3DDesignLink + " to complete the component mapping manually \
+
\
+
Use of our IDF-to-3D tool is free
\
+
Generate a 3D PDF of your 3D Board Assembly at no cost
\
+
Incorporate additional 3D Models to your design by using our IDF-to-3D model library and 3D STEP Model integration tool
\
+
\
+ If satisfied with your 3D image:
\
+ " + pdf3dLink + " to open a 3D PDF (Free)
\
+
\
+
\
+
" );
+
+ //update display
+ dlgRedisplay();
+
+ break;
+ }
+ else{
+ TextMessageDialog = GetHtmlText( "There was an error in your request. Please try submit again. \
+ If error persists contact support. \
+ Contact Support \
+ Error Code:" + neterror() + " - Unable to parse xml response \
+ XML Response:" + postResponse );
+ dlgRedisplay();
+
+ //dlgMessageBox( postResponse );
+
+ break;
+ }
+
+ //this is needed to update the text display
+ dlgRedisplay();
+
+ }
+ else{
+ //handle error in netpost
+ TextMessageDialog = GetHtmlText( "We were unable to complete your request at this time. Please try submit again. \
+ If error persists contact support. \
+ Contact Support \
+ Error Code:" + neterror() + " Post Response:" + postResponse );
+
+ dlgRedisplay();
+
+ break;
+ } //end if-else
+ }
+
+ } //end for
+
+
+ //alert user to job success
+ if( jobCompleted ){
+ dlgMessageBox( "Your job is complete" );
+ }
+ else{
+ dlgMessageBox( "Your job ended in error\n Job Status: " + jobStatus );
+
+ TextMessageDialog = GetHtmlText( "There was an error in your request. Please try submit again. \
+ If error persists contact support. \
+ Contact Support \
+ Error Code:" + neterror() + "" );
+ //force text view to update
+ dlgRedisplay();
+ } //end if-else
+
+ */
+
+ } //end sub
+
+//main function to generate IDF fils
+void GenerateEmnEmpFiles() {
+
+ //update user now as the post will take some time to start
+ TextMessageDialog = GetHtmlText(
+ "IDF File generation in process.");
+
+ HeightHtmlTable = ""; //reset
+
+ //refresh display to show message
+ dlgRedisplay();
+
+ //get board name
+ string boardName;
+ string boardDir;
+
+ board(BRD)
+ {
+ boardName = filename(BRD.name);
+
+ boardDir = filedir(BRD.name);
+ } //end board
+
+ //get emn and emp strings
+ string emnData = GenerateEmn();
+ string empData = GenerateEmp();
+
+ //write strings to files
+ string dirName;
+ dirName = dlgDirectory("Select a directory to write IDF files to:",
+ boardDir);
+
+ //show path to user
+ dlgMessageBox(
+ "Writing IDF Files: " + dirName + GetFileSeperator()
+ + filesetext(boardName, ".emn"));
+
+ output(dirName + GetFileSeperator() + filesetext(boardName, ".emn"), "wt")
+ {
+ printf(emnData);
+ }
+
+ output(dirName + GetFileSeperator() + filesetext(boardName, ".emp"), "wt")
+ {
+ printf(empData);
+ }
+
+ //complete height table
+ HeightHtmlTable =
+ "The table below shows the components placed in the emn/emp files. \
+ The height field in the table indicates an extrusion height used in generating the components on the 3D model. \
+ A default value is set if a value is not set and is indicated in yellow. The values are defined as HEIGHT attribute values and can be updated in the board file. \
+ Heights are set at the element level and can vary by placement. This may cause unexpected behavior if you only update a single component in the file. \
+
Ref. ID
Alt. Name
Package Name
Height
"
+ + HeightHtmlTable + "
";
+ //
Ref. ID
Alt. Name
Package Name
Height
" + HeightHtmlTable + "
";
+
+ TextMessageDialog = GetHtmlText(
+ "IDF Files written successfully to "
+ + dirName + "
" + HeightHtmlTable);
+} //end sub
+
+void LoadLibraries() {
+
+ int libraryCount = 0;
+
+ //load library string in to Libraries array
+ libraryCount = strsplit(Libraries, LibraryLookup, ':');
+
+} //end sub
+
+string GetHomepageBanner(){
+ string temp;
+ //get banner along with version and OS data to help with support and detect unsupportedconfigs for future releases
+ string url = "https://www.simplifiedsolutionsinc.com/EagleTo3D/eagle_to_3d_ssi_banner.php?os=" + OS_SIGNATURE + "&v=" + version;
+
+ if( netget( temp, url) >= 0 ){
+ //pass
+ return temp;
+ }
+ else{
+ //fail
+ return "";
+ } //end if-else
+
+ }
+
+string GetHomepageLinks(){
+ string temp;
+ string url = "https://www.simplifiedsolutionsinc.com/EagleTo3D/eagle_to_3d_ssi_bullets.php";
+
+ if( netget( temp, url) >= 0 ){
+ //pass
+ return temp;
+ }
+ else{
+ //fail
+ return "";
+ } //end if-else
+
+ }
+
+
+string RunNetworkTests(){
+ /*
+ 1. Check internet
+ 2. Check SSI site
+ 3. Check SSI site with port
+ */
+
+ string temp = "";
+ string internetSite = "http://www.google.com/";
+ int internetSiteResult = 0;
+ string internetSiteError = "";
+ string internetSiteTroubleshootMsg = "";
+
+ string ssiSite = "https://www.simplifiedsolutionsinc.com/";
+ int ssiSiteResult = 0;
+ string ssiSiteError = "";
+ string ssiSiteTroubleshootMsg = "";
+
+ string ssiWithPortSite = "http://www.simplifiedsolutionsinc.com:8080/";
+ int ssiWithPortSiteResult = 0;
+ string ssiWithPortSiteError = "";
+ string ssiWithPortSiteTroubleshootMsg = "";
+
+
+ if( netget( temp, internetSite ) >= 0 ){
+ //pass
+ internetSiteResult = 1;
+ }
+ else{
+ //fail
+ internetSiteResult = 0;
+ internetSiteError = neterror();
+ internetSiteTroubleshootMsg = "We are unable to reach the internet. Please verify your internet connectivity. If you have an internet proxy please configure it under Help->Check for Update->Configure in the Eagle Control Panel window before running the ULP";
+ } //end if-else
+
+
+ if( netget( temp, ssiSite ) >= 0 ){
+ //pass
+ ssiSiteResult = 1;
+ }
+ else{
+ //fail
+ ssiSiteResult = 0;
+ ssiSiteError = neterror();
+ ssiSiteTroubleshootMsg = "We are unable to reach the internet. Please verify your internet connectivity. If you have an internet proxy please configure it under Help->Check for Update->Configure in the Eagle Control Panel window before running the ULP";
+ } //end if-else
+
+ if( netget( temp, ssiWithPortSite ) >= 0 ){
+ //pass
+ ssiWithPortSiteResult = 1;
+ }
+ else{
+ //fail
+ ssiWithPortSiteResult = 0;
+ ssiWithPortSiteError = neterror();
+ ssiWithPortSiteTroubleshootMsg = "We are unable to reach the Simplified Solutions site at port 8080. Please verify your internet connectivity. You may need to request your firewall rules be opened for port 8080.";
+ } //end if-else
+
+
+ //check results of tests
+ if( internetSiteResult && ssiSiteResult && ssiWithPortSiteResult ){
+ return "PASS";
+ }
+ else{
+ return internetSiteError + ":" + internetSiteTroubleshootMsg + ";";
+ }
+
+ }
+
+
+//-----------------------------------------------------------------------------
+// main section
+//-----------------------------------------------------------------------------
+
+void main() {
+
+ //check to make sure board Is loaded
+ if (!board) {
+ dlgMessageBox(
+ usage
+ + "ERROR: No board!
\nThis program can only work in the layout editor.
Click the \"Generate IDF Files\" button to save IDF files to your computer. Import the IDF files into a Mechanical CAD to view components in \"block\" form
\
+
Click the \"Build 3D PCB\" button to utilize IDF-to-3D to build a 3D PCB of your active .brd file. The 3D PCB will contain accurate 3D component geometry. STEP files of the 3D PCBs can be downloaded after purchasing a subscription to IDF-to-3D
\
+
Click the \"Login to IDF-to-3D\" button to continue working on an existing IDF-to-3D session.
\
+ <\ol> \
+ \
+ " + homepageLinks +
+ "
\
+
\
+ \
+
\
+
";
+
+ //set initial text view content
+ TextMessageDialog = GetHtmlText(startHTML);
+
+ //show dialog to user
+int mainDlgResult = dlgDialog( "Eagle IDF Exporter" ) {
+ //main layout
+ dlgVBoxLayout {
+
+ //set width by creating a spacing hbox to drive width
+ if( IsWindows() ) {
+ //windows
+ dlgHBoxLayout dlgSpacing( 800 );//sets width
+ }
+ else {
+ //mac/linux
+ dlgHBoxLayout dlgSpacing( 825 );//sets width
+ } //end if-else
+
+ //set height and text view
+ dlgHBoxLayout {
+ dlgTextView( TextMessageDialog ); //text view. holds html
+
+ if( IsWindows() ) {
+ //windows
+ dlgVBoxLayout dlgSpacing( 475 );//sets height
+ }
+ else {
+ //mac/linux
+ dlgVBoxLayout dlgSpacing( 500 );//sets height
+ } //end if-else
+ } //end box layout
+
+ //add options for IDF export
+ dlgHBoxLayout {
+
+ dlgLabel("Layer for wires (Default=20): ");
+
+ dlgStringEdit( WireLayer );
+
+ dlgLabel("Board Thickness (MM): ");
+
+ dlgStringEdit( BoardThickness );
+
+ } //end box layout
+
+ //buttons to submit and exit
+ dlgHBoxLayout {
+ dlgPushButton( "Generate IDF Files" ) {
+
+ //submit data to idf site
+ GenerateEmnEmpFiles();
+ } //end button
+
+ dlgPushButton( "Build 3D PCB" ) {
+
+ //submit data to idf site
+ SubmitFormData();
+ } //end button
+
+ dlgPushButton( "Login to IDF-to-3D" ) {
+
+ LaunchBrowser( Login_url );
+ } //end button
+
+ dlgPushButton( "Exit" ) dlgReject();
+ } //end box layout
+ } //end v box layout
+}; //end mainDlgResult
+
+} //end main
diff --git a/trunk/ulp/edit-used-dev-pac-sym.ulp b/trunk/ulp/edit-used-dev-pac-sym.ulp
new file mode 100644
index 00000000..0a78c96f
--- /dev/null
+++ b/trunk/ulp/edit-used-dev-pac-sym.ulp
@@ -0,0 +1,247 @@
+#usage "Offers a selection to open (one of) the respective Library Editor window(s) of the currently edited DEVice/PACkage/SYMbol.
"
+ "It is also possible to edit a DEVice, PACkage, or SYMbol from Schematic or Board directly.
"
+ "Example: "
+ "RUN edit-used-dev-pac-sym "
+ "RUN edit-used-dev-pac-sym partname gatename "
+ "RUN edit-used-dev-pac-sym partname @ "
+ "If the Device consits of one Gate only, use the option '@' for the gatename. "
+ "In case of using @ for a device with more than one Gate, the first Gate used by the Device will be opened.
"
+ "Attention: If the used Library is not available in the given path, see - Options - Directory - Library - in the Control Panel, "
+ "a new Schematic/Bord with the Device/Symbole/Package name will be opened! "
+ "Author: support@cadsoft.de
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+
+string Help = "Öffnet in der Bibliothek das Editorfenster das mit dem gerade editierten DEVice/SYMbol/PACkage verknüpft ist.
" +
+ "Vom Schaltplan bzw. Board muss es mit den Optionen Bauteilname Gatename aufgerufen werden.
" +
+ "Beispiel: " +
+ "RUN edit-used-dev-pac-sym " +
+ "RUN edit-used-dev-pac-sym Bauteilname Gatename " +
+ "RUN edit-used-dev-pac-sym Bauteilname @ " +
+ "Besitzt das Bauteil nur ein Symbol (Gate) kann mit @ das Symbol aufgerufen werden. " +
+ "Wird @ bei einem Bauteil mit mehreren Symbolen (Gates) angewendet, so wird das erste benutzte Symbol aufgerufen " +
+ "Achtung: Ist die benutzte Bibliothek nicht im Pfad im Menü - Optionen -- Verzeichnisse - Bibliotheken " +
+ "enthalten, so wird ein Schaltplan bzw. Board mit dem Bauteil/Symbol/Package-Namen angelegt. " +
+ "Author: support@cadsoft.de
";
+
+// Version 1.0 -- 19.05.2005 support@cadsoft.de
+// 1.1 -- 29.06.2006 support@cadsoft.de
+// 1.2 -- 05.12.2012 alf@cadsoft.de checkapostroph() in Symbol- und Device-Name
+
+if (language() != "de") Help = usage;
+
+string devList[];
+string pacList[];
+string symList[];
+string pac_name;
+string sym_name;
+int cntDev, cntPac, cntSym;
+
+string use_in;
+
+string Object = strupr(argv[1]); // use in schematic (Device) or board (Element)
+string Gate = strupr(argv[2]); // only in schematic can use
+
+string checkapostroph(string s) { // da der ganze String in ' eingeschlossen wird,
+ // müssen die Apostrophen verdoppelt werden.
+ string t[];
+ int cnt;
+ cnt = strsplit(t, s, '\''); // check Apostroph
+ if (cnt > 1) {
+ s = "";
+ for (int i = 0; i < cnt; i++) {
+ if (i == 0) {
+ if (t[i]) s += t[i];
+ }
+ else if (i) s += "''" + t[i];
+ }
+ }
+ return s;
+}
+
+int newDevice(string DS_name) {
+ int new = 1;
+ for (int n = 0; n < cntDev; n++) {
+ if (devList[n] == DS_name) {
+ new = 0;
+ break;
+ }
+ }
+ return new;
+}
+
+
+int newSymbol(string S_name) {
+ int new = 1;
+ for (int n = 0; n < cntSym; n++) {
+ if (symList[n] == S_name) {
+ new = 0;
+ break;
+ }
+ }
+ return new;
+}
+
+
+if (schematic) {
+ schematic(SCH) {
+ SCH.sheets(S) {
+ S.parts(PA) {
+ if (PA.name == Object) {
+ if (Gate) {
+ int foundgates = 0;
+ PA.instances(I) {
+ foundgates++;
+ if (Gate == "@") {
+ exit("OPEN " + PA.deviceset.library + ";\nEDIT '" + checkapostroph(I.gate.symbol.name) + ".SYM'");
+ }
+ if (I.name == Object+Gate) {
+ exit("OPEN " + PA.deviceset.library + ";\nEDIT '" + checkapostroph(I.gate.symbol.name) + ".SYM'");
+ }
+ }
+ if (foundgates)
+ if (dlgMessageBox("! Gate '" + Gate + "' from Device '" + Object + "' not found.\n" +
+ "Use INVOKE to see available Gates.", "Yes", "No") != 0) exit(0);
+ exit("INVOKE " + Object);
+ }
+ else {
+ exit("OPEN '" + PA.deviceset.library + "';\nEDIT '" + PA.deviceset.name + ".DEV'");
+ }
+ }
+ }
+ }
+ }
+ dlgMessageBox(Help, "OK");
+}
+
+else if (board) board(B) {
+ B.elements(E) {
+ if (E.name == Object) {
+ exit("OPEN " + E.package.library + "; EDIT '" + E.package.name + ".PAC'");
+ }
+ }
+ dlgMessageBox(Help, "OK");
+}
+
+else if (library) {
+
+ if (deviceset) {
+ deviceset(DS) {
+ DS.devices(D) {
+ if (D.package) {
+ pacList[cntPac] = D.package.name;
+ cntPac++;
+ }
+ }
+ DS.gates(G) {
+ if (newSymbol(G.symbol.name)) {
+ symList[cntSym] = G.symbol.name;
+ cntSym++;
+ }
+ }
+ }
+ dlgDialog("EDIT selected Package or Symbol") {
+ int selectPac = cntPac+1, selectSym = cntSym+1;
+ dlgHBoxLayout dlgSpacing(400);
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgLabel("Used p&ackages");
+ dlgListView("Packages", pacList, selectPac) {
+ dlgAccept();
+ exit("EDIT '" + pacList[selectPac] + ".PAC'");
+ }
+ dlgHBoxLayout {
+ dlgPushButton("Edit &Package") {
+ dlgAccept();
+ exit("EDIT '" + pacList[selectPac] + ".PAC'");
+ }
+ dlgStretch(1);
+ }
+ }
+ dlgVBoxLayout {
+ dlgLabel("Used s&ymbols");
+ dlgListView("Symbols", symList, selectSym) {
+ dlgAccept();
+ exit("EDIT '" + checkapostroph(symList[selectSym]) + ".SYM'");
+ }
+ dlgHBoxLayout {
+ dlgPushButton("Edit &Symbol") {
+ dlgAccept();
+ exit("EDIT '" + checkapostroph(symList[selectSym]) + ".SYM'");
+ }
+ dlgStretch(1);
+ }
+ }
+ dlgVBoxLayout dlgSpacing(200);
+ }
+ dlgLabel("Double click on listed Package or Symbol to edit.");
+ dlgHBoxLayout {
+ dlgPushButton("-Cancel") { dlgReject(); exit(0); }
+ dlgStretch(1);
+ }
+ };
+ exit(0);
+ }
+
+ if (package || symbol) {
+ if (package) {
+ package(P) pac_name = P.name;
+ devList[0] = "!No Devices use this package";
+ use_in = "Package used in";
+ library(L) {
+ L.devicesets(DS) {
+ DS.devices(D) {
+ if (D.package) {
+ if (D.package.name == pac_name) {
+ devList[cntDev] = DS.name;
+ cntDev++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (symbol) {
+ symbol(S) sym_name = S.name;
+ devList[0] = "!No Devices use this symbol";
+ use_in = "Symbol used in";
+ library(L) {
+ L.devicesets(DS) {
+ DS.gates(G) {
+ if (G.symbol.name == sym_name) {
+ if (newDevice(DS.name)) {
+ devList[cntDev] = DS.name;
+ cntDev++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (cntDev) {
+ if (cntDev > 1) { // 2006.06.29
+ dlgDialog("EDIT selected Device") {
+ int select;
+ dlgLabel(use_in);
+ dlgHBoxLayout {
+ dlgListView("Devices", devList, select) {
+ dlgAccept();
+ exit("EDIT '" + checkapostroph(devList[select]) + ".DEV';");
+ }
+ dlgVBoxLayout dlgSpacing(200);
+ }
+ dlgLabel("Double click on listed device to edit.");
+ dlgHBoxLayout {
+ dlgPushButton("+OK") { dlgAccept(); exit("EDIT '" + checkapostroph(devList[select]) + ".DEV';"); }
+ dlgPushButton("-Cancel") dlgReject();
+ dlgStretch(1);
+ }
+ };
+ }
+ else exit("EDIT '" + checkapostroph(devList[0]) + ".DEV';");
+ }
+ else dlgMessageBox(devList[0], "Ok");
+}
\ No newline at end of file
diff --git a/trunk/ulp/editnext-dev-sym-pac.ulp b/trunk/ulp/editnext-dev-sym-pac.ulp
new file mode 100644
index 00000000..2b540305
--- /dev/null
+++ b/trunk/ulp/editnext-dev-sym-pac.ulp
@@ -0,0 +1,71 @@
+#usage "Edit next device, symbol, or package in library\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string dev[];
+string sym[];
+string pac[];
+string edit = "";
+int scount = 0;
+int dcount = 0;
+int pcount = 0;
+int n = 0;
+
+if (library) library(L) {
+ L.devicesets(D) {
+ dcount++;
+ dev[dcount] = D.name;
+ }
+ L.symbols(S) {
+ scount++;
+ sym[scount] = S.name;
+ }
+ L.packages(P) {
+ pcount++;
+ pac[pcount] = P.name;
+ }
+
+ if (deviceset) deviceset(D) {
+ edit = D.name;
+ for (n = 1; n < dcount; n++) {
+ if (edit == dev[n]) {
+ break;
+ }
+ }
+
+ if (n < dcount) {
+ cmd += "EDIT " + dev[n + 1] + ".dev;\n" ;
+ }
+ else exit (0);
+ }
+ if (symbol) symbol(S) {
+ edit = S.name;
+ for (n = 1; n < scount; n++) {
+ if (edit == sym[n]) {
+ break;
+ }
+ }
+
+ if (n < scount) {
+ cmd += "EDIT " + sym[n + 1] + ".sym;\n" ;
+ }
+ else exit (0);
+ }
+ if (package) package(P) {
+ edit = P.name;
+ for (n = 1; n < pcount; n++) {
+ if (edit == pac[n]) {
+ break;
+ }
+ }
+
+ if (n < pcount) {
+ cmd += "EDIT " + pac[n + 1] + ".pac;\n" ;
+ }
+ else exit (0);
+ }
+ exit(cmd);
+ }
diff --git a/trunk/ulp/editnext-lbr.ulp b/trunk/ulp/editnext-lbr.ulp
new file mode 100644
index 00000000..bbd72600
--- /dev/null
+++ b/trunk/ulp/editnext-lbr.ulp
@@ -0,0 +1,29 @@
+#usage "Edit next library in current directory\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+if (library) {
+ library(L) {
+ string a[], cmd;
+ string Lname = L.name;
+ string lbr_path = filedir(L.name);
+ int n = fileglob(a, lbr_path + "*.lbr");
+ if (n) {
+ for (int xl = 0; xl < n; xl++) {
+ if (Lname == a[xl]) {
+ if (xl < n-1) {
+ string h;
+ sprintf(h, "OPEN '" + a[xl + 1] + "';");
+ cmd += h;
+ exit (cmd);
+ }
+ }
+ }
+ }
+ }
+ exit (0);
+ }
+
+else dlgMessageBox("Start this ULP from a Library", "OK");
diff --git a/trunk/ulp/editnext-sheet.ulp b/trunk/ulp/editnext-sheet.ulp
new file mode 100644
index 00000000..d7c31ad6
--- /dev/null
+++ b/trunk/ulp/editnext-sheet.ulp
@@ -0,0 +1,23 @@
+#usage "Edit next sheet\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+
+if (schematic) {
+ int scnt = 0;
+ int s;
+ schematic(SH) {
+ sheet(SH) s = SH.number;
+ SH.sheets(S) {
+ scnt = S.number;
+ }
+ if (s < scnt) {
+ s++;
+ sprintf(cmd, "EDIT .s%d;\n", s);
+ }
+ }
+ exit(cmd);
+ }
diff --git a/trunk/ulp/editprev-dev-sym-pac.ulp b/trunk/ulp/editprev-dev-sym-pac.ulp
new file mode 100644
index 00000000..2a2e0413
--- /dev/null
+++ b/trunk/ulp/editprev-dev-sym-pac.ulp
@@ -0,0 +1,71 @@
+#usage "Edit previous device, symbol, or package in library\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string dev[];
+string sym[];
+string pac[];
+string edit = "";
+int scount = 0;
+int dcount = 0;
+int pcount = 0;
+int n = 0;
+
+if (library) library(L) {
+ L.devicesets(D) {
+ dcount++;
+ dev[dcount] = D.name;
+ }
+ L.symbols(S) {
+ scount++;
+ sym[scount] = S.name;
+ }
+ L.packages(P) {
+ pcount++;
+ pac[pcount] = P.name;
+ }
+
+ if (deviceset) deviceset(D) {
+ edit = D.name;
+ for (n = 1; n < dcount; n++) {
+ if (edit == dev[n]) {
+ break;
+ }
+ }
+ if (n > 0) {
+ cmd += "EDIT " + dev[n - 1] + ".dev;\n" ;
+ }
+ else exit (0);
+ }
+
+ if (symbol) symbol(S) {
+ edit = S.name;
+ for (n = 1; n < scount; n++) {
+ if (edit == sym[n]) {
+ break;
+ }
+ }
+ if (n > 0) {
+ cmd += "EDIT " + sym[n - 1] + ".sym;\n" ;
+ }
+ else exit (0);
+ }
+
+ if (package) package(P) {
+ for (n = 1; n < pcount; n++) {
+ edit = P.name;
+ if (edit == pac[n]) {
+ break;
+ }
+ }
+
+ if (n > 0) {
+ cmd += "EDIT " + pac[n - 1] + ".pac;\n" ;
+ }
+ else exit (0);
+ }
+ exit(cmd);
+ }
diff --git a/trunk/ulp/editprev-lbr.ulp b/trunk/ulp/editprev-lbr.ulp
new file mode 100644
index 00000000..a8def577
--- /dev/null
+++ b/trunk/ulp/editprev-lbr.ulp
@@ -0,0 +1,29 @@
+#usage "Edit previous library in current directory\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+if (library) {
+ library(L) {
+ string a[], cmd;
+ string Lname = L.name;
+ string lbr_path = filedir(L.name);
+ int n = fileglob(a, lbr_path + "*.lbr");
+ if (n) {
+ for (int xl = 0; xl <= n; xl++) {
+ if (Lname == a[xl]) {
+ if (xl > 0) {
+ string h;
+ sprintf(h, "OPEN '" + lbr_path + filename(a[xl - 1]) + "';");
+ cmd += h;
+ exit (cmd);
+ }
+ }
+ }
+ }
+ }
+ exit (0);
+ }
+
+else dlgMessageBox("Start this ULP from a Library", "OK");
diff --git a/trunk/ulp/editprev-sheet.ulp b/trunk/ulp/editprev-sheet.ulp
new file mode 100644
index 00000000..d6dc3f16
--- /dev/null
+++ b/trunk/ulp/editprev-sheet.ulp
@@ -0,0 +1,19 @@
+#usage "Edit previous sheet\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+
+if (schematic) {
+ int s;
+ schematic(SH) {
+ sheet(SH) s = SH.number;
+ if (s > 1) {
+ s--;
+ sprintf(cmd, "EDIT .s%d;\n", s);
+ }
+ }
+ exit(cmd);
+ }
diff --git a/trunk/ulp/ex-argv-path.ulp b/trunk/ulp/ex-argv-path.ulp
new file mode 100644
index 00000000..b1f94c4a
--- /dev/null
+++ b/trunk/ulp/ex-argv-path.ulp
@@ -0,0 +1,17 @@
+#usage "Example: Usage of argv\n"
+ "
"
+ "Returns the path of the ULP."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+void main(void) {
+ string ulp_path = "";
+ char c = '/';
+ int pos = strrchr(argv[0], c);
+ if (pos >= 0) {
+ ulp_path = strsub(argv[0], 0, pos + 1);
+ }
+ dlgMessageBox(ulp_path , "+OK");
+}
diff --git a/trunk/ulp/ex-dialogs.ulp b/trunk/ulp/ex-dialogs.ulp
new file mode 100644
index 00000000..fc262343
--- /dev/null
+++ b/trunk/ulp/ex-dialogs.ulp
@@ -0,0 +1,653 @@
+#usage "Example: Dialogs\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string Text = "This is some text.\nLine 2\nLine 3";
+string Text2 = "This is text number 2\nLine 2\nLine 3";
+Text2 += "\n...\n...\n...\n...\n...\n...\n...\n...\n";
+Text2 += "end of text2.";
+
+int Result = dlgDialog("List-Fenster") {
+ dlgVBoxLayout {
+ dlgLabel("&View text 1");
+ dlgTextView(Text);
+
+ dlgLabel("Vie&w text 2");
+ dlgTextView(Text2);
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ }
+ };
+if (Result == 0) exit (0);
diff --git a/trunk/ulp/ex-file-copy.ulp b/trunk/ulp/ex-file-copy.ulp
new file mode 100644
index 00000000..200cc239
--- /dev/null
+++ b/trunk/ulp/ex-file-copy.ulp
@@ -0,0 +1,30 @@
+#usage "Example: Copy a file\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string fileName;
+string test = "";
+int Result = 0;
+int nBytes = 0;
+int start = 0;
+char c[];
+
+fileName = dlgFileOpen("Select a file", "*.*");
+
+nBytes = fileread(c, fileName);
+
+sprintf(test, "%d = &%x", nBytes, nBytes);
+dlgMessageBox("Length of File = " + test);
+
+dlgMessageBox("Write " + fileName + "?");
+fileName += ".copy";
+output(fileName, "wb") {
+ for (int z = 0; z < nBytes; z++) {
+ printf("%c", c[z]);
+ Result = z+1;
+ }
+ }
+sprintf(test, "%d = $%x", Result, Result);
+dlgMessageBox("Length of File = " + test, "OK");
diff --git a/trunk/ulp/ex-include.ulp b/trunk/ulp/ex-include.ulp
new file mode 100644
index 00000000..01adaffb
--- /dev/null
+++ b/trunk/ulp/ex-include.ulp
@@ -0,0 +1,22 @@
+#usage "Example: Usage of include file\n"
+ "
"
+ "Demonstrates how to use the include file 'useful-routines.ulp'."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+#include "useful-routines.ulp"
+
+int Result;
+string s1, s2, h;
+
+s1 = "DISPLAY ALL;\n";
+s2 = get_ulp_name();
+Result = edit_save_execute(s1, s2);
+sprintf(h, "Result: %d", Result);
+dlgMessageBox(h, "OK");
+
+dlgMessageBox("ULP path: "+get_ulp_path(),"OK");
+
+dlgMessageBox("Project path: "+get_project_path(),"OK");
diff --git a/trunk/ulp/ex-input-file.ulp b/trunk/ulp/ex-input-file.ulp
new file mode 100644
index 00000000..9b444b8e
--- /dev/null
+++ b/trunk/ulp/ex-input-file.ulp
@@ -0,0 +1,75 @@
+#usage "Example: Input file dialog\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+int n = 0; // global counter
+char b[];
+string fileName = "";
+
+fileName = dlgFileOpen("Select a File", "");
+int nBytes = fileread(b, fileName);
+
+ for (n; n < nBytes; n++) {
+ switch (b[n]) {
+ case 0: break;
+
+ case 1: cmd += "Device\n";
+ break;
+
+ case 2: cmd += "\nEND - HEADER\n";
+ break;
+
+ case 3: cmd += "\nEND - 3\n";
+ break;
+
+ case 4: cmd += "4";
+ break;
+
+ case 5: break;
+
+ case 6: break;
+
+ case 7: break;
+
+ case 8: break;
+
+ case 9: cmd += "\t";
+ break;
+
+
+ case 10: cmd += "Line Feed\n";
+ break;
+
+ case 12: cmd += "\nNew Page\n";
+ break;
+
+ case 13: cmd += "Carriage Return\n";
+ break;
+
+ case 27: cmd += "\nEscape\n";
+ break;
+
+ case 32: cmd += ".space." + b[n];
+ break;
+
+ default: cmd += b[n];
+ break;
+ }
+ }
+ // Demo Text Editor Box
+ dlgDialog("Text Editor Box") {
+ dlgTextEdit(cmd);
+ dlgHBoxLayout {
+ dlgPushButton("+Ok") {
+ dlgAccept();
+ output("test.txt", "wt") {
+ printf(cmd);
+ }
+ };
+ dlgPushButton("-Cancel") dlgReject();
+ }
+ };
+ exit(0);
diff --git a/trunk/ulp/ex-loop-lbrs.ulp b/trunk/ulp/ex-loop-lbrs.ulp
new file mode 100644
index 00000000..c1a03c7d
--- /dev/null
+++ b/trunk/ulp/ex-loop-lbrs.ulp
@@ -0,0 +1,67 @@
+#usage "Example: Check all libraries in a directory\n"
+ "
"
+ "This is an example how to loop through all libraries in a directory "
+ "and perform a device check."
+ "
"
+ "In this case, the device descriptions are checked for double bold tags. "
+ "An error report error.txt is generated in the library directory."
+ "
"
+ "Load any library from the library directory and execute the ULP."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string a[], par, lbr_path, dest, cmd = "", s, progname;
+int lbrpnt, x;
+
+//--------------------------------------------------
+string checklbr (UL_LIBRARY L) {
+ int errflag = 0;
+ string h;
+ L.devices(D) {
+ h = "";
+ sprintf(h,"%s",D.description);
+ h = strlwr(h);
+ if (strstr(h, "") >= 0 && !errflag) {
+ cmd += L.name+"\n";
+ errflag = 1;
+ }
+ }
+ if (errflag) return "***";
+ else return "";
+ }
+
+
+//-------- main program --------------------------------------------------
+progname = filesetext(filename(argv[0]), "");
+library(L) {
+ lbr_path = filedir(L.name);
+ }
+dest = lbr_path+"error.txt";
+
+lbrpnt = strtod(argv[1]);
+int n = fileglob(a, lbr_path+"*.lbr");
+
+if (n) {
+ if (lbrpnt < 1) { // first run
+// initial actions, e.g. headline
+//------------------------------------------------------------------------
+ output(dest, "wt") printf("Faulty Libraries marked with ***\n\n");
+//------------------------------------------------------------------------
+ exit("OPEN '"+lbr_path+filename(a[0])+"';\nRUN '"+progname+"' 1");
+ }
+ else { // next runs
+ library(L) {
+// insert here whatever you want to do with the current library
+//------------------------------------------------------------------------
+ s = checklbr(L);
+ output(dest, "at") printf("%s%s\n",L.name, s);
+//------------------------------------------------------------------------
+ lbrpnt++;
+ sprintf(par, "%d", lbrpnt);
+ if (lbrpnt == n) exit(0);
+ exit("OPEN '"+lbr_path+filename(a[lbrpnt])+"';\nRUN '"+progname+"' "+par+"\n");
+ }
+ }
+ }
diff --git a/trunk/ulp/ex-run-script.ulp b/trunk/ulp/ex-run-script.ulp
new file mode 100644
index 00000000..ea675966
--- /dev/null
+++ b/trunk/ulp/ex-run-script.ulp
@@ -0,0 +1,32 @@
+#usage "Example: Export a script and execute it\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string dev = "";
+
+cmd += "OPEN TEST.LBR;\n";
+cmd += "Edit testxx.pac;\n";
+cmd += "change Layer tPlace;\n";
+cmd += "Grid MIL ON;\n";
+cmd += "; WIRE 1 (-100 -100) (230 360);\n";
+cmd += "; WIRE 20 (-10 -50) (130 60);\n";
+cmd += "WIN FIT;\n;";
+
+string ulp_path;
+
+// ** always use '/' as path delimiter to keep ULPs platform independent **
+
+char bkslash = '/';
+int pos = strrchr(argv[0], bkslash);
+if (pos >= 0) { // split path from filename
+ ulp_path = strsub(argv[0], 0, pos + 1);
+ }
+
+output(ulp_path + "v4test.scr", "wt") {
+ printf(cmd);
+}
+
+exit("; SCR '" + ulp_path + "v4test.scr';\n");
diff --git a/trunk/ulp/exp-descr-html.ulp b/trunk/ulp/exp-descr-html.ulp
new file mode 100644
index 00000000..1df71dd5
--- /dev/null
+++ b/trunk/ulp/exp-descr-html.ulp
@@ -0,0 +1,90 @@
+#usage "Export descriptions of devices and packages to HTML\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string dev[];
+string descript[];
+int count = 0;
+int n = 0;
+
+// find some path names ---------
+string ulp_path = "";
+string eagle_path = ""; // certain only for EAGLE standard installation
+string doc_path = ""; // certain only for EAGLE standard installation
+string direntry[];
+char c = '/';
+int dirnr, j;
+ int pos = strrchr(argv[0], c);
+ if (pos >= 0) {
+ ulp_path = strsub(argv[0], 0, pos + 1);
+ eagle_path = ulp_path;
+ eagle_path = strsub(eagle_path, 0, pos);
+ int pos = strrchr(eagle_path, c);
+ if (pos >= 0) {
+ eagle_path = strsub(eagle_path, 0, pos + 1);
+ dirnr = fileglob(direntry, eagle_path+"*");
+ doc_path = eagle_path;
+ for (j; j<= dirnr; j++) {
+ if (strrstr(direntry[j], "doc/") > 0) {
+ doc_path = direntry[j];
+ }
+ }
+ }
+ }
+
+// find string s2 in s1, and replace with s3
+string replace_string(string s1, string s2, string s3) {
+int i, pos = 1;
+ string a = s1;
+ while (pos >= 0) {
+ pos = strstr(a, s2);
+ if (pos < 0) break;
+ string st1 = strsub(a, 0, pos);
+ string st2 = strsub(a, pos + strlen(s2));
+ a = st1+s3+st2;
+ }
+ return a;
+ }
+
+if (library) library(L) {
+ L.devicesets(D) {
+ count++;
+ dev[count] = D.name;
+ descript[count] = replace_string(D.description, "
", " ");
+
+ string h = "";
+
+ int l = strlen(dev[count]);
+ string s = strsub(dev[count], 0, 2);
+ string t = strsub(dev[count], 3, l);
+
+ sprintf(h, "DEVICE: %s %s
", " ");
+ string h = "";
+ int l = strlen(dev[count]);
+ string s = strsub(dev[count], 0, 2);
+ string t = strsub(dev[count], 3, l);
+
+ sprintf(h, "PACKAGE: %s %s
\n", dev[count], descript[count]);
+ cmd += h;
+ }
+
+//define destination path name
+//for a fixed destination, delete next line, uncomment the one after
+//the next line and edit it
+ string dest = dlgFileSave("Save Description File", doc_path+"descript.htm", "*.htm");
+//dest = "c:/eagle/doc/descript.htm";
+
+ output(dest, "wt") {
+ printf(cmd);
+ }
+ }
diff --git a/trunk/ulp/exp-descr-script.ulp b/trunk/ulp/exp-descr-script.ulp
new file mode 100644
index 00000000..98b4a72f
--- /dev/null
+++ b/trunk/ulp/exp-descr-script.ulp
@@ -0,0 +1,105 @@
+#usage "Export descriptions of devices and packages to a script\n"
+ "
"
+ "Use this ULP to export the device and package descriptions "
+ "of a library to a file."
+ "
"
+ "You can then edit this file with a text editor and read back "
+ "changed descriptions with the SCRIPT command."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string dev[];
+string descript[];
+string dest;
+int count = 0;
+int n = 0;
+
+// Find some path names ---------
+string ulp_path = "";
+string eagle_path = ""; // certain only for EAGLE standard installation
+string scr_path = ""; // certain only for EAGLE standard installation
+string direntry[];
+char c = '/';
+int dirnr, j;
+ int pos = strrchr(argv[0], c);
+ if (pos >= 0) {
+ ulp_path = strsub(argv[0], 0, pos + 1);
+ eagle_path = ulp_path;
+ eagle_path = strsub(eagle_path, 0, pos);
+ int pos = strrchr(eagle_path, c);
+ if (pos >= 0) {
+ eagle_path = strsub(eagle_path, 0, pos + 1);
+ dirnr = fileglob(direntry, eagle_path+"*");
+ scr_path = eagle_path;
+ for (j; j<= dirnr; j++) {
+ if (strrstr(direntry[j], "scr/") > 0) {
+ scr_path = direntry[j];
+ }
+ }
+ }
+ }
+//--------------------------------
+
+string replacenewline(string nl) {
+ string a[];
+ int n = strsplit(a, nl, '\n');
+ if (n > 0) {
+ nl = "";
+ for (int x = 0; x < n - 1; x++) {
+ nl += a[x] + "\\n";
+ }
+ nl += a[x];
+ }
+ return nl;
+ }
+
+ if (library) library(L) {
+ L.devicesets(D) {
+ count++;
+ dev[count] = D.name;
+ descript[count] = replacenewline(D.description);
+ string h = "";
+ sprintf(h, "EDIT %s.dev ;\nDESCRIPT '%s'\n", dev[count], descript[count]);
+ cmd += h;
+ }
+
+ L.packages(P) {
+ count++;
+ dev[count] = P.name;
+ descript[count] = replacenewline(P.description);
+
+ string h = "";
+
+ int l = strlen(dev[count]);
+ string s = strsub(dev[count], 0, 2);
+ string t = strsub(dev[count], 3, l);
+
+ sprintf(h, "EDIT %s.pac ;\nDESCRIPT '%s'\n", dev[count], descript[count]);
+ cmd += h;
+ }
+
+ cmd = "SET UNDO_LOG OFF;\n" + cmd + "SET UNDO_LOG ON;\n";
+
+ // EditBox
+ dlgDialog("Descriptions") {
+ dlgTextEdit(cmd);
+ dlgHBoxLayout {
+ dlgPushButton("+Ok") dlgAccept();
+ dlgPushButton("-Cancel Changes") dlgReject();
+ }
+ };
+
+// define destination path name
+// for a fixed destination, delete next line, uncomment the one after
+// the next line and edit it
+ dest = dlgFileSave("Save Description File", scr_path+"descript.scr", "*.scr");
+//dest = "c:/eagle/scr/descript.scr";
+
+ if (dest == "") exit(0);
+ output(dest, "wt") {
+ printf(cmd);
+ }
+ }
diff --git a/trunk/ulp/exp-lbrs.ulp b/trunk/ulp/exp-lbrs.ulp
new file mode 100644
index 00000000..9ec905fe
--- /dev/null
+++ b/trunk/ulp/exp-lbrs.ulp
@@ -0,0 +1,805 @@
+#usage "en:Export of libraries from a drawing.
\n"
+ "This can be used to make individual changes to components in a project. "
+ "Just load schematic, board or both, use this ULP to generate one or several libraries "
+ "containing the used components. Make your changes in the library/libraries and use the "
+ "UPDATE command to introduce the changes to schematic and/or board.
"
+ "See Help for further details.
",
+ "de:Export von Bibliotheken aus einer Zeichnungsdatei.
\n"
+ "Damit können Sie individuelle Änderungen an Komponenten in einem Projekt machen. "
+ "Laden Sie dazu Schaltplan, Board oder beides, verwenden Sie dieses ULP, um eine oder mehrere Bibliotheken "
+ "mit den verwendeten Komponenten zu generieren. Machen Sie Ihre Änderungen in der/den Bibliothek(en) "
+ "und verwenden Sie den UPDATE-Befehl, um die Änderungen in Schaltplan und/oder Board zu bringen.
"
+ "Siehe Hilfe für weitere Details.
"
+
+#require 6.0301
+
+string Version = "6.0";
+
+// Language:
+//----------
+// Please keep to alphabetic sorting for maintainability !
+string Dictionary[] = {
+ "en\v"
+ "de\v",
+ "Back\v"
+ "Zurück\v",
+ "Cancel\v"
+ "Abbrechen\v",
+ "Creation mode\v"
+ "Erzeugungsmodus\v",
+ "&Browse\v"
+ "&Durchsuchen\v",
+ "Export EAGLE libraries - Help\v"
+ "Export von EAGLE-Bibliotheken - Hilfe\v",
+ "Export EAGLE libraries from drawing\v"
+ "Export von EAGLE-Bibliotheken aus der Zeichnung\v",
+ "Export original libraries\v"
+ "Original-Bibliotheken exportieren\v",
+ "File \v"
+ "Datei \v",
+ "Help\v"
+ "Hilfe\v",
+ "Load\v"
+ "Laden\v",
+ "Merge to one library, \v"
+ "In eine Bibliothek integrieren, \v",
+ "original library names as prefix for symbol, package and device names\v"
+ "Original-Bibliotheksnamen als Präfix für Symbol-, Package- und Devicenamen verwenden\v",
+ "Path\v"
+ "Pfad\v",
+ "Please start from schematic or board editor!\v"
+ "Bitte starten Sie vom Schaltplan- oder Board-Editor!\v",
+ "Start\v"
+ "Start\v",
+ "unchanged symbol, package and device names\v"
+ "Symbol-, Package- und Devicenamen unverändert\v"
+};
+
+string DlgLang = language();
+if (DlgLang != "de") DlgLang = "en";
+int LangIdx = strstr(Dictionary[0], DlgLang) / 3;
+
+// Translate, based on dictionary
+string TR(string s) {
+ string t = lookup(Dictionary, s, LangIdx, '\v');
+ return t ? t : s;
+}
+//-----------------------------------------------------------------------------
+
+// Used in DrawText
+string AlignName[];
+AlignName[ALIGN_BOTTOM_LEFT] = "BOTTOM LEFT";
+AlignName[ALIGN_BOTTOM_CENTER] = "BOTTOM CENTER";
+AlignName[ALIGN_BOTTOM_RIGHT] = "BOTTOM RIGHT";
+AlignName[ALIGN_CENTER_LEFT] = "CENTER LEFT";
+AlignName[ALIGN_CENTER] = "CENTER CENTER";
+AlignName[ALIGN_CENTER_RIGHT] = "CENTER RIGHT";
+AlignName[ALIGN_TOP_LEFT] = "TOP LEFT";
+AlignName[ALIGN_TOP_CENTER] = "TOP CENTER";
+AlignName[ALIGN_TOP_RIGHT] = "TOP RIGHT";
+
+string Croute[];
+Croute[CONTACT_ROUTE_ALL] = "ALL";
+Croute[CONTACT_ROUTE_ANY] = "ANY"; // 2012-09-26
+
+// Used in DrawDimension
+string DimType[];
+DimType[DIMENSION_PARALLEL] = "PARALLEL";
+DimType[DIMENSION_HORIZONTAL] = "HORIZONTAL";
+DimType[DIMENSION_VERTICAL] = "VERTICAL";
+DimType[DIMENSION_RADIUS] = "RADIUS";
+DimType[DIMENSION_DIAMETER] = "DIAMETER";
+DimType[DIMENSION_ANGLE] = "ANGLE";
+DimType[DIMENSION_LEADER] = "LEADER";
+
+string UnitName[];
+UnitName[GRID_UNIT_MIC] = "MIC";
+UnitName[GRID_UNIT_MM] = "MM";
+UnitName[GRID_UNIT_MIL] = "MIL";
+UnitName[GRID_UNIT_INCH] = "INCH";
+
+string x[] = { " " };
+string CurrentLbrName = "";
+string EditName;
+string h, cmd = "";
+string ScriptName, PureScriptName;
+string WorkPath;
+string Status = "";
+int n;
+int NameIndex = 0;
+int Merge = 0;
+
+char ascii127[] = { 181, 196, 214, 220, 223, 0 }; // not allowed character 2010-05-12
+// www: In 8859-1 these chars are { ,Ä ,Ö, Ü, ß } and therefore actually allowed as object names.
+// Change this if requested ! What's also allowed but deprecated is { ä, ö, ü }. Should be replaced
+// by { Ä, Ö, Ü }. All other chars allowed for file names are allwoed also for object names.
+// Lower case is automatically converted to upper case (except the umlauts).
+string Newascii127[] = { "U", "AE", "OE", "UE", "SS", "" }; // change to allowed character
+
+string HelpText[] = {
+ "The library export collects the devices or packages from a schematic or board and stores them back "
+ "into one or several libraries."
+ "
"
+ "By default all contained libraries are exported with their original name into the drawing path."
+ "Thus you can edit symbols and/or packages in these libraries and "
+ "use the UPDATE command to change all respective parts in schematic or board."
+ "
"
+ "Alternatively all objects can be merged into a single library with the name of the schematic or board."
+ "You can choose between using the names of the original libraries as prefix for package, symbol and device names or not."
+ "Not using these prefixes can lead to ambiguities and therefore is not recommended."
+ "
"
+ "The export path can be adjusted by 'Browse' to select a directory."
+ "If one of the library files to be created already exists, you will be prompted if "
+ "the existing file may be deleted."
+ ,
+ "Der Bibliotheks-Export sammelt Devices und Packages eines Schaltplans oder Boards und speichert "
+ "sie in eine oder mehrere Bibliotheken."
+ "
"
+ "Standardmässig werden alle enthaltenen Bibliotheken mit ihrem Orignialnamen in den Pfad der Zeichnungsdatei(en) "
+ "exportiert. So können Sie Symbole und/oder Packages editieren und mit dem UPDATE-Befehl alle entsprechenden "
+ "Bauteile in Schaltplan und Board aktualisieren."
+ "
"
+ "Alternativ können alle Objekte in eine einzige Bibliothek mit Schaltplan- bzw. Boardnamen integriert werden. "
+ "Sie können wählen, ob Sie die Namen der Original-Bibliotheken als Präfix für die Package-, Symbol- und Devicenamen verwenden "
+ "oder nicht. Diese Präfixe nicht zu verwenden kann zu Mehrdeutigkeit führen und wird daher nicht empfohlen."
+ "
"
+ "Der Export-Pfad kann mit 'Durchsuchen' eingestellt werden. "
+ "Wenn eines der Bibliotheken bereits existiert, werden Sie gefragt, ob die bestehende Datei gelöscht werden darf."
+};
+
+void DisplayHelp() {
+ dlgDialog(TR("Export EAGLE libraries - Help")) {
+ dlgHBoxLayout dlgSpacing(400);
+ dlgTextView(HelpText[LangIdx]);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+" + TR("Back")) dlgReject();
+ dlgStretch(1);
+ }
+ };
+}
+
+string get_project_path() {
+ if (board) board(B) return(filedir(B.name));
+ if (schematic) schematic(B) return(filedir(B.name));
+ if (library) library(B) return(filedir(B.name));
+}
+
+string replacenewline(string nl) {
+ string a[];
+ int n = strsplit(a, nl, '\n');
+ if (n > 0) {
+ nl = "";
+ for (int x = 0; x < n - 1; x++) {
+ nl += a[x] + "\\n";
+ }
+ nl += a[x];
+ }
+ return nl;
+}
+
+// Da der ganze String in ' eingeschlossen wird,
+// müssen die Apostrophen verdoppelt werden.
+string addApostroph(string name) { // 2012-03-23
+ string t[];
+ int cnt = strsplit(t, name, '\''); // check Apostroph
+ if (cnt > 1) {
+ name = "";
+ for (int i = 0; i < cnt; i++) {
+ if (i == 0) {
+ if (t[i]) name += t[i];
+ }
+ else if (i) name += "''" + t[i];
+ }
+ }
+ return name;
+}
+
+string replaceascii127(string s, int n, string newascii) {
+ if (n == strlen(s)) return strsub(s, 0, n) + newascii;
+ else return strsub(s, 0, n) + newascii + strsub(s, n+1);
+}
+
+string check_ascii127(string s) { // 2009-02-02
+ int n = 0;
+ int pos;
+ do {
+ pos = strchr(s, ascii127[n]);
+ if (pos > -1)
+ s = replaceascii127(s, pos, Newascii127[n]);
+ if (pos < 0) n++; // 2012-02-08
+ } while (ascii127[n]);
+ return s;
+}
+
+// Remove this as soon as the "@-problem" is solved !
+string ReplaceAt(string s) {
+ for (int i = 0; i < strlen(s); i++)
+ if (s[i]=='@') s[i]='$'; // Creates problems when name is used in ADD and other commands
+ return s;
+}
+
+string ReplaceInvalidCharsForObjNames(string s) {
+ for (int i = 0; i < strlen(s); i++)
+ if (s[i]==' ') s[i]='-'; // No '_' to distinguish from prefix ending !
+ return ReplaceAt(s);
+}
+
+string LbrPrefix(string s) {
+ s = check_ascii127(s);
+ return ReplaceInvalidCharsForObjNames(s) + "_";
+}
+
+int exist_file(string FileName) {
+ string a[];
+ int n = fileglob(a, FileName);
+ if (n == 0) return 0;
+ else return 1;
+}
+
+void CreateLBRdescription(string project_name) {
+ // !!! Wird nicht vorherige Description überschrieben ?
+ sprintf(h, "DESCRIPTION 'Generated from %s
"
+ "RUN export-errors [Save] [Filename] "
+ "author alf@cadsoft.de"
+
+#require 7.01.03;
+string Version = "1.0.0"; // 2014-11-11 alf@cadsoft.de
+
+string HeaderErcErrors;
+string HeaderDrcErrors;
+
+string SaveErrorFileName = "";
+string Option1 = strupr(argv[1]);
+int CntErrorInconsistenc = 0;
+
+int Consistence = 0;
+string ExistSCHfile = "";
+string ExistBRDfile = "";
+string ErrorList[];
+int CntError = 0;
+
+int Debug = 0;
+
+/*
+Die Member layer und contours() sind nur im UL_BOARD Kontext und
+die Member area2, modulename, s1..s6 und sheet sind nur im UL_SCHEMATIC Kontext verfügbar.
+*/
+int ErrBx1[], ErrBy1[], ErrBx2[], ErrBy2[]; // area UL_AREA nur im Board
+int ErrSx1[], ErrSy1[], ErrSx2[], ErrSy2[]; // area2 UL_AREA nur im Schaltplan
+int ErrCode[]; // Identifikations-Nummer
+string ErrDescription[];
+int ErrLayer[];
+string ErrModulename[];
+string ErrS1[], ErrS2[], ErrS3[], ErrS4[], ErrS5[], ErrS6[];
+int ErrSheet[]; // int Seitennummer
+string ErrSignature[]; // string (Signatur-String) state
+int ErrState[]; // int (ERROR_STATE_...)
+int ErrType[]; // int (ERROR_TYPE_...)
+int ErrX[], ErrY[]; // int (Mittelpunkt)
+
+string ErrorState[], ErrorType[];
+ ErrorState[ERROR_STATE_ACTIVE] = "error has not yet been approved or processed";
+ ErrorState[ERROR_STATE_APPROVED] = "error has been approved";
+ ErrorState[ERROR_STATE_PROCESSED] = " error has been processed";
+ ErrorType[ERROR_TYPE_NONE] = "no error";
+ ErrorType[ERROR_TYPE_WARNING] = "warning";
+ ErrorType[ERROR_TYPE_ERROR] = "error";
+ ErrorType[ERROR_TYPE_CONSISTENCY] = "consistency error";
+
+ HeaderErcErrors = "Consistency not checked (no board loaded)";
+
+if (language() == "de") {
+ ErrorState[ERROR_STATE_ACTIVE] = "Fehler wurde weder bearbeitet, noch gebilligt";
+ ErrorState[ERROR_STATE_APPROVED] = "Fehler wurde gebilligt";
+ ErrorState[ERROR_STATE_PROCESSED] = "Fehler wurde bearbeitet";
+ ErrorType[ERROR_TYPE_NONE] = "kein Fehler";
+ ErrorType[ERROR_TYPE_WARNING] = "Warnung";
+ ErrorType[ERROR_TYPE_ERROR] = "Fehler";
+ ErrorType[ERROR_TYPE_CONSISTENCY] = "Konsistenz-Fehler";
+
+ HeaderErcErrors = "Konsistenz nicht geprüft (kein Board geladen)";
+}
+
+
+string s;
+
+/* ### ERROR functions ### */
+void error_3(int sel) {
+ sprintf(s, "RUN ulpmessage 'Signatur:%s Description:%s Layer:%d '",
+ ErrSignature[sel], ErrDescription[sel], ErrLayer[sel]
+ );
+ exit(s);
+}
+
+void error_5(int sel) {
+ real x = u2mm(ErrSx2[sel]) - u2mm(ErrSx1[sel]);
+ real y = u2mm(ErrSy2[sel]) - u2mm(ErrSy1[sel]);
+ if (x < y) {
+ sprintf(s, "Win (%.8fmm %.8fmm);\nRUN ulpmessage 'der Abstand in x ist um %.8fmm zu klein.'",
+ u2mm(ErrX[sel]), u2mm(ErrY[sel]), x
+ );
+ }
+ else if (y < x) {
+ sprintf(s, "Win (%.8fmm %.8fmm);\nRUN ulpmessage 'der Abstand in y ist um %.8fmm zu klein.'",
+ u2mm(ErrX[sel]), u2mm(ErrY[sel]), y
+ );
+ }
+ else {
+ sprintf(s, "Win (%.8fmm %.8fmm);\nRUN ulpmessage 'der Abstand in x & y ist jeweils um %.8fmm zu klein.'",
+ u2mm(ErrX[sel]), u2mm(ErrY[sel]), y
+ );
+ }
+ exit(s);
+}
+
+void error_11(int sel) {
+ sprintf(s, "DISPLAY NONE %d;\nWINDOW (%.8fmm %.8fmm);\nCHANGE FONT Vector (%.8fmm %.8fmm);\nDISPLAY LAST;",
+ ErrLayer[sel],
+ u2mm(ErrX[sel]), u2mm(ErrY[sel]),
+ u2mm(ErrX[sel]), u2mm(ErrY[sel])
+ );
+ exit(s);
+}
+
+void checkerror(int sel) {
+ int ecod = ErrCode[sel];
+ switch(ecod) {
+ case 1 : // Drill Size
+ break;
+ case 2 : // Drill Distance
+ break;
+ case 3 : // Width
+ break;
+ case 4 : // Dimension
+ break;
+ case 5 : // Clearance
+ break;
+ case 6 : // Restrict
+ break;
+ case 7 : // Keepout
+ break;
+ case 8 : // Angle
+ break;
+ case 9 : // Off Grid
+ break;
+ case 11 : // No Vector Font
+ break;
+ case 19 : // Overlap
+ break;
+ case 101 : // Nicht angeschlossener Pin
+ break;
+ case 102 : // SUPPLY-Pin überschrieben mit xxx
+ break;
+ case 103 : // NC-Pin IC3 xxxx verbunden mit xx
+ break;
+ case 104 : // POWER-Pin verbunden mit xxx
+ break;
+ case 105 : // Keine Pins an Netz xxx
+ break;
+ case 106 : // Nur ein Pin an Netz xxx
+ break;
+ case 107 : // Junction verbindet Netze xx und xx scheinbar
+ break;
+ case 108 : // Fehlende Junction in Netz xxx
+ break;
+ case 109 : // Nahe beieinander liegende, aber unverbundene Linien in Netz xx
+ break;
+ case 110 : // Nahe beeinander liegende, aber unverbundene Linien in Netzen xxx und xxx
+ break;
+ case 111 : // Netz xxx überlappt Pin
+ break;
+ case 112 : // Pins überlappen
+ break;
+ case 113 : // Part has no value
+ break;
+ case 115 : // Segment des Netzes XXX hat keine erkennbare Verbindung (z.B. Label, Bus oder Supply-Pin) zu anderen Segmenten des selben Netzes
+ break;
+ case 116 : // Pin an XXXX angeschlossen ohne Netz-Wire, Junction oder anderen Pin
+ break;
+ case 118 : // Netz benutzt durch Port xxx hat kein Label
+ break;
+ case 119 : // Es existiert kein Modul Netz für Port xxxx
+ break;
+ case 120 : // Bus A[0..15] überlappt Port
+ break;
+ case 121 : // Netz L1 überlappt Port
+ break;
+ case 201 : // SUPPLY-Pin überschrieben mit mehr als einem Signal
+ break;
+ case 202 : // not connected input pin
+ break;
+ case 205 : // no Supply-Pin for implizit Power pin
+ break;
+ case 206 : // Mehr als ein OUTPUT-Pin an Netz xx
+ break;
+ case 209 : // Nur INPUT-Pins an Netz xxx
+ break;
+ case 211 : // Netzname XXX ist im Bus xxxxxx nicht enthalten
+ break;
+ case 213 : // Direction 'io' von Port KB0 ist nicht kompatibel mit den Pins am Netz im Modul
+ break;
+ case 304 : // element not found on board
+ break;
+ case 305 : // part not found on schematic
+ break;
+ default : sprintf(s, "Error-Code %d: unknown!", ecod);
+ dlgDialog("Error") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgStringEdit(ErrDescription[sel]);
+ dlgLabel(s);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-1); }
+ dlgStretch(1);
+ }
+ };
+ }
+}
+
+/* *** normal functions *** */
+string checkexistfile(string existfile) {
+ string a[];
+ int cnt = fileglob(a, existfile);
+ if (cnt) return a[0];
+ return "";
+}
+
+void savefile(string sourcefilename, string editname) {
+ output(SaveErrorFileName, "wt") {
+ printf("#Exported from: \"%s\"\n#with %s Version %s\n", sourcefilename, filename(argv[0]), Version);
+ printf("#%s\n", EAGLE_SIGNATURE);
+ printf("#at:%s\n", t2string(time()) );
+ if (CntErrorInconsistenc) {
+ //if (ExistSCHfile) printf("%s\n",ExistSCHfile);
+ //if (ExistBRDfile) printf("%s\n",ExistBRDfile);
+ printf("%s\n", HeaderErcErrors);
+ }
+ else {
+ printf("%s\n", HeaderErcErrors);
+ }
+ for (int n = 0; n < CntError; n++) {
+ printf("%s\n", ErrorList[n]);
+ }
+ }
+}
+
+void saveerrors(string header, string sourcefilename, string errorfilename) {
+ string a[];
+ int fexist = fileglob(a, errorfilename);
+ int xl = 30 + strlen(errorfilename) * 5;
+
+ dlgDialog(header) {
+ dlgHBoxLayout dlgSpacing(xl);
+ dlgStringEdit(errorfilename);
+ dlgHBoxLayout {
+ if (fexist) {
+ if (language() == "de") {
+ dlgLabel("Datei existiert bereits... ");
+ dlgPushButton("Überschreiben") { dlgAccept(); savefile(sourcefilename, errorfilename); exit(0); }
+ }
+ else {
+ dlgLabel("File exist... ");
+ dlgPushButton("Overwrite") { dlgAccept(); savefile(sourcefilename, errorfilename); exit(0); }
+ }
+ }
+ else {
+ dlgPushButton("+OK") { dlgAccept(); savefile(sourcefilename, errorfilename); exit(0); }
+ }
+ dlgPushButton("+CANCEL") { dlgReject(); exit(-2); }
+ dlgStretch(1);
+ }
+ };
+}
+
+void saveerrdialog(string dialogheader, string listheader, string sourcefilename) {
+ string consistenceleader;
+ string consistencetrailer;
+ if (schematic) {
+ if (CntErrorInconsistenc) {
+ //if (ExistSCHfile) printf("%s\n",ExistSCHfile);
+ //if (ExistBRDfile) printf("%s\n",ExistBRDfile);
+ }
+ else {
+ consistenceleader = "";
+ consistencetrailer = "";
+ }
+ if (Consistence) {
+ ExistSCHfile = "";
+ ExistBRDfile = "";
+ consistenceleader = "";
+ consistencetrailer = "";
+ }
+ }
+ if (board) {
+ ExistSCHfile = "";
+ ExistBRDfile = "";
+ consistenceleader = "";
+ consistencetrailer = "";
+ }
+ dlgDialog(dialogheader) {
+ int sel = -1;
+ int srt = 0;
+ dlgHBoxLayout dlgSpacing(800);
+ if (ExistSCHfile) dlgLabel(ExistSCHfile);
+ if (ExistBRDfile) dlgLabel(ExistBRDfile);
+
+ dlgLabel(consistenceleader + HeaderErcErrors + consistencetrailer);
+
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(400);
+ dlgListView(listheader, ErrorList, sel, srt) checkerror(sel);
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("&Save") saveerrors("Save ERC-ERRORS", sourcefilename, SaveErrorFileName);
+ dlgStretch(1);
+ }
+ };
+}
+
+if (schematic) {
+ schematic(SCH) {
+ if (!SCH.checked) {
+ string msg = "Schematic is changed, first start Electrical Rule Check (ERC)!";
+ if (language() == "de") msg = "Der Schaltplan wurde verändert, starten sie zuerst den Electrical Rule Check!";
+ if (dlgMessageBox(msg, "OK", "CANCEL") != 0) exit(-3);
+ string cmd;
+ sprintf(cmd, "ERC; RUN '%s'", argv[0]);
+ exit (cmd);
+ }
+ ExistSCHfile = "SCH File loaded: \"" + SCH.name + "\"";
+ ExistBRDfile = "BRD File exist : \"" + checkexistfile(filesetext(SCH.name, ".brd")) + "\"";
+ if(project.board) {
+ Consistence = 1;
+ HeaderErcErrors = "Baord and schematic are consistent";
+ if (language() == "de") HeaderErcErrors = "Board und Schaltplan sind konsistent";
+ }
+ else Consistence = 0;
+
+ SCH.errors(E) {
+ if (E.type == ERROR_TYPE_CONSISTENCY) CntErrorInconsistenc++;
+ ErrSignature[CntError] = E.signature;
+ ErrSx1[CntError] = E.area.x1;
+ ErrSy1[CntError] = E.area.y1;
+ ErrSx2[CntError] = E.area.x2;
+ ErrSy2[CntError] = E.area.y2;
+ ErrBx1[CntError] = E.area2.x1;// Das Member area2 ist eine zweite UL_AREA, die nur im Schaltplan bei einzelnen ERC-Fehlern die entsprechende Region im Board angibt.
+ ErrBy1[CntError] = E.area2.y1;
+ ErrBx2[CntError] = E.area2.x2;
+ ErrBy2[CntError] = E.area2.y2;
+
+ ErrCode[CntError] = E.code;
+ ErrDescription[CntError] = E.description;
+ ErrLayer[CntError] = E.layer;
+ ErrModulename[CntError] = E.modulename;
+ ErrS1[CntError] = E.s1;
+ ErrS2[CntError] = E.s2;
+ ErrS3[CntError] = E.s3;
+ ErrS4[CntError] = E.s4;
+ ErrS5[CntError] = E.s5;
+ ErrS6[CntError] = E.s6;
+
+ ErrX[CntError] = E.x;
+ ErrY[CntError] = E.y;
+ ErrSheet[CntError] = E.sheet;
+ ErrState[CntError] = E.state;
+ ErrType[CntError] = E.type;
+ if (Debug) checkerror(CntError);
+ sprintf(ErrorList[CntError], "%s\t%s\t%d\t%s\t%s\t%s\t%d\t%d\t%d\t%d",
+ ErrorType[E.type],
+ E.description,
+ E.sheet,
+ E.modulename,
+ E.signature,
+ ErrorState[E.state],
+ ErrSx1[CntError],
+ ErrSy1[CntError],
+ ErrSx2[CntError],
+ ErrSy2[CntError]
+ );
+ CntError++;
+ }
+ if (CntErrorInconsistenc) {
+ sprintf(HeaderErcErrors, "Consistence Error(%d).", CntErrorInconsistenc);
+ if (language() == "de") sprintf(HeaderErcErrors, "Konsistenzfehler (%d)", CntErrorInconsistenc);
+ }
+ else {
+ if (Consistence) {
+ HeaderErcErrors = "Board and Schematic are consistent.";
+ if (language() == "de") HeaderErcErrors = "Board und Schematic sind konsistent";
+ }
+ }
+
+ if (Option1 == "SAVE") {
+ if (!argv[2]) {
+ SaveErrorFileName = filesetext(SCH.name, ".erc.err");
+ saveerrors("Save ERC-ERRORS", SCH.name, SaveErrorFileName);
+ }
+ else {
+ SaveErrorFileName = argv[2];
+ }
+ savefile(SaveErrorFileName, SCH.name);
+ }
+ else {
+ SaveErrorFileName = filesetext(SCH.name, ".erc.err");
+ string listheader = "Type\tDesciption\tSheet\tModul\tSignatur\tState\tAreaX1\tAreaY1\tAreaX2\tAreaY2";
+ if (language() == "de") listheader = "Type\tBeschreibung\tSeite\tModul\tSignatur\tStatus\tAreaX1\tAreaY1\tAreaX2\tAreaY2";
+ saveerrdialog("ERRORS ERC)", listheader, SCH.name);
+ }
+ }
+}
+
+else if (board) {
+ board(BRD) {
+ if (!BRD.checked) {
+ string msg = "Board is changed, first start Design Rile Check (DRC)!";
+ if (language() == "de") msg = "Board wurde verändert, starten sie zuerst den Design Rule Check! (DRC)";
+ if (dlgMessageBox(msg, "OK", "CANCEL") != 0) exit(-4);
+
+ string cmd;
+ sprintf(cmd, "DRC; RUN '%s'", argv[0]);
+ exit (cmd);
+ }
+ ExistBRDfile = "BRD File loaded: " + BRD.name;
+ ExistSCHfile = "SCH File exist : " + checkexistfile(filesetext(BRD.name, ".sch"));
+
+ if(project.schematic) {
+ Consistence = 1;
+ }
+ else Consistence = 0;
+ BRD.errors(E) {
+ ErrSignature[CntError] = E.signature;
+ ErrSx1[CntError] = E.area.x1;
+ ErrSy1[CntError] = E.area.y1;
+ ErrSx2[CntError] = E.area.x2;
+ ErrSy2[CntError] = E.area.y2;
+ ErrBx1[CntError] = E.area2.x1;// Das Member area2 ist eine zweite UL_AREA, die nur im Schaltplan bei einzelnen ERC-Fehlern die entsprechende Region im Board angibt.
+ ErrBy1[CntError] = E.area2.y1;
+ ErrBx2[CntError] = E.area2.x2;
+ ErrBy2[CntError] = E.area2.y2;
+
+ ErrCode[CntError] = E.code;
+ ErrDescription[CntError] = E.description;
+ ErrLayer[CntError] = E.layer;
+ ErrModulename[CntError] = E.modulename;
+ ErrS1[CntError] = E.s1;
+ ErrS2[CntError] = E.s2;
+ ErrS3[CntError] = E.s3;
+ ErrS4[CntError] = E.s4;
+ ErrS5[CntError] = E.s5;
+ ErrS6[CntError] = E.s6;
+
+ ErrX[CntError] = E.x;
+ ErrY[CntError] = E.y;
+ ErrSheet[CntError] = E.sheet;
+ ErrState[CntError] = E.state;
+ ErrType[CntError] = E.type;
+ if (Debug) checkerror(CntError);
+ sprintf(ErrorList[CntError], "%s\t%s\t%d\t%s\t%s\t%d\t%d\t%d\t%d\t%s",
+ ErrorType[E.type],
+ E.description,
+ E.layer,
+ E.signature,
+ ErrorState[E.state],
+ ErrSx1[CntError],
+ ErrSy1[CntError],
+ ErrSx2[CntError],
+ ErrSy2[CntError],
+ ""
+ );
+ CntError++;
+ }
+ sprintf(HeaderErcErrors, "Error (%d)", CntError);
+ if (language() == "de") sprintf(HeaderErcErrors, "Fehler (%d)", CntError);
+
+ if (Option1 == "SAVE") {
+ if (!argv[2]) {
+ SaveErrorFileName = filesetext(BRD.name, ".drc.err");
+ saveerrors("Save DRC-ERRORS", BRD.name, SaveErrorFileName);
+ }
+ else {
+ SaveErrorFileName = argv[2];
+ }
+ savefile(SaveErrorFileName, BRD.name);
+ }
+ else {
+ SaveErrorFileName = filesetext(BRD.name, ".drc.err");
+ string listheader = "Type\tDesciption\tLayer\tSigatur\tState\tAreaX1\tAreaY1\tAreaX2\tAreaY2";
+ if (language() == "de") listheader = "Type\tBeschreibung\tLayer\tSigatur\tStatus\tAreaX1\tAreaY1\tAreaX2\tAreaY2";
+ saveerrdialog("ERRORS DRC", listheader, BRD.name);
+ }
+ }
+}
+
+else {
+ dlgMessageBox("Start this ULP in a schematic or board.", "OK");
+ exit(0);
+}
+
diff --git a/trunk/ulp/export-ict-netlist-pad-coordinates.ulp b/trunk/ulp/export-ict-netlist-pad-coordinates.ulp
new file mode 100644
index 00000000..7fa78088
--- /dev/null
+++ b/trunk/ulp/export-ict-netlist-pad-coordinates.ulp
@@ -0,0 +1,100 @@
+#usage "Export In-Circuit-Test net list with pad/smd coordinates"
+ "Exported format: Net Part.Pad Layer X Y "
+ "support@cadsoft.de"
+
+string Version = " Version 1.0"; // 2008-05-14 alf@cadsoft.de
+int withSignal = 0;
+
+if (strupr(argv[1]) == "NOSIGNAL") withSignal = 1;
+
+string list, s;
+string lTop = "t";
+string lBottom = "b";
+
+void sortnet(void) {
+ string s[];
+ int n;
+ int index[], i;
+ n = strsplit(s, list, '\n');
+ sort(n, index, s);
+ list = "";
+ for (i = 0; i < n; i++) {
+ list += s[index[i]] + "\n";
+ }
+ return;
+}
+
+
+if (board) {
+ board(B) {
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.signal || withSignal) {
+ string cLayer;
+ if (C.smd) {
+ if (C.smd.layer == 1) cLayer = lTop;
+ else cLayer = lBottom;
+ sprintf(s, "%s\t%s.%s\t%s\t%.4f\t%.4f\n",
+ C.signal,
+ E.name,
+ C.name,
+ cLayer,
+ u2mm(C.x),
+ u2mm(C.y)
+ );
+ list += s;
+ }
+ else {
+ sprintf(s, "%s\t%s.%s\t%s\t%.4f\t%.4f\n",
+ C.signal,
+ E.name,
+ C.name,
+ lTop,
+ u2mm(C.x),
+ u2mm(C.y)
+ );
+ list += s;
+ sprintf(s, "%s\t%s.%s\t%s\t%.4f\t%.4f\n",
+ C.signal,
+ E.name,
+ C.name,
+ lBottom,
+ u2mm(C.x),
+ u2mm(C.y)
+ );
+ list += s;
+ }
+ }
+ }
+ }
+ sortnet();
+ list = "# Data export with " + filename(argv[0]) + Version + "\n# at: "+ t2string(time()) + " from: "+filename(B.name) + "\n# " + EAGLE_SIGNATURE + "\n# Testpoint for In-Circuit-Test (Coordinates in mm)\nNet\tPart.Pad\tLayer\tX\tY\n" + list;
+ string f = filesetext(B.name, ".ict");
+ dlgDialog("ICT Netlist") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(600);
+ dlgVBoxLayout {
+ dlgTextEdit(list);
+ }
+ }
+ dlgLabel("If you want this list with unconnected pads start with: RUN export-ict-netlist-pad-coordinates.ulp NOSIGNAL");
+ dlgLabel("Save as: "+f);
+ dlgHBoxLayout {
+ dlgPushButton("OK") {
+ dlgAccept();
+ {
+ output(f, "wt") printf("%s", list);
+ }
+ }
+ dlgPushButton("-CANCEL") {
+ dlgReject();
+ exit(-1);
+ }
+ dlgStretch(1);
+ }
+ };
+ }
+}
+
+else dlgMessageBox("Start this ULP from a Board", "OK");
diff --git a/trunk/ulp/export-protelnet.ulp b/trunk/ulp/export-protelnet.ulp
new file mode 100644
index 00000000..e4d236e4
--- /dev/null
+++ b/trunk/ulp/export-protelnet.ulp
@@ -0,0 +1,91 @@
+/*
+ * This EAGLE User Language Program prints the netlist of a board
+ * in standard Protel format (1.0) (very similar to Tango netlist format)
+ * to import it to Protel PCB software.
+ *
+ * It is also possible to print the netlist of a schematic,
+ * but this will not adhere to the correct Protel format:
+ * package names are missing, pin names instead of pad names.
+ *
+ * If you have only the schematic, just generate the board and run this
+ * ULP in the EAGLE board editor.
+ *
+ * 19.09.2001 Hans Lederer, Ingenieurbüro Lederer, Emmendingen
+ * Hans.Lederer@ib-lederer.de
+ */
+
+if (board) board(B) {
+ output(filesetext(B.name, ".NET")) {
+
+ B.elements(E) {
+ printf("%s\n","[");
+ printf("%s\n",E.name);
+ printf("%s\n",E.package.name);
+ printf("%s\n",E.value);
+ printf("\n\n\n%s\n","]");
+ }
+
+ B.signals(S) {
+ numeric string Part[], Pad[];
+ int cnt = 0, index[];
+
+ S.contactrefs(C) {
+ Part[cnt] = C.element.name;
+ Pad[cnt] = C.contact.name;
+ cnt++;
+ }
+ if (cnt) {
+ sort(cnt, index, Part, Pad);
+ printf("%s\n","(");
+ printf("%s\n",S.name);
+ for (int i = 0; i < cnt; i++)
+ printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]);
+ printf("%s\n",")");
+ }
+ }
+ }
+ }
+
+if (schematic) schematic(SCH) {
+ output(filesetext(SCH.name, ".net")) {
+
+ SCH.parts(P) {
+ int pos_g = strrstr(P.device.name,"GND");
+ int pos_v = strrstr(P.device.name,"VCC");
+
+ if ((pos_g < 0) && (pos_v < 0)) {
+ string pkg = P.device.package.name;
+ int dip_dil = strrstr(pkg,"DIL");
+ if ( dip_dil >= 0)
+ pkg[2]='P';
+ printf("%s\n","[");
+ printf("%s\n",P.name);
+ printf("%s\n",pkg);
+ printf("%s\n",P.device.name);
+ printf("\n\n\n%s\n","]");
+ }
+ }
+
+ SCH.nets(N) {
+ numeric string Part[], Pin[], trimmed, Pad[];
+ int cnt = 0, index[];
+
+ N.pinrefs(P) {
+ Part[cnt] = P.part.name;
+ Pin[cnt] = P.pin.name;
+ Pad[cnt] = P.pin.contact.name;
+ cnt++;
+ }
+
+ if (cnt) {
+ sort(cnt, index, Part, Pin);
+ printf("%s\n","(");
+ printf("%s\n",N.name);
+ for (int i = 0; i < cnt; i++) {
+ printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]);
+ }
+ printf("%s\n",")");
+ }
+ }
+ }
+ }
diff --git a/trunk/ulp/export-protelpcb.ulp b/trunk/ulp/export-protelpcb.ulp
new file mode 100644
index 00000000..b3fdbdfc
--- /dev/null
+++ b/trunk/ulp/export-protelpcb.ulp
@@ -0,0 +1,432 @@
+#usage "Export PCB project to Protel .PCBDOC (ASCII)"
+ "
"
+ "This ULP script tries to export PCB file which can be opened by Protel. "
+ "It is probably not bug-free as well as it seems to be impossible to export "
+ "with 100% accuracy so use at your own risk and check the results carefully."
+ "
"
+ "Bugs"
+ "
"
+ "Units are always English for now. "
+ "Polygons are not exported. "
+ "Vias are always exported round. Protel does not have other via shapes. "
+ "Board outline is lost and must be restored from Mechanical 1 (Protel DXP only). "
+ "Not all layers exported correctly. "
+ "
"
+ "Important Notice\n"
+ "
"
+ "This script is NOT designed to replace Protel. "
+ "As Protel file format is proprietary, "
+ "use of this script for purposes other than migrating from Eagle to Protel "
+ "may be illegal due to copyright laws. The author will not be liable for any illegal "
+ "use of this script."
+ "
"
+ "This ULP can convert an Eagle schematic into an ALTIUM schematic."
+ "
"
+ "Load any schematic and execute the ULP in the eagle."
+
+
+/* ==========================================================================
+ * This script is based on the eagle2kicad_sch.ULP from Juergen Messerer which
+ * was released under the license of the GNU Public license Version 2.
+ * Adaption was made by Christian Keller (retrochris (at) web.de)
+ * ==========================================================================*/
+
+/*
+ * CHANGELOG================================================
+ *
+ * 08.12.2009: Version 1.1:
+ * minor issue fixed preventing V5.x creating correct results
+ * file naming scheme corrected
+ * 18.11.2009: printf was causing an error if a value contains the char '%' (e.g. 10k/1%), heiko.schedletzky (at) grossfunk.de
+ * 05.11.2009: Initial Version 1
+ *
+ */
+
+/* ==========================================================================
+ * License: This file is released under the license of the GNU Public license
+ * Version 2.
+ * ==========================================================================*/
+
+
+
+ string sch_name = "";
+
+//------------------------------------------------------
+//Records
+//------------------------------------------------------
+
+string HeaderRecord (int val)
+{
+ string s;
+ sprintf (s, "|HEADER=Protel for Windows - Schematic Capture Ascii File Version 5.0|WEIGHT=%d\n" , val);
+ return s;
+}
+
+//------------------------------------------------------
+// Optimize Text for output with printf
+// 18.11.2009 - heiko.schedletzky (at) grossfunk.de
+//------------------------------------------------------
+
+string FixText(string src)
+{
+ // problem : printf is causing an error if a value contains the char '%' (e.g. 10k/1%)
+ // solution : '%' is substituted with '_'
+
+ string tarray[];
+ strsplit(tarray,src,'%');
+ return strjoin(tarray,'_');
+}
+
+//------------------------------------------------------
+//convert string
+//------------------------------------------------------
+string ConvString(string text)
+{
+ int i;
+ int Felder;
+ string helper;
+
+ helper="";
+
+
+ for (i=0;i0)
+ mirrored="T";
+
+
+ orientation=0;
+// if (I.angle==90) orientation=1;
+// if (I.angle==180) orientation=2;
+// if (I.angle==270) orientation=3;
+ if (I.angle==90)
+ if(I.mirror==0) orientation=1;
+ else
+ orientation=3;
+ if (I.angle==180) orientation=2;
+ if (I.angle==270)
+ if(I.mirror==0) orientation=3;
+ else
+ orientation=1;
+
+ x=int(u2mil(I.x)/10);
+ y=int(u2mil(I.y)/10);
+
+ string s;
+ sprintf (s, "|RECORD=1|LIBREFERENCE=%s|PARTCOUNT=%d|DISPLAYMODECOUNT=1|ISMIRRORED=%s|INDEXINSHEET=%d|OWNERPARTID=-1|LOCATION.X=%d|LOCATION.Y=%d|ORIENTATION=%d|CURRENTPARTID=%d|LIBRARYPATH=*|SOURCELIBRARYNAME=%s|TARGETFILENAME=*|AREACOLOR=11599871|COLOR=128|PARTIDLOCKED=F|DESIGNITEMID=%s\n",P.device.name,partcount, mirrored,Record ,x,y,orientation,part,I.gate.symbol.library,P.device.name);
+ return s;
+}
+
+
+//------------------------------------------------------
+string PinRecord (UL_PIN P, int owner,int owner2,int ownerpartid)
+{
+
+ int PinLength;
+ int x;
+ int y;
+ int PinConglomerate;
+ string designator;
+ string pinsymbol;
+
+
+ pinsymbol="";
+ if (P.function==PIN_FUNCTION_FLAG_CLK)
+ pinsymbol="SYMBOL_INNEREDGE=3|";
+ if (P.function==PIN_FUNCTION_FLAG_DOT)
+ pinsymbol="SYMBOL_OUTEREDGE=1|";
+
+ x=int(u2mil(P.x)/10);
+ y=int(u2mil(P.y)/10);
+
+ if (P.length==PIN_LENGTH_POINT) PinLength=0;
+ if (P.length==PIN_LENGTH_SHORT) PinLength=10;
+ if (P.length==PIN_LENGTH_MIDDLE) PinLength=20;
+ if (P.length==PIN_LENGTH_LONG) PinLength=30;
+
+ PinConglomerate=32;
+
+
+ if (P.visible==PIN_VISIBLE_FLAG_OFF) PinConglomerate+=0;
+ else
+ if (P.visible==PIN_VISIBLE_FLAG_PIN) PinConglomerate+=8;
+ else
+ if (P.visible==PIN_VISIBLE_FLAG_PAD) PinConglomerate+=16;
+ else
+ PinConglomerate+=24;
+
+ if (P.angle==0) {
+ PinConglomerate+=2;
+ x=x+PinLength;}
+ if (P.angle==90) {
+ PinConglomerate+=3;
+ y=y+PinLength;}
+ if (P.angle==180) {
+ PinConglomerate+=0;
+ x=x-PinLength;}
+ if (P.angle==270) {
+ PinConglomerate+=1;
+ y=y-PinLength;}
+
+ if (!P.contact)
+ designator="0";
+ else
+ designator=P.contact.name;
+
+ string s;
+ sprintf (s, "|RECORD=2|OWNERINDEX=%d|OWNERPARTID=%d|%sFORMALTYPE=1|ELECTRICAL=4|PINCONGLOMERATE=%d|PINLENGTH=%d|LOCATION.X=%d|LOCATION.Y=%d|NAME=%s|DESIGNATOR=%s|SWAPIDPART=1\n",owner,ownerpartid,pinsymbol,PinConglomerate,PinLength,x,y,P.name, designator);
+
+ return s;
+}
+
+
+
+
+//------------------------------------------------------
+string LabelRecord (UL_TEXT T,int Ownerindex, int Ownerpart){
+
+ string s;
+ int x;
+ int y;
+ int orientation;
+
+ orientation=0;
+ if (T.angle==90) orientation=1;
+ if (T.angle==180) orientation=2;
+ if (T.angle==270) orientation=3;
+
+
+ x=int(u2mil(T.x)/10);
+ y=int(u2mil(T.y)/10);
+
+ sprintf (s, "|RECORD=4|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|ORIENTATION=%d|COLOR=8388608|FONTID=1|TEXT=%s\n",Ownerindex, Ownerpart, x,y,orientation,T.value);
+
+ return s;
+}
+
+
+//------------------------------------------------------
+
+string PolygonRecord (UL_POLYGON P,int Ownerindex, int Ownerpart)
+{
+ int x;
+ int y;
+ int count=1;
+ string helper="";
+ string helper2="";
+
+ string s;
+ sprintf (s, "|RECORD=7|OWNERINDEX=%d|OWNERPARTID=%d|COLOR=16711680|AREACOLOR=12632256|ISSOLID=T",Ownerindex,Ownerpart );
+
+ P.contours(C){
+ x=int(u2mil(C.x1)/10);
+ y=int(u2mil(C.y1)/10);
+
+ sprintf (helper, helper+ "|X%d=%d|Y%d=%d",count,x,count,y );
+ count+=1;
+
+ }
+
+ sprintf (helper2, "|LOCATIONCOUNT=%d",(count-1));
+ sprintf (s, s+helper2+helper+"\n");
+
+
+ return s;
+}
+
+
+//------------------------------------------------------
+string ArcRecord (UL_CIRCLE C, int Record, int Index, int Owner){
+
+ string s;
+ int x;
+ int y;
+ int r;
+
+ x=int(u2mil(C.x)/10);
+ y=int(u2mil(C.y)/10);
+ r=int(u2mil(C.radius)/10);
+
+ sprintf (s, "|RECORD=12|INDEXINSHEET=%d|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|RADIUS=%d|RADIUS_FRAC=0|LINEWIDTH=1|STARTANGLE=0|ENDANGLE=0|COLOR=16711680\n",Record, Index,Owner,x,y,r );
+ return s;
+}
+
+
+//------------------------------------------------------
+string LineRecord (UL_WIRE W,int Records,int Owner, int ownerpartid)
+{
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ int r;
+
+ string s;
+
+ x1=int(u2mil(W.x1)/10);
+ y1=int(u2mil(W.y1)/10);
+ x2=int(u2mil(W.x2)/10);
+ y2=int(u2mil(W.y2)/10);
+
+ if (W.curve==0)
+ sprintf (s, "|RECORD=13|OWNERINDEX=%d|ISNOTACCESIBLE=T|INDEXINSHEET=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|CORNER.X=%d|CORNER.Y=%d|LINEWIDTH=1|COLOR=16711680\n",Owner,Records,ownerpartid, x1,y1,x2,y2);
+
+ else{
+ x1=int(u2mil(W.arc.xc)/10);
+ y1=int(u2mil(W.arc.yc)/10);
+ r=int(u2mil(W.arc.radius)/10);
+
+ sprintf (s, "|RECORD=12|OWNERINDEX=%d|INDEXINSHEET=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|RADIUS=%d|RADIUS_FRAC=0|LINEWIDTH=1|STARTANGLE=%f|ENDANGLE=%f|COLOR=16711680\n",Owner,Records,ownerpartid,x1,y1,r, W.arc.angle1, W.arc.angle2 );
+ }
+
+ return s;
+}
+
+
+//------------------------------------------------------
+string RectangleRecord (UL_RECTANGLE R,int Records,int Owner)
+{
+
+ string s;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ int xt1;
+ int yt1;
+ int xt2;
+ int yt2;
+ int x;
+ int y;
+ real winkel;
+
+ x1=int(u2mil(R.x1)/10);
+ y1=int(u2mil(R.y1)/10);
+ x2=int(u2mil(R.x2)/10);
+ y2=int(u2mil(R.y2)/10);
+
+ x=(x1+x2)/2;
+ y=(y1+y2)/2;
+
+
+ y1=y-y1+y;
+ y2=y-y2+y;
+
+ winkel=PI/180*R.angle;
+
+ xt1=(x1-x)*cos(winkel)+(y1-y)*sin(winkel+PI)+x;
+ yt1=(x1-x)*sin(winkel)+(y1-y)*cos(winkel)+y;
+ xt2=x-(xt1-x);
+ yt2=y-(yt1-y);
+
+
+ sprintf (s, "|RECORD=14|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|CORNER.X=%d|CORNER.Y=%d|COLOR=8388608|AREACOLOR=8388608|ISSOLID=T\n",Records, Owner, xt1,yt1,xt2,yt2);
+ return s;
+
+}
+
+
+//------------------------------------------------------
+string PowerObjectRecord (int x,int y, int owner)
+{
+
+ string s;
+
+ x=int(u2mil(x)/10);
+ y=int(u2mil(y)/10);
+
+ sprintf (s, "|RECORD=17|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|COLOR=128|TEXT=OffSheet|ISCROSSSHEETCONNECTOR=T",owner, x,y);
+ return s;
+
+}
+
+
+//------------------------------------------------------
+string NetLabelRecord (string name, int x, int y)
+{
+ x=int(u2mil(x)/10);
+ y=int(u2mil(y)/10);
+
+ string s;
+ sprintf (s, "|RECORD=25|OWNERPARTID=-1|LOCATION.X=%d|LOCATION.Y=%d|COLOR=128|FONTID=1|TEXT=%s\n", x,y,name);
+ return s;
+}
+
+
+//------------------------------------------------------
+
+string BusRecord (int x1,int y1,int x2,int y2)
+{
+
+ string s;
+ int cx1;
+ int cy1;
+ int cx2;
+ int cy2;
+
+ cx1=int(u2mil(x1)/10);
+ cy1=int(u2mil(y1)/10);
+ cx2=int(u2mil(x2)/10);
+ cy2=int(u2mil(y2)/10);
+
+ sprintf (s, "|RECORD=26|OWNERPARTID=-1|LINEWIDTH=1|COLOR=8388608|LOCATIONCOUNT=2|X1=%d|Y1=%d|X2=%d|Y2=%d\n",cx1,cy1,cx2,cy2);
+
+ return s;
+
+}
+
+
+//------------------------------------------------------
+string WireRecord (UL_WIRE W,int Records,int Owner)
+{
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+ string s;
+
+ x1=int(u2mil(W.x1)/10);
+ y1=int(u2mil(W.y1)/10);
+ x2=int(u2mil(W.x2)/10);
+ y2=int(u2mil(W.y2)/10);
+
+ sprintf (s, "|RECORD=27|INDEXINSHEET=%d|OWNERPARTID=%d|LINEWIDTH=1|COLOR=8388608|LOCATIONCOUNT=2|X1=%d|Y1=%d|X2=%d|Y2=%d\n",Owner,Records, x1,y1,x2,y2);
+
+ return s;
+}
+
+
+//------------------------------------------------------
+string JunctionRecord (int x, int y)
+{
+
+ x=int(u2mil(x)/10);
+ y=int(u2mil(y)/10);
+
+ string s;
+ sprintf (s, "|RECORD=29|OWNERPARTID=-1|LOCATION.X=%d|LOCATION.Y=%d|COLOR=128|LOCKED=T\n",x ,y);
+ return s;
+}
+
+
+//------------------------------------------------------
+string ImplementationListRecord (int Owner)
+ {
+
+ string s;
+ sprintf (s, "|RECORD=44|OWNERINDEX=%d\n",Owner);
+ return s;
+ }
+
+
+//------------------------------------------------------
+string SheetRecord (UL_SHEET SCH)
+{
+
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+
+ x1=int(u2mil(SCH.area.x1)/10);
+ y1=int(u2mil(SCH.area.y1)/10);
+ x2=int(u2mil(SCH.area.x2)/10);
+ y2=int(u2mil(SCH.area.y2)/10);
+
+ string s;
+ sprintf (s, "|RECORD=31|FONTIDCOUNT=1|SIZE1=10|FONTNAME1=Times New Roman|USEMBCS=T|ISBOC=T|HOTSPOTGRIDON=T|HOTSPOTGRIDON=T|HOTSPOTGRIDSIZE=4|SYSTEMFONT=1|SHEETNUMBERSPACESIZE=4|AREACOLOR=16317695|SNAPGRIDON=T|SNAPGRIDSIZE=10|VISIBLEGRIDON=T|VISIBLEGRIDSIZE=10|CUSTOMX=%d|CUSTOMY=%d|USECUSTOMSHEET=T|REFERENCEZONESON=T|CUSTOMXZONES=6|CUSTOMYZONES=4|CUSTOMMARGINWIDTH=20|DISPLAY_UNIT=4\n",x2-x1,y2-y1);
+ return s;
+
+}
+
+
+//------------------------------------------------------
+string DesignatorRecord (int Owner, string T, int x, int y, int angle, int ownerpartid, string ishidden)
+{
+
+ string s;
+
+ x=int(u2mil(x)/10);
+ y=int(u2mil(y)/10);
+
+ int orientation;
+
+ orientation=0;
+ if (angle==90) orientation=1;
+ if (angle==180) orientation=2;
+ if (angle==270) orientation=3;
+
+
+ sprintf (s, "|RECORD=34|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|COLOR=8388608|FONTID=1|TEXT=%s|ORIENTATION=%d|ISHIDDEN=%s|NAME=Designator\n",Owner,ownerpartid,x,y,T,orientation,ishidden);
+ return s;
+}
+
+
+//------------------------------------------------------
+string ParameterRecord (int Owner,string name, string text,int x, int y, int ownerpart, string hidden)
+{
+
+ string s;
+
+ x=int(u2mil(x)/10);
+ y=int(u2mil(y)/10);
+
+ int orientation;
+
+ orientation=0;
+// if (I.angle==90) orientation=1;
+// if (I.angle==180) orientation=2;
+// if (I.angle==270) orientation=3;
+
+ sprintf (s, "|RECORD=41|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|COLOR=8388608|FONTID=1|TEXT=%s|ISHIDDEN=%s|NAME=%s\n",Owner, ownerpart,x,y,text,hidden,name);
+ return s;
+}
+
+
+//------------------------------------------------------
+string ImplementationRecord (int Owner, UL_PART P){
+
+ string s;
+
+ sprintf (s, "|RECORD=45|OWNERINDEX=%d|INDEXINSHEET=-1|DESCRIPTION=%s|USECOMPONENTLIBRARY=T|MODELNAME=%s|MODELTYPE=PCBLIB|DATAFILECOUNT=1|MODELDATAFILEENTITY0=%s|MODELDATAFILEKIND0=PCBLib|ISCURRENT=T|DATALINKSLOCKED=T|DATABASEDATALINKSLOCKED=T|INTEGRATEDMODEL=F|DATABASEMODEL=T\n",Owner, P.device.package.headline,P.device.package.name,P.device.package.name);
+
+ return s;
+}
+
+//------------------------------------------------------
+
+
+//------------------------------------------------------
+// Parts erzeugen
+//------------------------------------------------------
+
+int MakePart(UL_SYMBOL S, UL_PART P, int OwnerPart, int Records, int partcount){
+
+// printf("*** Bauteil ***\n");
+
+ S.pins(Pi){
+ printf(PinRecord(Pi,OwnerPart-2,Records,partcount));
+ Records+=1;
+ if (Pi.direction==PIN_DIRECTION_SUP){
+ printf(NetLabelRecord(Pi.net, Pi.x, Pi.y));
+ Records+=1;
+
+ }
+
+ }
+
+
+ S.wires(W){
+ printf(LineRecord(W,Records,OwnerPart-2,partcount));
+ Records+=1;
+ }
+
+
+
+
+ S.texts(T){
+
+ if ((T.layer != LAYER_NAMES) && (T.layer != LAYER_VALUES)){
+ printf(LabelRecord(T,OwnerPart-2,partcount));
+ Records+=1;
+ }
+ }
+
+ S.rectangles(R){
+ printf(RectangleRecord(R,OwnerPart-2,partcount));
+ Records+=1;
+ }
+
+
+ S.polygons(Poly){
+ printf(PolygonRecord(Poly,OwnerPart-2,partcount));
+ Records+=1;
+ }
+
+
+
+return Records;
+
+}
+
+//------------------------------------------------------
+//write index of modules
+//------------------------------------------------------
+void write_sch( string fileName ){
+
+string CopyHelp[];
+string FileNameNumbered;
+int Records=1;
+int OwnerPart;
+int SchaltplanSeite=1;
+int i;
+int Technik;
+int Footprint;
+int partcount;
+int part;
+int CommentLayer=0;
+int DesignatorLayer=0;
+string name;
+string konstrukt;
+int designatorflag;
+int commentflag;
+
+ schematic(S){
+
+ S.sheets(SCH){
+
+ Records=1;
+ sprintf(FileNameNumbered,fileName+"_%d.SchDoc",SchaltplanSeite);
+ SchaltplanSeite+=1;
+
+ output(FileNameNumbered, "Fwt") {
+
+
+ printf(SheetRecord(SCH));
+ Records+=1;
+
+
+
+// ********************************************** Bauteile **************************************
+ SCH.parts(P){
+ P.instances(I){
+
+
+
+ // wieviele parts hat die komponente ?
+
+ partcount=2;
+ part=1;
+ S.libraries(L) {
+ L.devicesets(D) {
+ if (D.name==P.deviceset.name){
+ partcount=1;
+ part=1;
+ D.gates(G) {
+ if ((P.name+G.name)==I.name)
+ part=partcount;
+ partcount+=1;
+
+ }
+ }
+ }
+ }
+ printf(PartRecord(I,P,part,partcount,Records));
+ Records+=1;
+ OwnerPart=Records;
+
+ S.libraries(L) {
+ if (P.deviceset.library==L.name){
+
+ L.devicesets(D) {
+
+
+ if (D.name==P.deviceset.name) {
+
+ D.devices(devi){
+
+
+ konstrukt="";
+ name=D.name;
+ Technik=0;
+ Footprint=0;
+
+
+
+ for (i=0;iGenerate EAGLE Output in Fabmaster Format FATF REV 11.1
\n"
+ "See program text for more information
"
+ "ULP Rev. 1.46 "
+ "Author: support@cadsoft.de"
+
+string ULPversion = "V1.46"; // 2013-07-01 alf@cadsoft.de
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// ASCII Transfer Format (FATF) FABmaster software V8.E - 11 August 2000 //
+// FABMASTER FATF REV 11.1 //
+// //
+// Rev. 1.46: correct funktion validname () add chenge '(' to '_' //
+// 2013-10-24 by alf@cadsoft.de //
+// //
+// Rev. 1.45: Comma ends the last line //
+// 2013-07-01 by alf@cadsoft.de //
+//
+// Rev. 1.44: message exportet to path/file //
+// 2012-12-19 by alf@cadsoft.de //
+// //
+// Rev. 1.43: corrected request in loop S.contactrefs(C) { => if (C.contact) { //
+// 2011-03-30 by alf@cadsoft.de //
+// //
+// Rev. 1.42: quick find pin-name part-name //
+// 2009-12-04 by support@cadsoft.de //
+// //
+// Rev. 1.41: Corrected LAYER_NAMES definition for BPLACE //
+// March 2007 by support@cadsoft.de //
+// //
+// Revision 1.4: Export Layer 51/52 (Layer table expanded) //
+// Febr. 2007 support@cadsoft.de //
+// //
+// Revision 1.3: Export Wires with Arc, rotated Pads, Pad Shape Long & Offset //
+// rotated Packages in 0.1 degree //
+// export rectangle and circle on layer 1, 16, 21, 22 //
+// export polygon filling on klayer 1, 16 //
+// export text on layer 1,16,21,22 as wire (**vector font**) //
+// Mai 2004 by support@cadsoft.de //
+///////////////////////////////////////////////////////////////////////////////////////////
+// Revision 1.2: Slightly changed in the output statement, so that the Fabmaster file //
+// will be written in the same directory as the brd file is. //
+// November 2001 by support@cadsoft.de //
+///////////////////////////////////////////////////////////////////////////////////////////
+// Revision 1.1: Runs with EAGLE version >= 4; top pad shape assumed for all layers;
+// fixed bug in EAGLE version output
+///////////////////////////////////////////////////////////////////////////////////////////
+// Rudi Hofer, CadSoft, rudi.hofer@cadsoft.de, 9/99
+//
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND,
+// EXPRESSED OR IMPLIED.
+//
+// This ULP generates output for FABMASTER software which is able to convert the
+// data for automatic mounting and test equipment. The resolution is fixed to 1 mil.
+//
+// To generate the output, load the board and run this ULP from the board window.
+//
+// Restrictions and prerequisites:
+// - Board outline must be defined as wires in dimension layer (directly in
+// board or in a package).
+// - All coordinates must be positive!!! Please move the board accordingly!!!
+// - Do not use different packages with the same name (avoid REPLACE command).
+// - Padtypes octagon, xlongoct, ylongoct are realized with round shapes.
+// - For polygons no output is generated.
+// - Inner layer Route2..5 may contain tracks.
+// - Inner layer Route6 may contain a power plain (no output generated yet!).
+// - For all other inner layers no output is generated.
+// - On the top and bottom layers only wires and smd pads are output.
+// Exception: Circles defined in a package are output as filled circles
+// but do not belong to a signal.
+//
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#require 4.1602
+
+
+string jobname,
+ layer_name[],
+ padshape[] = {"P_ROUND","P_ROUND","P_ROUND","P_ROUND","P_ROUND"},// if long/offset subst. by round
+ viashape[] = {"P_BLOCK","P_ROUND","P_ROUND","P_ROUND","P_ROUND"},// if long/offset subst. by round
+ padname,
+ shapename[], // package names
+ t[], // padtypes
+ pst[]; // padstacktypes
+
+real cx, cy, rx, ry, x, y, x1, x2, y1, y2, r, a1, a2;;
+real delta = 5;
+
+int i, new, sx,
+ padcount,
+ pad_is_numeric,
+ // eagle to fabmaster layer conversion
+ // eagle 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52 ** Feb. 2007 **
+ flayer[] = {0, 2, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0,16,16,17, 0, 0,18,19,20,21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,16,17};
+
+string partnumname[]; // 2009-12-03 quick find pin-name part-name
+int cntnumname = 0;
+
+numeric string areaEname[];
+int indexareaEname[];
+int cntindex = 1;
+ // create pad number index list
+numeric string areaEpadname[];
+int areaPadNumber[]; // the number of pad in FATF format
+int cntEpad = 1;
+
+
+int sizes[], ratio[]; // Text fonts
+int cntt = 0;
+int boardroundness = 100; // global roundness (design rules)
+
+int xmin = 32000, xmax = 0, ymin = 32000, ymax = 0;
+
+int ht = time();
+
+//-----------------------------------------------------
+string validname (string s) {
+ int i;
+ for (i = 0; s[i]; i++) {
+ if (s[i] == ',') s[i] = '_';
+ if (s[i] == ';') s[i] = '_';
+ if (s[i] == ')') s[i] = '_';
+ if (s[i] == '(') s[i] = '_'; // 2013-10-24
+ // add further substitutions here
+ }
+ return s;
+}
+//-----------------------------------------------------
+int fablayer(int l) {
+ return flayer[l];
+}
+
+//-----------------------------------------------------
+int u2u(int x) { // resolution 1/1000 inch
+ return u2mil(x); // mil
+}
+
+//-----------------------------------------------------
+real deg2arc(int x) { // degree to arc
+ return x*PI/180;
+}
+
+//-----------------------------------------------------
+int u2ang(real x, int mirror) {
+ if (mirror) {
+ real m = 360 - x;
+ if (m > 180) m -= 180;
+ else m += 180;
+ x = round((360 - m) * 10); // clockwise in FABMASTER!!!
+ }
+ else {
+ x = round((360 - x) * 10); // clockwise in FABMASTER!!!
+ }
+ return x;
+}
+
+//----------------------------------------------------
+real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) {
+ real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
+ real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
+
+ if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
+ WinkelNeu = (Xalt - Xorigin) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */
+ WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */
+ WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+}
+
+real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) {
+ real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
+ real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
+
+ if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
+ WinkelNeu = (Xalt - Xorigin) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */
+ WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */
+ WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+}
+
+
+//-----------------------------------------------------
+string padtype(UL_ELEMENT E, UL_CONTACT C) {
+ string s;
+ int pdi, x1, y1, x2, y2, r, d;
+ if (C.pad) {
+ pdi = u2u(C.pad.diameter[16]);
+ if (C.pad.shape[16] == PAD_SHAPE_ROUND || C.pad.shape[16] == PAD_SHAPE_OCTAGON || C.pad.shape[16] == PAD_SHAPE_SQUARE) {
+ sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi);
+ }
+ // if long subst. by round use this code
+ else if (C.pad.shape[16] == PAD_SHAPE_LONG) { // substitute y/xlongoct by round
+ pdi = pdi/2;
+ sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi);
+ }
+ // if offset subst. by round use this code
+ else if (C.pad.shape[16] == PAD_SHAPE_OFFSET) { // substitute offset by round
+ pdi = pdi/2;
+ sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi);
+ }
+ }
+ return s;
+}
+
+void get_roundness(UL_ELEMENT E) {
+ E.package.contacts(C) {
+ if (C.smd) {
+ if (C.smd.roundness < boardroundness) boardroundness = C.smd.roundness;
+ }
+ }
+ return;
+}
+
+//-----------------------------------------------------
+int padindex(UL_ELEMENT E,UL_CONTACT C) {
+ int i = 0;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == padtype(E,C))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+
+//-----------------------------------------------------
+string padstacktype(UL_ELEMENT E, UL_CONTACT C) {
+ int px, d;
+ string s;
+ px = padindex(E,C);
+ d = u2u(C.pad.drill);
+ sprintf(s, "P_%d_%d", d, px);
+ return s;
+}
+
+//-----------------------------------------------------
+string PAC_padtype(UL_PACKAGE P, UL_CONTACT C) {
+ string s;
+ int pdi, x1, y1, x2, y2, r, d;
+ if (C.pad) {
+ pdi = u2u(C.pad.diameter[16]);
+ if (C.pad.shape[16] == PAD_SHAPE_ROUND || C.pad.shape[16] == PAD_SHAPE_OCTAGON || C.pad.shape[16] == PAD_SHAPE_SQUARE) {
+ sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi);
+ }
+ // if long subst. by round use this code
+ else if (C.pad.shape[16] == PAD_SHAPE_LONG) { // substitute y/xlongoct by round
+ pdi = pdi/2;
+ sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi);
+ }
+ // if offset subst. by round use this code
+ else if (C.pad.shape[16] == PAD_SHAPE_OFFSET) { // substitute offset by round
+ pdi = pdi/2;
+ sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi);
+ }
+ }
+ return s;
+}
+
+//-----------------------------------------------------
+int PAC_padindex(UL_PACKAGE P,UL_CONTACT C) {
+ int i = 0;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == PAC_padtype(P,C))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+
+//-----------------------------------------------------
+string PAC_padstacktype(UL_PACKAGE P, UL_CONTACT C) {
+ int px, d;
+ string s;
+ px = PAC_padindex(P,C);
+ d = u2u(C.pad.drill);
+ sprintf(s, "P_%d_%d", d, px);
+ return s;
+}
+
+//-----------------------------------------------------
+int padstackindex(UL_PACKAGE P, UL_CONTACT C) {
+ int i = 0;
+ for (i = 0; pst[i]; i++) {
+ if (pst[i] == PAC_padstacktype(P,C))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+
+//-----------------------------------------------------
+string viatype(UL_VIA V) {
+ string s;
+ int pdi, x1, y1, x2, y2;
+ pdi = u2u(V.diameter[16]);
+ if (V.shape[16] == VIA_SHAPE_ROUND || V.shape[16] == VIA_SHAPE_OCTAGON) {
+ sprintf(s, "%s (%d);", viashape[V.shape[16]], pdi);
+ }
+ if (V.shape[16] == VIA_SHAPE_SQUARE) {
+ x1 = round(-pdi/2); y1 = round(-pdi/2);
+ x2 = round(pdi/2); y2 = round(pdi/2);
+ sprintf(s, "%s (%d,%d,%d,%d);", viashape[V.shape[16]], x1,y1,x2,y2);
+ }
+ return s;
+}
+
+//-----------------------------------------------------
+int viaindex(UL_VIA V) {
+ int i = 0;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == viatype(V))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+
+//-----------------------------------------------------
+string viastacktype(UL_VIA V) {
+ int px, d;
+ string s;
+ px = viaindex(V);
+ d = u2u(V.drill);
+ sprintf(s, "P_%d_%d", d, px);
+ return s;
+}
+
+//-----------------------------------------------------
+int viastackindex(UL_VIA V) {
+ int i = 0;
+ for (i = 0; pst[i]; i++) {
+ if (pst[i] == viastacktype(V))
+ return i+1;
+ }
+ return i; // should not be possible
+}
+
+//-----------------------------------------------------
+string drawpadpoly(int dx, int dy, int xo, int yo, real angle, int roundness, real elong, int padtype) {
+ string s;
+ real a = angle;
+
+ if(roundness) {
+ real r1;
+ int l, r;
+ real rad, rad1, x1, x2, y1, y2;
+ real x_1, y_1, x_2, y_2;
+
+ if (dx <= dy) {
+ r = dx;
+ l = dy;
+ }
+ else {
+ r = dy;
+ l = dx;
+ }
+ r1 = r / 200 * roundness;
+
+ if (roundness == 100) { // rounded pad
+ if (padtype == PAD_SHAPE_OFFSET) {
+ rad = PI / 180 * a;
+ rad1 = PI / 180 * (a + 180);
+ x1 = 0;
+ y1 = 0;
+ x2 = u2u(cos(rad) * (r*elong/100) );
+ y2 = u2u(sin(rad) * (r*elong/100) );
+ }
+ else if (padtype == PAD_SHAPE_LONG) {
+ rad = PI / 180 * a;
+ rad1 = PI / 180 * (a + 180);
+ x1 = u2u(cos(rad) * ((r*elong/100) /2) );
+ y1 = u2u(sin(rad) * ((r*elong/100) /2) );
+ x2 = u2u(cos(rad1) * ((r*elong/100) /2) );
+ y2 = u2u(sin(rad1) * ((r*elong/100) /2) );
+ }
+ else { // SMD
+ rad = PI / 180 * a;
+ rad1 = PI / 180 * (a + 180);
+ x1 = u2u(cos(rad) * ((l-r) /2) );
+ y1 = u2u(sin(rad) * ((l-r) /2) );
+ x2 = u2u(cos(rad1) * ((l-r) /2) );
+ y2 = u2u(sin(rad1) * ((l-r) /2) );
+ }
+ sprintf(s, "TRACK (%d(%.0f,%.0f)(%.0f,%.0f))",
+ u2u(r),
+ u2u(xo) + x1,
+ u2u(yo) + y1,
+ u2u(xo) + x2,
+ u2u(yo) + y2 );
+ }
+
+ else { // octagon
+ r1 = r * 0.56;
+ sprintf(s, "POLYGON ((%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f))",
+ u2u(xo) + Xneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0+ (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0+ (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0- (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0- (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0- dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0- dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0- dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0- dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0- (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0- (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0+ (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0+ (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0+ dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0+ dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a) );
+
+ }
+ }
+ else { // rectangle
+ sprintf(s, "POLYGON ((%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f))",
+ u2u(xo) + Xneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0 + dx /2), u2u(0 - dy / 2), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0 + dx /2), u2u(0 - dy / 2), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0 - dx /2), u2u(0 - dy / 2), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0 - dx /2), u2u(0 - dy / 2), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0 - dx /2), u2u(0 + dy / 2), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0 - dx /2), u2u(0 + dy / 2), 0, 0, a),
+ u2u(xo) + Xneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a),
+ u2u(yo) + Yneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a) );
+ }
+ return s;
+}
+
+//-----------------------------------------------------
+string drawpad(UL_PACKAGE P, UL_CONTACT C, int l) {
+ string s = "no pad!";
+ int dx, dy, r, d;
+ if (C.pad) {
+
+
+ if (C.pad.shape[l] == PAD_SHAPE_ROUND) {
+ sprintf(s, "ROUND (%d,%d,%d)", u2u(C.pad.diameter[l]), u2u(C.pad.x), u2u(C.pad.y) );
+ }
+ else if (C.pad.shape[l] == PAD_SHAPE_SQUARE) {
+ s = drawpadpoly(C.pad.diameter[l], C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 0, 0, 0);
+ }
+
+ else if (C.pad.shape[l] == PAD_SHAPE_OCTAGON) {
+ d = round(d);
+ s = drawpadpoly(C.pad.diameter[l], C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 50, C.pad.elongation, PAD_SHAPE_OCTAGON);
+ }
+
+ else if (C.pad.shape[l] == PAD_SHAPE_LONG) {
+ r = round(d/2);
+ s = drawpadpoly(C.pad.diameter[l]*2, C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 100, C.pad.elongation, PAD_SHAPE_LONG);
+ }
+
+ else if (C.pad.shape[l] == PAD_SHAPE_OFFSET) {
+ r = round(d);
+ s = drawpadpoly(C.pad.diameter[l]*2, C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 100, C.pad.elongation, PAD_SHAPE_OFFSET);
+ }
+
+ // PAD_SHAPE_ANNULUS
+ // PAD_SHAPE_THERMAL
+ }
+ else { // smd
+ int smd_roundnes = C.smd.roundness;
+ if (smd_roundnes < boardroundness) smd_roundnes = boardroundness;
+ s = drawpadpoly(C.smd.dx, C.smd.dy, C.smd.x, C.smd.y, C.smd.angle, smd_roundnes, 0, 0);
+ }
+ return s;
+}
+
+
+//---------------------------------------------------
+string pin_number(UL_ELEMENT E, string pinname) {
+ int j, pad_is_numeric = 1, padcount;
+ string s = "";
+ E.package.contacts(CT) {
+ s = CT.name;
+ for (j = 0; s[j]; ++j) {
+ if (!isdigit(s[j])) {
+ pad_is_numeric = 0;
+ }
+ }
+ }
+ if (pad_is_numeric) {
+ return pinname;
+ }
+ else {
+ padcount = 0;
+ E.package.contacts(CT) {
+ padcount++;
+ if (CT.name == pinname) {
+ sprintf(s, "%d", padcount);
+ return s;
+ }
+ }
+ }
+ return s;
+}
+
+
+//-------------------------------------------------------
+string PAC_pin_number(UL_PACKAGE P, string pinname) {
+ int j, pad_is_numeric = 1, padcount;
+ string s = "";
+ P.contacts(CT) {
+ s = CT.name;
+ for (j = 0; s[j]; ++j) {
+ if (!isdigit(s[j])) {
+ pad_is_numeric = 0;
+ }
+ }
+ }
+ if (pad_is_numeric) {
+ return pinname;
+ }
+ else {
+ padcount = 0;
+ P.contacts(CT) {
+ padcount++;
+ if (CT.name == pinname) {
+ sprintf(s, "%d", padcount);
+ return s;
+ }
+ }
+ }
+ return s;
+}
+
+//---------------------------------------------------
+int realnet(UL_SIGNAL S) {
+ S.contactrefs(S) return 1;
+ return 0;
+}
+
+//---------------------------------------------------
+int net_on_layer(UL_SIGNAL S, int layer) { // 1 if a wire of this net is on the given layer
+ S.wires(W)
+ if (W.layer == layer) return 1;
+ S.polygons(P)
+ if(P.layer == layer) return 1;
+ return 0;
+}
+
+//////////////////////////////////////////////////////
+void create_header () {
+ printf (";EAGLE %d.%02d %s %s FATF OUTPUT FILE FABmaster(R) ", EAGLE_VERSION, EAGLE_RELEASE, filename(argv[0]), ULPversion);
+ printf ("%02d.%02d.%02d %02d:%02d:%02d\n\n",
+ t2day(ht),t2month(ht)+1,t2year(ht),t2hour(ht),t2minute(ht),t2second(ht));
+ printf (":FABMASTER FATF REV11.1;\n\n");
+ printf (":UNITS = 1/1000 INCH\n");
+ printf (":NOAUTOROTATE\n");
+ return;
+}
+
+
+//////////////////////////////////////////////////////
+void board_data(UL_BOARD B) {
+ int t = time();
+ printf ("\n:BOARD_DATA\n");
+ printf ("1,JOB(\"%s\",,%02d-%02d-%02d,);\n", jobname,t2day(t),t2month(t),t2year(t));
+
+ B.wires(W) { // if board outline as wires in board
+ if (W.layer == LAYER_DIMENSION) {
+ xmin = min(u2u(W.x1), xmin); xmin = min(u2u(W.x2), xmin);
+ ymin = min(u2u(W.y1), ymin); ymin = min(u2u(W.y2), ymin);
+ xmax = max(u2u(W.x1), xmax); xmax = max(u2u(W.x2), xmax);
+ ymax = max(u2u(W.y1), ymax); ymax = max(u2u(W.y2), ymax);
+
+ if (W.curve) {
+ // process arcs (done with wire segments)
+ x = W.arc.x1;
+ y = W.arc.y1;
+
+ printf ("2,CONTOUR (");
+ printf("(%d,%d,0)", u2u(x), u2u(y));
+ real angle = W.arc.angle1 + delta;
+
+ while (angle < W.arc.angle2) {
+ i++;
+ if (i==1) {
+ printf(",");
+ }
+ else if (i==2){
+ printf(");\n2,CONTOUR (");
+ i = 0;
+ }
+ x = W.arc.xc + W.arc.radius * cos(deg2arc(angle));
+ y = W.arc.yc + W.arc.radius * sin(deg2arc(angle));
+ printf("(%d,%d)", u2u(x), u2u(y));
+ xmin = min(u2u(x), xmin); xmin = min(u2u(x), xmin);
+ ymin = min(u2u(y), ymin); ymin = min(u2u(y), ymin);
+ xmax = max(u2u(x), xmax); xmax = max(u2u(x), xmax);
+ ymax = max(u2u(y), ymax); ymax = max(u2u(y), ymax);
+ angle += delta;
+ }
+ if (!i) {
+ printf("(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2));
+ }
+ else {
+ printf(");\n2,CONTOUR ((%d,%d,0)", u2u(x), u2u(y));
+ printf(",(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2));
+ }
+ i=0;
+ }
+ else {
+ printf ("2,CONTOUR (");
+ printf("(%d,%d,0),(%d,%d,0)", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ printf(");\n");
+ }
+ }
+ }
+ B.elements(E) {
+ E.package.wires(W) {
+ if (W.layer == LAYER_DIMENSION) {
+ xmin = min(u2u(W.x1), xmin); xmin = min(u2u(W.x2), xmin);
+ ymin = min(u2u(W.y1), ymin); ymin = min(u2u(W.y2), ymin);
+ xmax = max(u2u(W.x1), xmax); xmax = max(u2u(W.x2), xmax);
+ ymax = max(u2u(W.y1), ymax); ymax = max(u2u(W.y2), ymax);
+
+ if (W.curve) {
+ // process arcs (done with wire segments)
+ x = W.arc.x1;
+ y = W.arc.y1;
+
+ printf ("2,CONTOUR (");
+ printf("(%d,%d,0)", u2u(x), u2u(y));
+ real angle = W.arc.angle1 + delta;
+
+ while (angle < W.arc.angle2) {
+ i++;
+ if (i==1) {
+ printf(",");
+ }
+ else if (i==2){
+ printf(");\n2,CONTOUR (");
+ i = 0;
+ }
+ x = W.arc.xc + W.arc.radius * cos(deg2arc(angle));
+ y = W.arc.yc + W.arc.radius * sin(deg2arc(angle));
+ printf("(%d,%d)", u2u(x), u2u(y));
+ xmin = min(u2u(x), xmin); xmin = min(u2u(x), xmin);
+ ymin = min(u2u(y), ymin); ymin = min(u2u(y), ymin);
+ xmax = max(u2u(x), xmax); xmax = max(u2u(x), xmax);
+ ymax = max(u2u(y), ymax); ymax = max(u2u(y), ymax);
+ angle += delta;
+ }
+ if (!i) {
+ printf("(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2));
+ }
+ else {
+ printf(");\n2,CONTOUR ((%d,%d,0)", u2u(x), u2u(y));
+ printf(",(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2));
+ }
+ i=0;
+ }
+ else {
+ printf ("2,CONTOUR (");
+ printf("(%d,%d,0),(%d,%d,0)", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ printf(");\n");
+ }
+ }
+ }
+ }
+ printf("3,WORK_SPACE (%d,%d,%d,%d);\n", xmin, xmax, ymin, ymax);
+ printf (":EOD\n");
+ printf ("\n:NOTRACE\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void parts(UL_BOARD B) {
+ int i = 1;
+ printf ("\n:PARTS\n");
+ B.elements(E) {
+ partnumname[i] = E.name; // 2009-12-03
+ printf("%d,",i++); // PART ID
+ printf("%s,",E.name); // PART NAME (not as in definition!)
+ printf("\"%s\",",E.value); // DEVICE NAME = Value
+ printf("%s,",validname(E.package.name + "__" + E.package.library)); // PACKAGE NAME
+ printf("%d,%d,",u2u(E.x), u2u(E.y)); // X,Y
+ printf("%d,",u2ang(E.angle, E.mirror)); // ROTATION
+ if (E.mirror) // ASSEMBLY SIDE
+ printf("B;");
+ else
+ printf("T;");
+ printf("\n");
+ }
+ cntnumname = i; // 2009-12-03
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void pad_symbols(UL_BOARD B) {
+ int i, j = 0, new; // j+1 = pad index; t[] contains padtypes
+ printf ("\n:PAD_SYMBOLS\n\n");
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ new = 1; // padtype not generated yet
+ for (i = 0; t[i]; i++) {
+ if (t[i] == padtype(E,C))
+ new = 0; // padtype exists
+ }
+ if (new) {
+ t[j] = padtype(E,C);
+ printf("%d,%s\n", j+1, padtype(E,C));
+ j++;
+ }
+ }
+ }
+ }
+ B.signals(S) {
+ S.vias(V) {
+ new = 1;
+ for (i = 0; t[i]; i++) {
+ if (t[i] == viatype(V))
+ new = 0; // padtype exists
+ }
+ if (new) {
+ t[j] = viatype(V);
+ printf("%d,%s\n", j+1, viatype(V));
+ j++;
+ }
+ }
+ }
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void layer_names(UL_BOARD B) {
+ int i;
+ string layers[] = {
+ "\"DRILL PAD\",COMMON,0,ELECTRICAL;" // layer 1
+ ,"\"TOP\",TOP,3,ELECTRICAL;"
+ ,"\"BOTTOM\",BOTTOM,2,ELECTRICAL;"
+ ,"\"ROUTE2\",TRANSPARENT,0,ELECTRICAL;"
+ ,"\"ROUTE3\",TRANSPARENT,0,ELECTRICAL;"
+ ,"\"ROUTE4\",TRANSPARENT,0,ELECTRICAL;"
+ ,"\"ROUTE5\",TRANSPARENT,0,ELECTRICAL;"
+ ,"\"POWER1\",TRANSPARENT,0,ELECTRICAL;"
+ ,"\"DRILLH\",TRANSPARENT,0,DOCUMENTATION;" //layer 9
+ ,"\"POWER2\",TRANSPARENT,0,DOCUMENTATION;"
+
+ ,"\"DRILL\",TRANSPARENT,0,DOCUMENTATION;"
+ ,"\"THERMAL_2\",TRANSPARENT,0,DOCUMENTATION;"
+ ,"\"FORMAT\",TRANSPARENT,0,BOARD_CUTOUT;"
+ ,"\"THERMAL_1\",TRANSPARENT,0,DOCUMENTATION;"
+ ,"\"THERMAL\",TRANSPARENT,0,DOCUMENTATION;"
+
+
+ ,"\"TPLACE\",TOP,17,ASSEMBLY;" // 16
+ ,"\"BPLACE\",BOTTOM,16,ASSEMBLY;"
+
+ ,"\"TNAMES\",TOP,19,DOCUMENTATION;"
+ ,"\"BNAMES\",BOTTOM,18,DOCUMENTATION;"
+
+ ,"\"TVALUES\",TOP,21,DOCUMENTATION;"
+ ,"\"BVALUES\",BOTTOM,20,DOCUMENTATION;"
+ };
+ printf("\n:LAYER_NAMES\n");
+ for (i=0; layers[i]; i++) {
+ printf("%d,%s\n", i+1, layers[i]);
+ }
+ printf(":EOD\n");
+ printf("\n:LAYER_SETS\n"); //layer sets
+ printf("1,\"ALL\",(1");
+ for (i=1; layers[i]; i++) {
+ printf(",%d", i+1);
+ }
+ printf(");\n");
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void pad_stacks(UL_BOARD B) {
+ int new, i, j;
+ printf ("\n:PAD_STACKS\n");
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ new = 1; // padstacktype not generated yet
+ for (i = 0; pst[i]; i++) {
+ if (pst[i] == padstacktype(E, C))
+ new = 0; // padstacktype exists
+ }
+ if (new) {
+ pst[j] = padstacktype(E, C);
+ printf("%d,\"%s\",%d,P,((1,%d));\n",
+ j+1,
+ padstacktype(E,C),
+ u2u(C.pad.drill),
+ padindex(E,C)
+ );
+ j++;
+ }
+ }
+ }
+ }
+ B.signals(S) {
+ S.vias(V) {
+ new = 1;
+ for (i = 0; pst[i]; i++) {
+ if (pst[i] == viastacktype(V))
+ new = 0; // viastacktype exists
+ }
+ if (new) {
+ pst[j] = viastacktype(V);
+ printf("%d,\"%s\",%d,P,((1,%d));\n",
+ j+1,
+ viastacktype(V),
+ u2u(V.drill),
+ viaindex(V)
+ );
+ j++;
+ }
+ }
+ }
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void pads(UL_BOARD B) {
+ int i = 0;
+ printf ("\n:PADS\n");
+ B.signals(S) {
+ if (realnet(S)) { // vias belonging to real net
+ i++;
+ S.vias(V) {
+ printf("%d,%d,((%d,%d));\n", i, viastackindex(V), u2u(V.x), u2u(V.y));
+ }
+ }
+ else { // other vias
+ S.vias(V) {
+ printf("0,%d,((%d,%d));\n", viastackindex(V), u2u(V.x), u2u(V.y));
+ }
+ }
+ }
+ printf(":EOD\n");
+ return;
+}
+
+
+int searchfont(int tsize, int tratio) {
+ int found = -1;
+ for (int n = 0; n < cntt; n++) {
+ if (sizes[n] == tsize && ratio[n] == tratio) {
+ found = n;
+ break;
+ }
+ }
+ return found;
+}
+
+//////////////////////////////////////////////////////
+void fonts(UL_BOARD B) {
+ int n;
+ printf ("\n:FONTS\n");
+ printf ("1,\"STANDARD\",96,60,72,0;\n");
+ B.texts(T) {
+ if (searchfont(T.size, T.ratio) < 0) {
+ sizes[cntt] = T.size;
+ ratio[cntt] = T.ratio;
+ cntt++;
+ }
+ }
+ B.elements(E) {
+ E.package.texts(T) {
+ if (searchfont(T.size, T.ratio) < 0) {
+ sizes[cntt] = T.size;
+ ratio[cntt] = T.ratio;
+ cntt++;
+ }
+ }
+ }
+ for (n = 0; n < cntt; n++) {
+ printf("%d,\"FONT_%d\",%d,%.0f,%.0f,%.d;\n", n+2, n+2, u2u(sizes[n]), u2u(sizes[n])*.6, u2u(sizes[n])*.72, u2u(sizes[n]*ratio[n])/100);
+ }
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void packages(UL_BOARD B) {
+ int i = 1, j, k, l, xll,yll, textlayer;
+ real tangle, angle;
+ string dp, jst;
+ printf ("\n:PACKAGES\n");
+ B.libraries(LBR) {
+ LBR.packages(P) {
+ new = 1; // padstacktype not generated yet
+ for (i = 0; shapename[i]; i++) {
+ if (shapename[i] == validname(P.name + "__" + P.library))
+ new = 0; // package name exists
+ }
+ if (new) {
+ shapename[sx] = validname(P.name + "__" + P.library);
+ sx++;
+
+ printf("%d,",i++); // PACKAGE ID
+ printf("\"%s\",",validname(P.name + "__" + P.library)); // PACK.NAME
+ printf(",,,\n"); // xmin etc. left blank
+ j = 0; k = 0;
+ P.contacts(C) {
+ if (k == 0) printf(" (PINS "); // only if contacts present
+ k++;
+ printf("(%s,,%d,%d,", PAC_pin_number(P, C.name), u2u(C.x), u2u(C.y)); // Pin IDs
+ if (C.pad) printf("D)"); // ASSEMBLY SIDE
+ else printf("T)");
+ j++;
+ if (j > 2) { // max. 3 pins in one line
+ printf("\n ");
+ j = 0;
+ }
+ }
+ if (k != 0) printf(")\n"); // only if contacts present close PINS section
+ j = 0;
+ printf(" ("); // corresponds to ); before next package
+ P.contacts(C) {
+ if (C.pad) {
+ if (j > 0) {
+ printf(" ");
+ }
+ printf("%s,PAD (%d ((%d,%d)))\n", // PAD
+ PAC_pin_number(P, C.name), padstackindex(P,C), u2u(C.x), u2u(C.y));
+ j++;
+ }
+ } // close PIN-ID,PAD section
+ j = 0;
+ P.contacts(C) {
+ if (C.pad) {
+ dp = drawpad(P, C, 1);
+ printf(" %s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(1)); // top side
+ printf(" %s))\n", dp);
+ dp = drawpad(P, C, 16);
+ printf(" %s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(16)); // bottom side
+ printf(" %s))\n", dp);
+ }
+ else { // smd, always on top layer
+ if (j > 0) printf(" ");
+ if (C.smd.layer == 1) {
+ printf("%s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(1));
+ printf(" %s))\n", drawpad(P, C, 1));
+ }
+ else {
+ printf("%s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(16));
+ printf(" %s))\n", drawpad(P, C, 16));
+ }
+ }
+ j++;
+ } // close PIN-ID,LAYER section
+
+ // process circles etc. on top and bottom side
+ P.circles(C) {
+ if (C.layer == 1 || C.layer == 16) {
+ printf("\n 0,LAYER (%d (\n", fablayer(C.layer));
+ int RminRmax = C.radius - C.width;
+ if (!C.width || RminRmax < 0) {
+ RminRmax = C.width/2;
+ printf(" ROUND (%d,%d,%d)", u2u((C.radius + RminRmax)*2),
+ u2u(C.x), u2u(C.y));
+ }
+ else {
+ printf(" CIRCLE (%d,%d,%d,%d)", u2u(C.radius) + u2u(C.width)/2,
+ u2u(C.radius) - u2u(C.width)/2,
+ u2u(C.x), u2u(C.y));
+ }
+ printf("))\n");
+ }
+ }
+ P.rectangles(W) {
+ if (W.layer == 1 || W.layer == 16) {
+ printf("\n 0,LAYER (%d (\n", fablayer(W.layer));
+ xll = W.x1; yll = W.y1;
+ int rectcenterx = (W.x1 + W.x2) /2;
+ int rectcentery = (W.y1 + W.y2) /2;
+ int rectx = W.x2 - W.x1;
+ int recty = W.y2 - W.y1;
+ printf(" %s", drawpadpoly(rectx, recty, rectcenterx, rectcentery, W.angle, 0, 0, 0));
+ printf("))\n");
+ }
+ }
+ P.texts(T) {
+ if (T.layer == 1 || T.layer == 16) {
+ printf(" 0,LAYER (%d (\n", fablayer(T.layer));
+ T.wires(W) {
+ printf(" TRACK (%d,(%d,%d),(%d,%d))\n", u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ }
+ /*
+ printf(" TEXT (%d,%d,%d,%s,%.1f,%s,%s)))\n",
+ searchfont(T.size, T.ratio)+2,
+ u2u(T.x), u2u(T.y), jst, T.angle, Mirror, T.value);
+ */
+ printf("))\n");
+ }
+ }
+
+ // end circles etc. on top and bottom
+ P.wires(W) {
+ if (W.layer == 1 || W.layer == 16 || W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52) {
+ printf(" 0,LAYER (%d (\n", fablayer(W.layer)); // tplace layer
+ if (W.curve) {
+ // process arcs (done with wire segments)
+ printf(" TRACK (%d,(%d,%d),", u2u(W.width), u2u(W.arc.x1), u2u(W.arc.y1));
+ angle = W.arc.angle1 + delta;
+ while (angle < W.arc.angle2) {
+ printf("\n (%d,%d),",
+ u2u(W.arc.xc + W.arc.radius * cos(deg2arc(angle))),
+ u2u(W.arc.yc + W.arc.radius * sin(deg2arc(angle))) );
+ angle += delta;
+ }
+ printf("(%d,%d))", u2u(W.arc.x2), u2u(W.arc.y2) );
+ }
+ else {
+ printf(" TRACK (%d,(%d,%d),", u2u(W.width), u2u(W.x1), u2u(W.y1));
+ printf("(%d,%d))", u2u(W.x2), u2u(W.y2));
+ }
+ printf("))\n");
+ }
+ }
+
+ P.rectangles(W) {
+ if (W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52) {
+ printf(" 0,LAYER (%d (\n", fablayer(W.layer)); // tplace layer
+ xll = W.x1; yll = W.y1;
+ int rectcenterx = (W.x1 + W.x2) /2;
+ int rectcentery = (W.y1 + W.y2) /2;
+ int rectx = W.x2 - W.x1;
+ int recty = W.y2 - W.y1;
+ printf("%s", drawpadpoly(rectx, recty, rectcenterx, rectcentery, W.angle, 0, 0, 0));
+ printf("))\n");
+ }
+ }
+
+ P.circles(C) {
+ if (C.layer == 21 || C.layer == 22 || C.layer == 51 || C.layer == 52) {
+ printf(" 0,LAYER (%d (\n", fablayer(C.layer)); // tplace layer
+ int RminRmax = C.radius - C.width;
+ if (!C.width || RminRmax < 0) {
+ RminRmax = C.width/2;
+ printf(" ROUND (%d,%d,%d)\n", u2u((C.radius + RminRmax)*2),
+ u2u(C.x), u2u(C.y));
+ }
+ else {
+ printf(" CIRCLE (%d,%d,%d,%d)\n", u2u(C.radius) + u2u(C.width)/2,
+ u2u(C.radius) - u2u(C.width)/2,
+ u2u(C.x), u2u(C.y));
+ }
+ printf("))\n");
+ }
+ }
+
+ P.texts(T) {
+ if (T.layer == 1 || T.layer == 16 || T.layer == 21 || T.layer == 22 || T.layer == 51 || T.layer == 52) {
+ printf(" 0,LAYER (%d (\n", fablayer(T.layer));
+ T.wires(W) {
+ printf(" TRACK (%d,(%d,%d),(%d,%d))\n", u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ }
+ printf("))\n");
+ }
+ /*
+ if (T.layer == 51 || T.layer == 52) {
+ printf(" 0,LAYER (%d (\n", fablayer(T.layer - 30)); // tplace layer
+ if (!T.mirror) {
+ jst = "BOTTOM_LEFT";
+ }
+ else {
+ jst = "TOP_RIGHT";
+ }
+ printf(" TEXT (1,%d,%d,%s,%3.0f, ,%s)\n",
+ u2u(x), u2u(y), jst, T.angle, T.value);
+ }
+ */
+ }
+ printf(");\n");
+ }
+ }
+ }
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void layer(UL_BOARD B) {
+ int textlayer;
+ string jst, mir;
+ real tangle, angle;
+ printf ("\n:LAYERS\n");
+ int i = 0, lay;
+ B.signals(S) {
+ if (realnet(S)) {
+ ++i;
+ for (lay = 1; lay <= 16; lay++) {
+ if (net_on_layer(S, lay) && fablayer(lay) > 0) {
+ printf("%d,LAYER (%d, (\n", i, fablayer(lay));
+ S.wires(W) {
+ if (lay == W.layer) {
+
+ if (W.curve) {
+ // process arcs (done with wire segments)
+ x = W.arc.x1;
+ y = W.arc.y1;
+ printf(" TRACK (%d,(%d,%d)", u2u(W.width), u2u(x), u2u(y));
+ angle = W.arc.angle1 + delta;
+ while (angle < W.arc.angle2) {
+ x = W.arc.xc + W.arc.radius * cos(deg2arc(angle));
+ y = W.arc.yc + W.arc.radius * sin(deg2arc(angle));
+ printf(",\n (%d,%d)", u2u(x), u2u(y));
+ angle += delta;
+ }
+ printf(",\n (%d,%d))", u2u(W.arc.x2), u2u(W.arc.y2)); // Comma ends the last line 2013-07-01
+ }
+ else {
+ printf(" TRACK (%d,(%d,%d),(%d,%d))\n",
+ u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ }
+ }
+ }
+
+ S.polygons(P) { // 13.05.2004 polygon
+ if (lay == P.layer) {
+ P.contours(W) {
+ printf(" TRACK (%d,(%d,%d),(%d,%d))\n",
+ u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ }
+ P.fillings(W) {
+ printf(" TRACK (%d,(%d,%d),(%d,%d))\n",
+ u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ }
+ }
+ }
+ printf(" ));\n");
+ }
+ }
+ }
+ }
+
+ // process name texts
+ B.elements(E) {
+ if (E.package) {
+ tangle = 0;
+ if (!E.mirror) {
+ textlayer = 25;
+ mir = "";
+ }
+ else {
+ textlayer = 26;
+ mir = "M";
+ }
+ jst = "CENTER";
+ x = E.x; y = E.y;
+ printf("0,LAYER (%d (\n", fablayer(textlayer)); // tnames layer
+ printf(" TEXT (1,%d,%d,%s,0,%s,%s)));\n", u2u(x), u2u(y), jst, mir, E.name);
+ }
+ }
+ B.texts(T) {
+ if (T.layer == 1 || T.layer == 16 || T.layer == 21) {
+ printf(" 0,LAYER (%d (\n", fablayer(T.layer));
+ T.wires(W) {
+ printf(" TRACK (%d,(%d,%d),(%d,%d))\n", u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2));
+ }
+ printf("))\n");
+ }
+ }
+ printf(":EOD\n");
+}
+
+
+// //////////// 2009-12-03 /////////////////
+void creat_pad_number_index(UL_BOARD B) {
+ B.elements(E) {
+ int iscontact = 0;
+ E.package.contacts(C) {
+ iscontact = 1;
+ break;
+ }
+ if (!iscontact) {
+ sprintf(areaEname[cntindex], "%s", E.name); // index of element without contacts
+ indexareaEname[cntindex] = 0;
+ cntindex++;
+ }
+ else {
+ int j = 0;
+ E.package.contacts(C) {
+ if (!j) {
+ j++;
+ sprintf(areaEname[cntindex], "%s", E.name); // index to start of pad names in package-pad-list
+ indexareaEname[cntindex] = cntEpad;
+ cntindex++;
+ }
+ // create pad number index list 2009-12-03
+ sprintf(areaEpadname[cntEpad], "%s~%s", E.name, C.name);
+ areaPadNumber[cntEpad] = strtol(pin_number(E, C.name)); // *** the number of pad in FATF format
+ cntEpad++;
+ j++;
+ }
+ }
+ }
+ return;
+}
+
+//-------------------------------------
+int getpadnbr(int i, string epname) {
+ for (int n = i; n < cntEpad; n++) {
+ if (areaEpadname[n] == epname) return areaPadNumber[n];
+ }
+ return 0;
+}
+
+int getpinr(string ename, string pname) {
+ string ep = ename + "~" + pname;
+ for (int i = 1; i < cntindex; i++) {
+ if (areaEname[i] == ename) return getpadnbr(indexareaEname[i], ep);
+ }
+ return 0;
+}
+
+int getelnr(string ename) {
+ for (int i = 1; i < cntindex; i++) {
+ if (areaEname[i] == ename) return i;
+ }
+ return 0;
+}
+
+
+//////////////////////////////////////////////////////
+void nets(UL_BOARD B) {
+ int i = 0, itemcnt, elnr, j;
+ string pin;
+ printf("\n:NETS\n");
+ B.signals(S) {
+ if (realnet(S)) {
+ printf("%d,\"%s\",S,\n (", ++i, S.name); // NET NR, NET NAME, STYPE
+ itemcnt = 0;
+ S.contactrefs(C) {
+ if (C.contact) { // 2011-02-30 first request if a connect.
+ elnr = getelnr(C.element.name); // Part ID 2009-12-03
+ sprintf(pin, "%d", getpinr(C.element.name, C.contact.name)); // Pin ID 2009-12-03
+ if (itemcnt) {
+ printf(",");
+ }
+ if (itemcnt > 5) {
+ printf("\n ");
+ itemcnt = 0;
+ }
+ itemcnt++;
+ printf("(%d,%s)", elnr, pin); // PART ID, PIN ID
+ }
+ else {
+ dlgMessageBox("Found signal '"+S.name+ "' without contactref!\nCheck consistence and corrupted signals.", "OK");
+ exit(-1);
+ }
+ }
+ printf(");\n");
+ }
+ }
+ printf(":EOD\n");
+ return;
+}
+
+//////////////////////////////////////////////////////
+void create_pcboard_section(UL_BOARD B) {
+ B.elements(E) get_roundness(E);
+ board_data(B);
+ parts(B);
+ nets(B);
+ pad_symbols(B);
+ layer_names(B);
+ pad_stacks(B);
+ pads(B);
+ fonts(B);
+ packages(B);
+ layer(B);
+ return;
+}
+
+//////////////////////////////////////////////////////
+if (board) board(B) {
+ jobname = filename(B.name);
+ jobname = strsub(jobname, 0, strlen(jobname) - 4);
+ output(filesetext(B.name, ".fab")) {
+ create_header();
+ creat_pad_number_index(B);
+ create_pcboard_section(B);
+ /* option to count run time
+ printf (";start %02d.%02d.%02d %02d:%02d:%02d : ",
+ t2day(ht),t2month(ht)+1,t2year(ht),t2hour(ht),t2minute(ht),t2second(ht));
+ int t = time();
+ printf (";end %02d.%02d.%02d %02d:%02d:%02d\n",
+ t2day(t),t2month(t)+1,t2year(t),t2hour(t),t2minute(t),t2second(t));
+ */
+ }
+ string ex;
+ sprintf(ex, "Data exported to:\n\n%s", filesetext( B.name, ".fab" ));
+ dlgMessageBox(ex, "OK");
+}
diff --git a/trunk/ulp/fill-via4vacuum.ulp b/trunk/ulp/fill-via4vacuum.ulp
new file mode 100644
index 00000000..23063249
--- /dev/null
+++ b/trunk/ulp/fill-via4vacuum.ulp
@@ -0,0 +1,84 @@
+#usage "Generate a mask to fill vias for vacuum adapter.\n"
+ "
"
+ "To delete the elements in user layer afterwards, display it without "
+ "any other layers, and use GROUP and DELETE. Then remove the user "
+ "layer with the command LAYER -number."
+ "
"
+ "Find single-ended wires that don't start or end at another wire, via or pad. "
+ "Starting the ulp without parameter generates a list. "
+ "The temporary list (file) will be deleted as soon as you quit EAGLE. "
+ "After running this ULP the MOVE command will be active. Now you should move this wire to a position where you can "
+ "select it easily with the RIPUP command."
+ "
defines a 0.1 micron group around this coordinate and activates the MOVE command
"
+ "
"
+ "When using the parameters + and - for purposes of clarity only the layer that contains "
+ "the wire is displayed. Possibly plus the layer(s) Pads and/or Vias. "
+ "For recognizing the wire stubs it is necessary to set the fill style of the respective layer "
+ "to not filled (dotted or hatched).
"
+ "NOTE: WIREs or VIAs that end in a polygon's area, are recognized as single-ended! "
+ "To avoid mistakes use RATSNEST to calculate the polygons before. Now you can start the ULP!"
+ "
"
+ "Findet WIREs die nicht an einem Pad, Via oder einem anderen Wire beginnen bzw. enden (Stummel). "
+ "Der Start des ULP ohne Parameter erzeugt eine Liste (Datei) der Wire, die zum einzeln durchschalten benutzt werden kann. "
+ "Die Liste (Datei) wird nur temporär erzeugt und beim Beenden von Eagle gelöscht."
+ "
zeigt den nächsten Eintrag in der Liste der gefundenen Elemente
"
+ "
-
zeigt den vorhergehenden Eintrag in der Liste der gefundenen Elmente
"
+ "
=
zeige den aktuellen Eintrag nochmal
"
+ "
M
Definiert einen Bereich von 0.1 Micron als Gruppe um die Koordinate und aktiviert den MOVE-Befehl
"
+ "
"
+ "Nach dem Beenden des ULP ist der MOVE-Befehl aktiv. Damit kann der Wire zuerst aus dem "
+ "Bereich herausgezogen werden, um ihn eindeutig mit dem RIPUP-Befehl zu selektieren. "
+ "Um die Übersichtlichkeit zu erhöhen, wird bei der Weiterschaltung mit + oder - nur der "
+ "Layer in dem sich der Wire-Stummel befindet, plus eventuell der Pad-Layer und/oder "
+ "Via-Layer eingeblendet. "
+ "Um die Wire-Stummel innerhalb eines Pad oder Via zu erkennen ist es nötig das Füllmuster der "
+ "entsprechenden Layer auf nicht füllend (gepunktet oder schraffiert) einzustellen.
"
+ "ACHTUNG: WIREs oder VIAs, die in einer Polygonfläche enden, werden ebenfalls als Single-Ended erkannt! "
+ "Um Verwechslungen auszuschliessen lassen Sie mit RATSNEST zuerst die Polygonflächen berechnen und starten Sie dann das ULP!"
+ "
"
+ "Author: support@cadsoft.de"
+
+string Version = "1.0.2"; // 2007-04-03 alf@cadsoft.de
+ // 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de
+ // 2011-03-30 corrected request in loop S.contactrefs(C) { => if (C.contact) {
+
+#require 4.1600;
+
+
+int test = 0;
+
+enum { typeW, typeS, typeP, typeV };
+string Typ[] = { "Wire", "Smd", "Pad", "Via" };
+int sameL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int sameS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int padL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int viaL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+int viaStackS[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+int viaStackE[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+int ncoord = 0;
+int wx[]; // X coordinate
+int wy[]; // Y coordinate
+int wl[]; // Layer
+int ws[]; // Start Layer for Via & Pad, Smd and Wire
+int we[]; // End Layer for Via & Pad, Smd and Wire == Start Layer
+int wt[]; // Type
+int index[];
+
+string cmd, s;
+
+string h;
+string file, memory;
+string cmdr[];
+
+
+// ### ---------------- functions ------------------- ###
+void set_layer(int lay, int s_lay, int e_lay, int type) {
+ switch(type) {
+ case typeW : // Wire
+ sameL[lay]++;
+ break;
+ case typeS : // Smd
+ sameL[lay]++;
+ sameS[lay]++;
+ break;
+
+ case typeP : // Pad
+ for (int pl = 1; pl < 18; pl++) {
+ padL[pl]++;
+ }
+ sameL[17]++;
+ break;
+ case typeV : // Via
+ for (int vl = s_lay; vl <= e_lay; vl++) {
+ viaL[vl]++;
+ }
+ viaStackS[viaL[18]] = s_lay;
+ viaStackE[viaL[18]] = e_lay;
+ viaL[18]++;
+ break;
+ }
+ return;
+}
+
+
+// ### claer counter ###
+void clear_same_counter(void) {
+ for (int n = 0; n < 19; n++) {
+ viaL[n] = 0;
+ padL[n] = 0;
+ sameS[n] = 0;
+ sameL[n] = 0;
+ viaStackS[n] = 0;
+ viaStackE[n] = 0;
+ }
+ return;
+}
+
+
+// #*#*#* check via stack and if via routet on more as 1 layer *#*#*#
+void check_via(int k, string sigName) {
+ int cntViaOverLap[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ string usedWireLayer = "";
+ int nV = 0;
+ for (nV = 0; nV < viaL[18]; nV++) { // ### Via Stack
+ usedWireLayer = "";
+ int wire_on_stack_via = 0;
+ for (int n = viaStackS[nV]; n <= viaStackE[nV]; n++) {
+ cntViaOverLap[n]++;
+ if (sameL[n]) {
+ sprintf(s, " %d", n);
+ usedWireLayer += s;
+ wire_on_stack_via++;
+ }
+ }
+ if (wire_on_stack_via < 2) {
+ if (!wire_on_stack_via) {
+ if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 18\tNur VIA von Layer %d - %d, Signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ viaStackS[nV], viaStackE[nV],
+ viaStackS[nV], viaStackE[nV],
+ sigName
+ );
+
+ else sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 18\tOnly VIA from layer %d - %d, signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ viaStackS[nV], viaStackE[nV],
+ viaStackS[nV], viaStackE[nV],
+ sigName
+ );
+ }
+ else {
+ if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tZu wenig WIRE: Nur in Layer %s an VIA von Layer %d - %d geroutet, Signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ usedWireLayer,
+ usedWireLayer,
+ viaStackS[nV], viaStackE[nV],
+ sigName
+ );
+
+ else sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tOnly WIRE on layer %s on VIA from layer %d - %d, signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ usedWireLayer,
+ usedWireLayer,
+ viaStackS[nV], viaStackE[nV],
+ sigName
+ );
+ }
+ cmd += s;
+ }
+ }
+ if (viaL[18]) { // ### check via layer overlap ###
+ string ViaOverlap = "";
+ int cnt;
+ for (cnt = 1; cnt < 17; cnt++) {
+ if (cntViaOverLap[cnt] > 1) {
+ sprintf(s, " %d", cnt);
+ ViaOverlap += s;
+ }
+ }
+ if (ViaOverlap) {
+ if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tVIAs Stack-Überlappung in Layer %s, Signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ ViaOverlap,
+ ViaOverlap,
+ sigName
+ );
+
+ else sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tVIAs stack overlap on layer %s, signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ ViaOverlap,
+ ViaOverlap,
+ sigName
+ );
+ cmd += s;
+ }
+ }
+ return;
+}
+
+
+// ### check count of elements on coordinate ###
+void check_same(int k, string sigName) {
+ if (!sameL[17]) { // ### Pads können kein Single-Ended-Wire sein ###
+ if (viaL[18]) {
+ check_via(k, sigName);
+ }
+ else {
+ for (int n = 1; n <= 16; n++) {
+ if (sameL[n]) {
+ if (sameL[n] + viaL[n] + sameS[n] < 2) {
+ if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d \tNur 1 WIRE im Layer %d von Signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ n, n, sigName);
+
+ else sprintf(s, "WINDOW (%.4f %.4f);\t %d \tFew WIRE on layer %d at signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ n, n, sigName);
+ cmd += s;
+ }
+ }
+ }
+ }
+ }
+
+ if (padL[17] && viaL[18]) {
+ if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 17 18\tPAD und VIA an gleicher Koordinate, Signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ ws[index[k]], we[index[k]],
+ sigName);
+ else sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 17 18\tPAD and VIA on same coordinate, signal %s\n",
+ u2mm(wx[index[k]]), u2mm(wy[index[k]]),
+ ws[index[k]], we[index[k]],
+ sigName);
+ cmd += s;
+ }
+ return;
+}
+
+
+
+// check multiple coordinates or one coordinate on this Signal
+void checkcoord(string sigName) {
+ int n = 0;
+ h = "";
+ sort(ncoord, index, wx, wy, wl, wt); // in Order - Coordinates - Layer - Type
+ n = 0;
+ clear_same_counter();
+
+ if (ncoord > 1) {
+ // ### loop ###
+ do {
+ set_layer(wl[index[n]], ws[index[n]], we[index[n]], wt[index[n]]);
+ if (wx[index[n+1]] == wx[index[n]] && wy[index[n+1]] == wy[index[n]] ) {
+ n++;
+ }
+ else {
+ check_same(n, sigName);
+ clear_same_counter();
+ n++;
+ }
+ } while (n < ncoord);
+ check_same(n, sigName);
+ }
+ else check_same(n, sigName);
+ return;
+}
+
+
+// collect coordinates
+void add(int x, int y, int lay, int l_start, int l_end, int type) {
+ wx[ncoord] = x;
+ wy[ncoord] = y;
+ wl[ncoord] = lay;
+ ws[ncoord] = l_start;
+ we[ncoord] = l_end;
+ wt[ncoord] = type;
+ ncoord++;
+ return;
+}
+
+
+// ### main ###
+if (board) {
+ board(B) {
+ string trace_file = filesetext(B.name, "~~.sew"); // single endet wire
+ string memory_file = filesetext(B.name, "~~.mlc"); // memory line counter
+
+ if (!argv[1]) {
+ dlgMessageBox(usage, "OK");
+ B.signals(S) {
+ status(" check "+S.name);
+ ncoord = 0;
+ S.wires(W) {
+ if (W.layer < 17) {
+ add(W.x1, W.y1, W.layer, W.layer, W.layer, typeW);
+ add(W.x2, W.y2, W.layer, W.layer, W.layer, typeW);
+ }
+ }
+ S.contactrefs(C) {
+ if (C.contact) { // 2011-02-30 first request if a connect.
+ if (C.contact.smd) {
+ add(C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, typeS);
+ }
+ else {
+ add(C.contact.pad.x, C.contact.pad.y, 17, 1, 16, typeP);
+ }
+
+ }
+ else { // 2011-03-30
+ dlgMessageBox("Found signal '"+ S.name + "' without contactrefs!\nCheck consistence and corrupted signals!", "OK");
+ exit(-1);
+ }
+ }
+ S.vias(V) {
+ add(V.x, V.y, 18, V.start, V.end, typeV);
+ }
+ checkcoord(S.name);
+ }
+ output(trace_file, "wtD") printf("%s", cmd);
+ output(memory_file, "wtD") printf("-1");
+ exit("RUN '" + argv[0] + "' +\n");
+ }
+
+ // ### trace listed points by key "+" "-"
+ else {
+ string m_cmd[];
+ int n = fileread(m_cmd, memory_file); // memory line counter
+ int cnt = strtol(m_cmd[0]);
+ string lines[];
+ n = fileread(lines, trace_file); // single endet wire
+
+ if (!n) {
+ dlgMessageBox("No single ended WIRE found!", "OK");
+ exit(0);
+ }
+
+ else if (argv[1] == "+" || argv[1] == "-" || argv[1] == "=" || strupr(argv[1]) == "M") {
+ if (argv[1] == "+") {
+ if (cnt < n-1) cnt++;
+ else {
+ if (language() == "de") dlgMessageBox("Letze Position!", "OK");
+ else dlgMessageBox("The last position in list!", "OK");
+ }
+ }
+ else if (argv[1] == "-") {
+ if(cnt) cnt--;
+ else {
+ if (language() == "de") dlgMessageBox("Erste Position!", "OK");
+ else dlgMessageBox("The first position in list!", "OK");
+ }
+ }
+ else if (strupr(argv[1]) == "M") {
+ n = strsplit(cmdr, lines[cnt], '(');
+ string Display = "";
+ n = strsplit(m_cmd, cmdr[1], ')');
+ n = strsplit(cmdr, m_cmd[0], ' ');
+ real x = strtod(cmdr[0]);
+ real y = strtod(cmdr[1]);
+ sprintf(Display, "GROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (>%.4f %.4f);\nMOVE (>%.4f %.4f)",
+ x-0.0001, y-0.0001,
+ x+0.0001, y-0.0001,
+ x+0.0001, y+0.0001,
+ x-0.0001, y+0.0001,
+ x-0.0001, y-0.0001,
+ x, y
+ );
+ exit(Display);
+ }
+ else if (argv[1] == "=");
+ }
+
+ else {
+ if (language() == "de") dlgMessageBox("Unbekannter Parameter!", "OK");
+ else dlgMessageBox("Unknown parameter!", "OK");
+ exit(0);
+ }
+
+ n = strsplit(cmdr, lines[cnt], '\t');
+ string Display = "";
+ if (m_cmd[1] != cmdr[1]) {
+ sprintf(Display, "DISPLAY NONE %s ;\n", cmdr[1]);
+ }
+ output(memory_file, "wtD") printf("%d\n%s", cnt, m_cmd[1]); // save the last pointer
+ exit("GRID mm;\n"+Display+cmdr[0]+"RUN ulpmessage '"+cmdr[2]+"';"+"MOVE"); // activate th move command
+ }
+ }
+}
+
+else {
+ if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Board", "OK");
+ else dlgMessageBox("Start this ULP in a Board", "OK");
+}
\ No newline at end of file
diff --git a/trunk/ulp/find.ulp b/trunk/ulp/find.ulp
new file mode 100644
index 00000000..bce1219e
--- /dev/null
+++ b/trunk/ulp/find.ulp
@@ -0,0 +1,1282 @@
+#usage "en: nobrFind elements in schematic/board and zoom in\n"
+ "
"
+ "Centers the object and zooms into the drawing."
+ "
"
+ "
You can also run this ULP from the command line:
"
+ "Usage: RUN find [ name [ pin | pad | [value [current_value [CH new_value]] [ count | * ]]"
+ "
"
+ "Search string is the name of the Device/Package/Net/Bus/Pin/Pad/Signal/Value
"
+ "counter specifies the number of elements that shall be found before ending the search "
+ "* sets the counter to 1000
"
+ "PIN | PAD | DEV | GATE additionally searches for PIN, PAD, GATE, DEVICE names "
+ "GATE without a given name, places the foremost found, unused gate "
+ "GATE * lists all unused gates, select one of them to place it "
+ "VIAstart end searches for blind, buried, and micro vias with a certain length "
+ "VALUEvalueCHvalue replaces the value of an element with the given new one, if found (CH is case sensitive) "
+ "value-S displays all elements with the same value at the same time (highlighted like with SHOW), in BRD only "
+ "value-+ shows step by step the previous or next found element, in BRD and SCH "
+ "
"
+ "Searching order: "
+ "
"
+ "
Schematic:
Board:
"
+ "
1. Part name
1. Element
"
+ "
2. Net name
2. Signal/Wires/Vias
"
+ "
3. Bus name
3. Pads
"
+ "
4. Value
4. Value
Searching for values is not case sensitive.
"
+ "
5. Device **
5. Polygon width **
"
+ "
6. Gate **
6. Drill
"
+ "
7. Pin **
7. Via stack
"
+ "
8. Pad **
"
+ "
9. Text
"
+ "
"
+ "** Device name, Gate name, Pin name, Pad name, Polygon width, or Drill diameter will be searched, if one of the options DEV, GATE, PIN, PAD, POLYGON or DRILL is given.
"
+ ""
+ "In the symbol editor you can search for PIN names, in the package editor you can search for PAD/SMD names "
+ "Author: support@cadsoft.de"
+ ,
+ "de: Findet Elemente in Schaltplan und Board"
+ "
"
+ "Zoomt das gefundene Element in die Fenstermitte"
+ "
"
+ "
Sie können das ULP auch aus der Kommandozeile starten mit:
"
+ "RUN find [ name [ pin | pad | value [aktueller_value [CH neuer_value]] [ count | * ]]"
+ " "
+ "RUN find "
+ "RUN find name "
+ "RUN find name [Zähler] "
+ "RUN find [DEV | GATE | PIN | PAD | POLYGON width | DRILL diameter | VIA stack | value [-S|+|-] [Zähler | *]] ** "
+ "RUN find DRILL Durchmesser [Zähler | *] ** "
+ "RUN find VALUE alter_value CH neuer_value [Zähler] "
+ "RUN find value -S "
+ "RUN find value+ | - (Step-Option) "
+ " "
+ "Suchbegriff ist der name des Device/Package/Net/Bus/Pin/Pad/Signal/Value "
+ "Zähler legt die Anzahl der gefundenen Elemente fest, nach der die Suche beendet wird "
+ "* setzt den Zähler auf 1000 "
+ "PIN | PAD | DEV | GATE sucht zusätzlich nach PIN-, PAD-, GATE-, DEVICE-Namen "
+ "GATE ohne Namen, platziert das zuerst gefundene, nicht benutzte Gate. "
+ "GATE * listet alle nicht benutzen Gates; das aus der Liste gewählte Gate wird plaziert. "
+ "VIAstart end sucht Blind- Buried- und Micro-Via einer bestimmten Länge "
+ "VALUEvalueCHvalue ersetzt den Value des gefundenen Elements (CH beachtet die Gross-/Klein-Schreibung) "
+ "value-S zeigt alle Elemente mit gleichen Values gleichzeitig (gehighlightet wie bei SHOW), nur in BRD. "
+ "-+ zeigt die gefundenen Elemente Schritt für Schritt (+ vor, - zurück), in BRD und SCH "
+ "
"
+ "Such-Reihenfolge: "
+ "
"
+ "
Schematic:
Board:
"
+ "
1. Part name
1. Element
"
+ "
2. Net name
2. Signal/Wires/Vias
"
+ "
3. Bus name
3. Pads
"
+ "
4. Value
4. Value
Keine Unterscheidung der Groß-/Kleinschreibung.
"
+ "
5. Device **
5. Polygon width **
"
+ "
6. Gate **
6. Drill
"
+ "
7. Pin **
7. Via stack
"
+ "
8. Pad **
8. Roundness
" // 2013-07-02
+ "
9. Text
"
+ "
"
+ "** nach Device-, Gate-, Pin-, Pad-Namen, Polygon-Width und Drill-Durchmesser wird gesucht, falls DEV, GATE, PIN, PAD, POLYGON oder DRILL gesetzt ist. "
+ ""
+ "Im Symbol-Editor kann nach Pin-Name, im Package-Editor kann nach Pad/Smd-Name gesucht werden.
"
+ "Author: support@cadsoft.de";
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+
+// Version 1.1 2005.06.15 - CH : search and replace Value / Suchen und ersetzen das Value alf@cadsoft.de
+// Zuweisung von Vfind berichtigt, es konnten nur Values mit Großschreibung gefunden werden.
+// durchsuchen von Netz-Namen in Bussen berichtigt.
+// Version 1.2 2005.07.19 - Search also in Polygon - contour - wire
+//
+// Version 1.3 2005.11.14 - Search Part_Name
+//
+// Version 1.4 2006.04.25 - Show all parts with same Value in Board
+//
+// Version 1.5 2006.05.08 - Clip zoom coordinate for show to maximum
+//
+// Version 1.6 2006.09.26 - Find also (Device+)GATE-name
+//
+// Version 1.7 2006.11.09 - +/- Trace step by step with value
+// ein neuer Suchbegriff setzt den Trace-counter auf 0
+//
+// Version 1.8 2007.02.13 - Find Net without Segment-Wire, but with Pinref
+//
+// Version 1.9 2007.02.23 - Find Polygons with Wire-Width
+// Zuweisung von Vfind als Kommadozeileneingabe berichtigt
+// In Bus-Namen werden jetzt auch Netze in der Schreibweise "D[0..7],A[0..15]" gefunden
+// Falls der Layer des gefundenen Element nicht Visible ist wird er eingeschaltet
+//
+// Version 2.0 2007.04.23 - Find Drills (Pad, Via, Hole - Diameter)
+// GATE
+// VIA stack, sucht Vias von Layer bis Layer
+//
+// Version 2.1 2007.06.27 - Erst die Anzahl der gefundenen Elemente anzeigen, dann mit SHOW markieren,
+// damit man anschliessend mit WINDOW bzw. Scroll-Rad zoomen kann ohne daß die
+// Markierung (highlighten) aufgehoben wird.
+// Abfrage des Zähler argc für die zu suchende Anzahl berichtigt.
+//
+// Version 2.2 2007.07.05 - Hilfe in #usage en: de: integriert.
+//
+// Version 2.3 2007.10.16 - Find PIN in Symbol
+// - Find PAD/SMD in Package
+//
+// Version 2.4 2008.06.10 - Window-Befehl für SCH angepasst,
+// Zoomfenster in SCH über Area berechnet
+// Zähler für Option PAD/PIN/DEV berichtigt
+// require 5.0.1
+//
+// Version 2.5 2010.09.03 - Suche auch in TEXTen
+//
+// Version 2.6 2013.07.02 - Suche nach Roundness bei SMD
+//
+// Version 2.7 2013.11.25 - Option Change Value berichtigt run find oldvalue CH newvalue *
+//
+// Version 2.8 2014.03.21 - corrected option -S
+//
+
+#require 5.1200;
+string Version = "Version 2.8";
+string Find;
+string Vfind;
+string NewValue;
+int Change_Value = 0;
+string Again;
+string Fpin;
+string FndPin = "Element";
+string foundelement = "";
+
+enum { sNull, sPin, sPad, sDevice, sGate, sValue };
+string SCHfPinPad[] = { "", "PIN", "PAD", "DEV", "GATE", "VALUE"};
+
+enum { bNull, bPad, bValue, bPolygon, bDrill, bVia, bRoundness };
+string BRDfPinPad[] = { "", "PAD", "VALUE", "POLYGON", "DRILL", "VIA", "ROUNDNESS" };
+ // for "POLYGON", "DRILL", "VIA" see also function returnfind() and function show_B()
+
+string Invoke[] ; // invoke list of not placed gates
+
+int Vstart;
+int Vend;
+
+int Fcnt = 0;
+int CntStep = 0;
+string StepFile = "";
+int all;
+int cnt;
+int StepMode = 0; // for trace vorward/backward of elements for show
+int Result;
+real lastZoom = 0;
+int lastSheet = 0;
+real PolyWidth = 0;
+real DrillDiam = 0;
+int Roundness = 0;
+
+int OptShow = 0; // Only board. Option to manually placing 2006.04.25
+int display_layer[];
+
+
+int test = 0;
+
+string fileName = argv[0];
+string scriptfile = filesetext(fileName, "$$$.scr");
+
+int gridunit;
+string unit[] = { "Micron", "mm", "Mil", "Inch" };
+
+string repeat = "";
+
+// ### Functions ###
+real u2u(int val) {
+ switch (gridunit) {
+ case GRID_UNIT_MIC : return u2mic(val);
+ case GRID_UNIT_MM : return u2mm(val);
+ case GRID_UNIT_MIL : return u2mil(val);
+ case GRID_UNIT_INCH : return u2inch(val);
+ }
+}
+
+string dpbacksl(string fs) {
+ int l = 0;
+ do {
+ if (fs[l] == '\\') {
+ string fs1 = strsub(fs, 0 , l + 1);
+ string fs2 = strsub(fs, l + 1 );
+ fs = fs1 + "\\" + fs2;
+ l += 2;
+ }
+ l++;
+ } while (fs[l]);
+ return fs;
+}
+
+
+string check_layer(void) {
+ board(B) {
+ B.layers(L) {
+ display_layer[L.number] = L.visible;
+ string s;
+ if (L.number == 21 || L.number == 22 || L.number == 25 || L.number == 26 || L.number == 27 || L.number == 28 || L.number == 51 || L.number == 52 ) {
+ if (L.visible) return "DISPLAY NONE 21 -23 25 27 51 22 -24 26 28 52;\n"; // display only Top layer
+ }
+ else if (L.visible) return "DISPLAY NONE 21 -23 25 27 51 22 -24 26 28 52;\n"; // display only Top layer
+ }
+ }
+ return "";
+}
+
+
+void showrepeat(string text) {
+ dlgDialog("FIND.ULP") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(300);
+ dlgTextEdit(text);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+&OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ return;
+}
+
+
+string returnfind(void) {
+ string rs;
+ if (!Fpin) FndPin = "Element";
+
+ if (Fpin == "POLYGON") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin);
+ else if (Fpin == "DRILL") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin);
+ else if (Fpin == "VIA") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin);
+ else if (Fpin == "ROUNDNESS") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin);
+ else if (StepMode){
+ if (StepMode == Fcnt) exit(repeat);
+ else repeat = ""; // no message while step mode
+ return "";
+ }
+ else sprintf(rs, "run ulpmessage.ulp '%d %s(s) %s found!' '%s';\n", Fcnt, FndPin, Find, foundelement); // 2007.03.23 alf
+
+ if (Find) {
+ if (CntStep) {
+ if (CntStep > Fcnt) {
+ output(StepFile, "wt") printf("%d\n%s\n%d", Fcnt, Vfind, CntStep); // write actual counter in file
+ }
+ else return ""; // for Trace step by step disply no message
+ }
+ }
+ return dpbacksl(rs);
+}
+
+
+void check(string repeat) {
+ if (OptShow) {
+ if (test) showrepeat(repeat);
+ if (Fcnt) {
+ exit(repeat);
+ }
+ return;
+ }
+ repeat = returnfind() + repeat;
+ if (test) showrepeat(repeat);
+ exit (repeat); // first messagebox than show 2007.06.27 alf
+}
+
+
+void helpULP(void) {
+ dlgDialog("find.ulp") {
+ dlgHBoxLayout dlgSpacing(550);
+ dlgLabel(usage);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ return;
+}
+
+
+string getfind() {
+ real Dmin = 0.0, Dmax = u2u(13100);
+ string f;
+ all = 0;
+ int sel_m = 0;
+ int findpoly = 0;
+ Result = dlgDialog("Find Element") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgHBoxLayout {
+ dlgLabel("&Name ");
+ dlgStringEdit(f);
+ dlgLabel(" (Value) ");
+ dlgSpacing(30);
+ dlgStretch(1);
+ dlgPushButton("&Help") helpULP();
+ }
+ dlgHBoxLayout {
+ dlgLabel("&Counts");
+ dlgIntEdit(all, 0, 10000);
+ dlgSpacing(200);
+ dlgStretch(1);
+ dlgLabel(Version);
+ dlgSpacing(12);
+ }
+ dlgHBoxLayout {
+ if (schematic) {
+ dlgGroup("Find options") {
+ dlgRadioButton("&...", sel_m) Fpin = "";
+ dlgRadioButton("P&IN", sel_m) { Fpin = "PIN"; }
+ dlgRadioButton("P&AD", sel_m) { Fpin = "PAD"; }
+ dlgRadioButton("&DEV", sel_m) { Fpin = "DEV"; }
+ dlgRadioButton("&GATE", sel_m) { Fpin = "GATE"; }
+ dlgHBoxLayout {
+ dlgRadioButton("&VALUE", sel_m) Fpin = "";
+ dlgSpacing(22);
+ dlgCheckBox(" &change to ", Change_Value);
+ dlgLabel(" Val&ue ");
+ dlgStringEdit(NewValue);
+ dlgStretch(1);
+ }
+ }
+ }
+ if (board) {
+ dlgGroup("Find options") {
+ dlgRadioButton("&...", sel_m) Fpin = "";
+ dlgRadioButton("P&AD", sel_m) Fpin = "PAD";
+ dlgHBoxLayout {
+ dlgRadioButton("&VALUE", sel_m) Fpin = "";
+ dlgSpacing(12);
+ dlgCheckBox(" &change to", Change_Value) if (Change_Value) OptShow = 0;
+ dlgLabel("Val&ue ");
+ dlgStringEdit(NewValue);
+ dlgSpacing(12);
+ dlgCheckBox("Sh&ow all ", OptShow) if (OptShow) Change_Value = 0;
+ dlgSpacing(132);
+ }
+ dlgHBoxLayout {
+ dlgRadioButton("POL&YGON", sel_m) Fpin = "PPOLYGON";
+ dlgSpacing(70);
+ dlgLabel(" &Width ");
+ dlgRealEdit(PolyWidth, 0, 10000);
+ dlgSpacing(90);
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgRadioButton("&DRILL", sel_m) Fpin = "DRILL";
+ dlgSpacing(73);
+ dlgLabel(" Diamete&r ");
+ dlgRealEdit(DrillDiam, Dmin, Dmax);
+ dlgSpacing(90);
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgRadioButton("V&IA layer stack", sel_m) Fpin = "VIA";
+ dlgSpacing(45);
+ dlgLabel(" &Start ");
+ dlgIntEdit(Vstart, 0, 16);
+ dlgSpacing(12);
+ dlgLabel(" &End ");
+ dlgIntEdit(Vend, 0, 16);
+ dlgSpacing(90);
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgRadioButton("&ROUNDNESS", sel_m) Fpin = "ROUNDNESS";
+ dlgSpacing(72);
+ dlgLabel(" &% ");
+ dlgIntEdit(Roundness, 0, 100);
+ dlgSpacing(250);
+ dlgStretch(1);
+ }
+ }
+ dlgStretch(1);
+ }
+ }
+ dlgStretch(0);
+ dlgHBoxLayout {
+ dlgPushButton("+&Find") {
+ dlgAccept();
+ all--;
+ }
+ dlgStretch(1);
+ dlgPushButton("-Cancel") { dlgReject(); exit(-1); }
+ }
+ dlgStretch(1);
+ }
+ }
+ };
+ if (!f && Fpin == "GATE") f = "0";
+ return f;
+}
+
+
+real clip_zoom(real v) { // clip value to max. coordinate 2006.05.08
+ switch (gridunit) {
+ case GRID_UNIT_MIC : if (v > 838200) return 838200;
+ if (v < -838200) return -838200;
+ break;
+ case GRID_UNIT_MM : if (v > 838.2) return 838.2;
+ if (v < -838.2) return -838.2;
+ break;
+ case GRID_UNIT_MIL : if (v > 33000.0) return 33000;
+ if (v < -33000.0) return -33000;
+ break;
+ case GRID_UNIT_INCH : if (v > 33.0) return 33;
+ if (v < -33.0) return -33;
+ break;
+ }
+ return v;
+}
+
+
+// #### make script line for show in board ####
+string show_B(real x, real y, real zoom1, real zoom2, string findb, int fist, int layer) {
+ Fcnt++;
+ string cmd = "";
+ string cmd_show;
+
+ if (findb[0] == '(') sprintf(cmd_show, "SHOW %s ", findb); // 2010.09.03 alf bei TEXTen Koordinate benutzen
+ else if (OptShow)sprintf(cmd_show, " '%s' ", findb); // 2014.03.21 corrected option -S
+ else sprintf(cmd_show, ";SHOW '%s' ", findb); // 2007.06.27 alf
+
+ if (Fpin == "PAD") cmd_show = ""; // can not show pads
+ if (Fpin == "POLYGON") sprintf(cmd_show, ";SHOW (%.4f %.4f);\n", x, y); // do not show polygons
+ // ### can not show drills ###
+ if (Fpin == "DRILL") cmd_show = ""; // do not change this line
+ // ### can not show vias, only complete signal ###
+ if (Fpin == "VIA") { cmd_show = ""; layer = 0; } // do not change this line
+ if (Fpin == "ROUNDNESS") { cmd_show = "";} // do not change this line 2013-07-02
+
+ if (OptShow) {
+ sprintf(cmd, "%s", cmd_show);
+ }
+ else {
+ if (lastZoom) {
+ if (StepMode) {
+ sprintf(cmd, "\n;WINDOW (%.6f %.6f) ;\n%s",
+ x, y,
+ cmd_show
+ );
+ }
+ else {
+ sprintf(cmd, "\n;WINDOW (%.6f %.6f) (%.6f %.6f) (%.6f %.6f);\n%s;\n",
+ x, y,
+ x, y,
+ x, y,
+ cmd_show
+ );
+ }
+ }
+ else {
+ if (StepMode) {
+ sprintf(cmd,
+ ";\nWINDOW (%.6f %.6f);\n%s",
+ x, y,
+ cmd_show
+ );
+ }
+ else {
+ sprintf(cmd, ";WINDOW FIT;\n"
+ ";WINDOW (%.6f %.6f) (%.6f %.6f) (%.6f %.6f);\n%s",
+ x, y,
+ clip_zoom(x + zoom1), y,
+ clip_zoom(x + zoom2), y,
+ cmd_show
+ );
+ lastZoom = zoom2;
+ }
+ }
+ }
+ if (Change_Value) { // 2013-10-24
+ string chval;
+ sprintf(chval, "; VALUE %s '%s';\n", findb, NewValue);
+ cmd += chval;
+ }
+
+ if (!display_layer[layer] && layer != 0) {
+ sprintf(cmd_show, "DISPLAY %d;\n%s", layer, cmd);
+ cmd += cmd_show;
+ }
+ if (Fpin == "VIA") {
+ sprintf(cmd_show, "DISPLAY %d %d 18;\n", Vstart, Vend);
+ cmd += cmd_show;
+ }
+ if (Fpin == "ROUNDNESS") { // 2013-07-02
+ sprintf(cmd_show, "DISPLAY 1 16;\n");
+ cmd += cmd_show;
+ }
+ return cmd;
+}
+
+
+// #### make script line for show in schematic ####
+string show_S(int s, real x1area, real y1area, real x2area, real y2area, string finds) {
+ Fcnt++;
+ string cmd_show;
+ if (finds[0] == '(') sprintf(cmd_show, ";SHOW %s ", finds); // 2010.09.03 alf Bei TEXTen kann nur die Koordinate benutzt werden
+ else sprintf(cmd_show, "\n;SHOW '%s' ", finds); // 2007.06.27 alf
+
+ string cmd = "";
+ if (s != lastSheet) {
+ lastSheet = s;
+ if (StepMode) {
+ sprintf(cmd, ";\nEDIT .s%d;\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s,
+ x1area, y1area,
+ x2area, y2area,
+ cmd_show
+ );
+ }
+ else {
+ sprintf(cmd, ";\nEDIT .s%d;\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s,
+ x1area, y1area,
+ x2area, y2area,
+ cmd_show
+ );
+ }
+ }
+ else {
+ if (StepMode) {
+ sprintf(cmd, ";\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s,
+ x1area, y1area,
+ x2area, y2area,
+ cmd_show
+ );
+ }
+ else {
+ sprintf(cmd, ";\nEDIT .s%d;\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s,
+ x1area, y1area,
+ x2area, y2area,
+ cmd_show
+ );
+ }
+ }
+ if (Change_Value) { // 2013-10-24
+ string chval;
+ sprintf(chval, "; VALUE %s '%s';\n", finds, NewValue);
+ cmd += chval;
+ }
+ if (StepMode) {
+ if (CntStep != Fcnt) cmd = "";
+ }
+ return cmd;
+}
+
+
+real zfactor(real x1, real y1, real x2, real y2) {
+ return sqrt( pow(x2 - x1, 2) + pow(y2 - y1, 2) );
+}
+
+
+
+// *** split bus-name from net-name ***
+int findBus(string name, string sfind) {
+ string bn[];
+ int b;
+ b = strsplit(bn, name, ':');
+ string nn[];
+ if (b == 2) {
+ b = strsplit(nn, bn[1], ',');
+ }
+ else {
+ b = strsplit(nn, name, ',');
+ }
+ for (int x = 0; x < b; x++) {
+ if(nn[x] == sfind) return 1;
+ }
+ // *** search for name[n..n] ***
+ string nm;
+ for (x = 0; x < b; x++) {
+ int pos1 = strchr(nn[x], '[');
+ int pos2 = strchr(nn[x], '.');
+ int pos3 = strchr(nn[x], ']');
+ string Pref = strsub(nn[x], 0 , pos1);
+ string n1 = strsub(nn[x], pos1+1, pos2-pos1-1);
+ string n2 = strsub(nn[x], pos2+2, pos3-pos2-2);
+ for (int n = strtol(n1); n <= strtol(n2); n++) {
+ sprintf(nm, "%s%d", Pref, n);
+ if (nm == sfind) return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+// *** trace elemete step by step ***
+string get_step(int step) {
+ StepMode = 1;
+ CntStep = 0;
+ string s = "";
+ string lastvalue;
+ StepFile = filesetext(argv[0], ".stp");
+ string sf[];
+ int isfile = fileglob(sf, StepFile);
+ if (isfile) {
+ string t[];
+ int ct = fileread(t, StepFile);
+ CntStep = strtod(t[0]);
+ if (Vfind != t[1]) CntStep = 0;
+ }
+ CntStep += step;
+ if (CntStep < 1) {
+ CntStep = 1;
+ dlgMessageBox("!This is the first Element", "OK");
+ }
+ output(StepFile, "wt") printf("%d\n%s", CntStep, Vfind); // write actual counter in file
+ sprintf(s, "%d", CntStep);
+ return s;
+}
+
+
+string get_invoke(void) {
+ int sel;
+ int Result = dlgDialog("Invoke unused gates") {
+ dlgListView("Gates to Invoke", Invoke, sel) { dlgAccept(); return Invoke[sel]; }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ dlgStretch(1);
+ }
+ };
+ if (Result) return Invoke[sel];
+ return "";
+}
+
+
+
+// ****** Main ******
+
+Vfind = argv[1];
+if (argc > 2) Again = strupr(argv[argc-1]); // 2007.06.27 alf
+if (argv[2] == "+") { Again = get_step(1); StepMode = strtod(Again); }
+if (argv[2] == "-") { Again = get_step(-1); StepMode = strtod(Again); }
+
+if (symbol) symbol(S) { // 2007.10.16
+ Vfind = strupr(argv[1]);
+ if (!Vfind) {
+ dlgMessageBox(usage + " " + Version);
+ exit(0);
+ }
+ library(L) gridunit = (L.grid.unit);
+ S.pins(P) {
+ if (P.name == Vfind) {
+ sprintf(Vfind, "WIN (%.4f %.4f);", u2u(P.x), u2u(P.y) );
+ exit(Vfind);
+ }
+ }
+ exit("run ulpmessage.ulp '" + Vfind + " not found!';\n");
+}
+
+else if (package) package(P) { // 2007.10.16
+ Vfind = strupr(argv[1]);
+ if (!Vfind) {
+ dlgMessageBox(usage + " " + Version);
+ exit(0);
+ }
+ library(L) gridunit = (L.grid.unit);
+ P.contacts(C) {
+ if (C.name == Vfind) {
+ sprintf(Vfind, "WIN (%.4f %.4f);", u2u(C.x), u2u(C.y) );
+ exit(Vfind);
+ }
+ }
+ exit("run ulpmessage.ulp '" + Vfind + " not found!';\n");
+}
+
+else if (schematic) {
+ if ( strupr(argv[1]) == SCHfPinPad[1]) { Fpin = SCHfPinPad[1]; Vfind = argv[2]; } // "PIN"
+ else if ( strupr(argv[1]) == SCHfPinPad[2]) { Fpin = SCHfPinPad[2]; Vfind = argv[2]; } // "PAD"
+ else if ( strupr(argv[1]) == SCHfPinPad[3]) { Fpin = SCHfPinPad[3]; Vfind = argv[2]; } // "DEV"
+ else if ( strupr(argv[1]) == SCHfPinPad[4]) { // "GATE"
+ Fpin = SCHfPinPad[4];
+ Vfind = argv[2];
+ if (!Vfind) { // found Gates are not placed in schematic
+ Vfind = "0";
+ }
+ }
+ else if ( strupr(argv[1]) == SCHfPinPad[5]) { Fpin = SCHfPinPad[5]; Vfind = argv[2]; } // "VALUE"
+ if (argc > 2) Again = strupr(argv[argc-1]);
+ else Again = "";
+}
+
+else if (board) {
+ if ( strupr(argv[1]) == BRDfPinPad[bPad]) { Fpin = BRDfPinPad[bPad]; Vfind = argv[2]; } // "PAD"
+ else if ( strupr(argv[1]) == BRDfPinPad[bValue]) { Fpin = BRDfPinPad[bValue]; Vfind = argv[2]; } // "VALUE"
+ else if ( strupr(argv[1]) == BRDfPinPad[bPolygon]) { // "POLYGON"
+ Fpin = BRDfPinPad[bPolygon];
+ Find = BRDfPinPad[bPolygon];
+ PolyWidth = strtod(argv[2]);
+ if (argc > 3) Again = strupr(argv[argc-1]);
+ else Again = "";
+ }
+ else if ( strupr(argv[1]) == BRDfPinPad[bDrill]) { // "DRILL"
+ Fpin = BRDfPinPad[bDrill];
+ Find = BRDfPinPad[bDrill];
+ DrillDiam = strtod(argv[2]);
+ if (argc > 3) Again = strupr(argv[argc-1]);
+ else Again = "";
+ }
+ else if ( strupr(argv[1]) == BRDfPinPad[bVia]) { // "VIA"
+ Fpin = BRDfPinPad[bVia];
+ Find = BRDfPinPad[bVia];
+ Vstart = strtod(argv[2]);
+ Vend = strtod(argv[3]);
+ if (argc > 4) Again = strupr(argv[argc-1]);
+ else Again = "";
+ }
+ else if ( strupr(argv[1]) == BRDfPinPad[bRoundness]) { // "ROUNDNESS" 2013-07-02
+ Fpin = BRDfPinPad[bRoundness];
+ Find = BRDfPinPad[bRoundness];
+ Roundness = strtol(argv[2]);
+ if (argc > 3) Again = strupr(argv[argc-1]);
+ else Again = "";
+ }
+}
+
+else {
+ if (language() == "de") dlgMessageBox("Starten Sie dieses ULP in einem Schaltplan, Board, Symbol oder Package Editor", "OK");
+ else dlgMessageBox("Start this ULP in Schematic, Board, Symbol or Package Editor", "OK");
+ exit(0);
+}
+
+if (argv[3] == "CH") {
+ Change_Value = 1;
+ NewValue = argv[4];
+}
+
+
+if (Again == "*") all = 1000;
+else all = strtol(Again) - 1;
+
+if (!Vfind) {
+ Vfind = getfind();
+}
+
+if (Change_Value) Find = Vfind; // 2013-11-25
+else Find = strupr(Vfind);
+if (!Find && Change_Value) exit (0);
+cnt = all + 1;
+
+if (!Fpin && !Find) {
+ dlgMessageBox("Missing options", "OK");
+ exit(-1);
+}
+
+
+// *** Board coord. ***
+if (board) {
+ int mx, my; // 2008.06.10 alf
+ if (argv[2] == "-S") OptShow = 1; // Show option 2006.04.25
+ board(B) {
+ gridunit = (B.grid.unit);
+ if (OptShow) {
+ all = 10000;
+ repeat = check_layer();
+ repeat += ";SHOW;\nWIN;\nSHOW "; // refresh window clear showed elements // 2007.06.27 alf
+ }
+
+ mx = B.area.x2 + (B.area.x1 * -1);
+ my = B.area.y2 + (B.area.y1 * -1);
+ if (Vfind) {
+ B.elements(E) {
+ if (E.value == Vfind || E.value == Find) {
+ FndPin = "Value";
+ if (StepMode && all > 0) {
+ ; // do nothing
+ }
+ else {
+ repeat += show_B(u2u(E.x), u2u(E.y), 2, 5, E.name, all, E.mirror);
+ sprintf(foundelement, "Element %s on (%.4f %.4f)", E.name ,u2u(E.x), u2u(E.y) );
+ }
+ if (all <= 0) check(repeat);
+ all--;
+ }
+ }
+ }
+ if (!Fpin && Find) {
+ B.elements(E) {
+ if (E.name == Find) {
+ FndPin = "Element";
+ repeat += show_B(u2u(E.x), u2u(E.y), 2, 5, Find, all, E.mirror);
+ sprintf(foundelement, "Element %s on (%.4f %.4f)", E.name, u2u(E.x), u2u(E.y) );
+ check(repeat);
+ }
+ }
+ B.signals(S) {
+ if (S.name == Find) {
+ S.contactrefs(C) {
+ if (C.contact) { // 2011-02-30 first request if a connect.
+ FndPin = "Signal";
+ repeat += show_B(u2u(C.contact.x), u2u(C.contact.y), 2, 5, Find, all, 0); // 0 = dummy for Layer
+ if (all <= 0) check(repeat);
+ all--;
+ }
+ else {
+ dlgMessageBox("Found signal '"+S.name+ "' without contactref!\nCheck consistence and corrupted signals.", "OK");
+ exit(-1);
+ }
+ }
+ }
+ }
+ B.signals(S) {
+ if (S.name == Find ) {
+ S.wires(W) {
+ FndPin = "Wire";
+ real z = zfactor(u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2) );
+ repeat += show_B( u2u((W.x1 + W.x2)/2), u2u((W.y1 + W.y2)/2), z/(z/2) , z/(z/5), Find, all, W.layer);
+ if (all <= 0) check(repeat);
+ all--;
+ }
+ }
+ }
+ B.signals(S) {
+ if (S.name == Find ) {
+ S.polygons(P) {
+ FndPin = "Polygon";
+ P.contours(W) {
+ real z = zfactor(u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2) );
+ repeat += show_B( u2u((W.x1 + W.x2)/2), u2u((W.y1 + W.y2)/2), z/(z/2) , z/(z/5), Find, all, W.layer);
+ if (all <= 0) check(repeat);
+ all--;
+ break;
+ }
+ }
+ }
+ }
+ B.signals(S) {
+ if (S.name == Find ) {
+ S.vias(V) {
+ FndPin = "Via";
+ repeat += show_B(u2u(V.x), u2u(V.y), 1, 5, Find, all, 18); // 18 dummy layer for via
+ sprintf(foundelement, "Element on (%.4f %.4f) %s VIA
"
+ ,
+ "de:Erzeuge die Daten für die 3D-Ausgabe des generate_3d_data(v13).ulp in dem "
+ "geladenen Package.
"
+ "RUN gen-3D-pac-idf [high-top high-bottom]
"
+ "high tophigh bottom == mm. Die tatsächliche Höhe des Bauteil. "
+ "Beachten Sie auch die interne Auflösung von Eagle V6 (3.125 Nanometer), und daß WIRE immer eine "
+ "Breite von 2 Einheiten benötigen. Dadurch ergeben sich WIRE-Breiten mit einem mehrfachen von "
+ "6.25 Nanometer.
"
+ "
"
+ "Es werden nur Objekte (WIRE/RECT) im Layer 21/51 & 22/52 im Layr 57/58 nachgezeichnet. "
+ "Das generate_3d_data_v13.ulp von Herrn Naubacher benutzt die Layer 57 und 58, "
+ "um die Daten für die 3. Dimension (Z-Achse) im .PAC zu hinterlegen. "
+ "Das generate_3d_data(v13).ulp liest im Board diese Daten (WIRE-Breite) und multipliziert sie mit 1000. "
+ "Der Trick ist, die Linienbreite der Bestückungsdruck (Layer 57 für Top und Layer 58 für Bottom) "
+ "in micrometer abzulegen. Diese dünnen Linien stören später die grafische Ansicht nicht, wenn goße Werte "
+ "für die 3. Dimension (Z-Achse) angegeben werden müssen, und man mit DISPLAY 57 58 die komplette Zeichnung "
+ "(alle Layer) anzeigt."
+ "Da die Lötbeinchen typischerweise mit RECT gezeichnet werden, bietet sich an, für RECT eine eigene "
+ "Höhenangabe zu berücksichtigen, wobei hier das Problem besteht, das EAGLE an einem Koorinatenpaar nur "
+ "eine Wirebreite zulässt. Hier muß dafür gesorgt werden, daß WIRE im Layer 57/58 die die gleiche "
+ "ausrichtung besitzen aber unterschiedlich breit sein müssen (wegen Z) nicht an den gleichen Koordinaten "
+ "beginnen bzw. Enden wie die RECTs. EAGLE würde sonst die Wirekoordinaten integrieren und eine "
+ "resultierende Wirebreite erzeugen. Es muß also dafür gesorgt werden, das die unterschiedlichen Wirebreiten "
+ "mindestens mit einen Versatz von einer Eagle-Einheit (3.125nanometer) gezeichnet werden."
+ "Author: alf@cadsoft.de"
+
+string Verison = "1.0.2"; // 2013-01-14 alf@cadsoft.de
+ // 2013-04-23 now with menu
+ // 2014-03-13 draw also RECT as wire with "high" as line
+
+int Test = 0;
+
+// Benutzung : Xneu(X, Y, X-drehpunkt, Y-drehpunkt, UserWinkel)
+real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) {
+ real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
+ real WinkelNeu;
+ /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
+ if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
+ WinkelNeu = (Xalt - Xorigin) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */
+ WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */
+ WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad));
+ }
+}
+
+// Benutzung : Yneu(X, Y, X-drehpunkt, Y-drehpunkt, UserWinkel)
+real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) {
+ real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
+ real WinkelNeu;
+ /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
+
+ if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
+ WinkelNeu = (Xalt - Xorigin) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */
+ WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+ if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */
+ WinkelNeu = (Xalt - Xorigin + 270) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad));
+ }
+}
+
+if (package) {
+ real Ztop = strtod(argv[1]);
+ real Zbottom = strtod(argv[1]);
+
+ if (argc == 1) {
+ int optg, optb;
+ dlgDialog("IDF 3D Package") {
+ dlgLabel(usage);
+ dlgLabel("");
+ dlgHBoxLayout {
+ dlgGridLayout {
+ dlgCell( 0, 0) dlgLabel("&Z high top mm");
+ dlgCell( 0, 1) dlgRealEdit(Ztop);
+ dlgCell( 1, 0) dlgLabel("&Z high bottom mm");
+ dlgCell( 1, 1) dlgRealEdit(Zbottom);
+
+ }
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") {
+ Ztop /= 1000;
+ Zbottom /= 1000;
+ if (Ztop >= u2mm(2) || Zbottom >= u2mm(2) ) {
+ dlgAccept();
+ }
+ else {
+ if (language() != "de") {
+ dlgMessageBox("First type in a real value for Z of Top and/or Bottom.", "OK");
+ }
+ else {
+ dlgMessageBox("Geben Sie zuerst einen (gültigen) Wert für die Höhe Z von Top bzw. Bottom ein.", "OK");
+ }
+ }
+ }
+ dlgPushButton("-CANCEL") { dlgReject(); exit(0); }
+ dlgStretch(1);
+ }
+ };
+ }
+
+ string cmd, s;
+ string cmdl = "";
+ int layer3dt, layer3db;
+
+ library(LIB) LIB.layers(LAY) {
+ if(LAY.number == 57) layer3dt = LAY.number;
+ if(LAY.number == 58) layer3db = LAY.number;
+ }
+ if (!layer3dt && !layer3db) {
+ layer3dt = 57;
+ layer3db = 58;
+ cmdl = "LAYER 57 t3D; SET COLOR_LAYER 57 6; SET FILL_LAYER 57 5; LAYER 58 b3D; SET COLOR_LAYER 58 5; SET FILL_LAYER 58 4;";
+ }
+
+ if (Ztop < u2mm(2)) {
+ string h, com;
+
+ if (language() != "de") {
+ sprintf(h, "!The calculated value for Z-top %.9f is < %.9fmm", Ztop, u2mm(2));
+ com = "CANCEL";
+ }
+ else {
+ sprintf(h, "!Der umgerechnete Wert für Z-top %.9f ist < %.9fmm", Ztop, u2mm(2));
+ com = "ABBRUCH";
+ }
+ dlgMessageBox(h, com);
+ exit(-1);
+ }
+ if (Ztop < u2mm(2)) {
+ string h, com;
+
+ if (language() != "de") {
+ sprintf(h, "!The calculated value for Z-bottom %.9f is < %.9fmm", Ztop, u2mm(2));
+ com = "CANCEL";
+ }
+ else {
+ sprintf(h, "!Der umgerechnete Wert für Z-bottom %.9f ist < %.9fmm", Ztop, u2mm(2));
+ com = "ABBRUCH";
+ }
+ dlgMessageBox(h, com);
+ exit(-1);
+ }
+ package(P) {
+ //sprintf(cmd, "Display NONE 1 16 17 18 20 23 25 27 57;\nSET WIRE_BEND 2;\n");
+ cmd += cmdl;
+ P.rectangles(R) {
+ real rectcenterx = u2mm((R.x1 + R.x2) / 2);
+ real rectcentery = u2mm((R.y1 + R.y2) / 2);
+ if (R.layer == 21 || R.layer == 51) {
+ sprintf(s, "LAYER %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm );\n",
+ layer3dt,
+ Ztop,
+ Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery
+ );
+ cmd += s;
+ }
+ else if (R.layer == 22 || R.layer == 52) {
+ sprintf(s, "LAYER %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm );\n",
+ layer3db,
+ Zbottom,
+ Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery,
+
+ Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx,
+ Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery
+ );
+ cmd += s;
+ }
+ }
+ P.wires(W) {
+ if (W.layer == 21 || W.layer == 51) {
+ sprintf(s, "Layer %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) %+.3f (%.9fmm %.9fmm );\n",
+ layer3dt,
+ Ztop,
+ u2mm(W.x1), u2mm(W.y1), W.curve, u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd += s;
+ }
+ else if (W.layer == 22 || W.layer == 52) {
+ sprintf(s, "Layer %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) %+.3f (%.9fmm %.9fmm );\n",
+ layer3db,
+ Zbottom,
+ u2mm(W.x1), u2mm(W.y1), W.curve, u2mm(W.x2), u2mm(W.y2)
+ );
+ cmd += s;
+ }
+ }
+ }
+ if (Test) {
+ dlgDialog("3D IDF test") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(600);
+ dlgTextEdit(cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("ok") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-273); }
+ dlgStretch(1);
+ }
+ };
+ }
+ exit(cmd);
+}
+
+else {
+ if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Package (Bibliothek)", "OK");
+ else dlgMessageBox("Start this ULP in a package (library)", "OK");
+}
\ No newline at end of file
diff --git a/trunk/ulp/generate-3d-idf-data.ulp b/trunk/ulp/generate-3d-idf-data.ulp
new file mode 100644
index 00000000..438e5c2a
--- /dev/null
+++ b/trunk/ulp/generate-3d-idf-data.ulp
@@ -0,0 +1,1018 @@
+
+#usage "en:export 3d-data from board to IDF-FileFormat
"
+ "More info can be found here: .../eagle.../doc/generate_3d_data_eng.pdf "
+ "Original author: Uploaded by Neubacher Andreas from Commend International GmbHh "
+ "co-Author: alf@cadsoft.de
"
+ ,
+ "de:export 3d-data from board to IDF-FileFormat
"
+ "Im Layer 50 muß eine Kopie der Boardkontour des Layer 20 angelegt werden. Die Wirebreite in Micron "
+ "ergibt die Boarddicke in mm. "
+ "Die Bordkontour kann entweder im Board lebst oder in einem Package angelegt werden, es muß nur die "
+ "obenstehende Bedingung eingehalten werden. "
+ "Um in einem Board einen Durchbruch zu erzeugen, kann man entweder im Board selbst oder in einem Package "
+ "eine Kontur mit der Wirebreite von 0 im Layer 50 anlegen. "
+ "Original author: Uploaded by Neubacher Andreas from Commend International GmbHh "
+ "co-Author: alf@cadsoft.de
"
+
+#require 6.0600
+string UlpVersion = "1.9";
+
+string Docuemantpath = "Weiter Infos finden sie im Dokumentenordner unter " + path_doc[0] + "/generate_3d_data_eng.pdf ";
+
+
+//############################################################################
+// Author: Andy Neubacher
+// Version | Date | log
+//---------+------------+-----------------------------------------------------
+// v1.9 | 2014-04-08 | - Now can change the filedirectory an filename
+// select Top and or Bottom side of parts to export
+// v1.8 | 2014-04-01 | - Cutout und Koordinaten berichtigt (nur beim ersten Wire, Anfang und Endkoordinate ausgeben)
+// dann immer nur die 2. Koordinate bis die erste Koordinate wieder erreicht ist.
+// - LoopCounter für geschlossene Konturen (Durchbruch/Cutout) wieder berichtigt.
+//
+// v1.7 | 2014-01-20 | - draw also pad-holes
+// v1.6 | 2013-12-19 | - LoopCounter für geschlossene Konturen (Durchbruch/Cutout).
+// Die Bedingung für die Erkennung der einzelnen Konturen ist:
+// 1. Die allererste Kontour im Layer 50 ist die Boardkontur,
+// was bedeutet, diese Kontour muss als allererste Kontur gezeichnet werden.
+// 2. Jede weitere Kontur wird als Cutout betrachtet, und es wird keine Überprüfung
+// vorgenommen, ob diese Kontur innerhalb oder ausserhalb der Board-Dimension ist.
+// 3. Jede Kontur muss durchgehend gezeichnet und geschlossen sein.
+// Das bedeutet, man darf innerhalb einer Kontur nicht an beliebigen Punkten
+// das (WIRE) zeichnen unterbrechen, und an einer anderen Stelle wieder beginnen,
+// also dem vorher unterbrochenen *Ende* entgegen zeichnen.
+//
+// v1.5 | 2013-12-18 | - file renamed and now without version, for use in Text-Menu
+// | | - draw board cutout
+// | | - ++CutoutNumSegments change to CutoutNumSegments++
+// alf@cadsoft.de
+// v1.4 | 2013-12-11 | - correct Board outline Curve
+// | | - correct Pre- to Post-Increment in all Functions
+// | | - fixed by Angelo.Cuccato@bogen-electronic.com
+// v1.3 | 2013-03-14 | - correct using ARC coorinates
+// v1.2 | 2013-01-14 | - Link in description to download page - fixes by alf@cadsoft.de
+// v1.1 | 2012-12-04 | - korrect Loop Label for contours in layer Dimension - fixes by alf@cadsoft.de
+// v1.0 | 2012-08-20 | - more resolution %.6f of coordinates - fixes by alf@cadsoft.de
+// v0.9 | 2012-02-08 | - used function u2mm() for Z-axis value - fixes by alf@cadsoft.de
+// | |
+// v0.8 | 2011-05-31 | - changed characters that caused import problems
+// | | - changed output file extension to .emn and .emp
+// | | - fixes by morten@riftlabs.com
+// | |
+// v0.7 | 2006-10-24 | - outline of board can also be drawn direct in brd-file
+// | | - any hole is taken from devices and board direct
+// | | - close open polygons on request
+// | | - drill vias on request
+// | | - bugfix : error if device contains more than one poly on top and bottom
+// | | - bugfix : sorting of points possible failed if polygon was open
+// | | - bugfix : partheights on bottomlayer were ignored
+// v0.6 | 2006-08-31 | now multiple partheights are possible
+// v0.5 | 2006-08-25 | modification to 'RIR-standard'
+// v0.4 | 2005-11-09 | 1st export of a real board+parts successfull
+// v0.3 | 2005-11-03 | correct mirrors at top and bottom side
+// v0.2 | 2005-10-21 | 1st working IDF-data
+// v0.1 | 2005-09-30 | start of project
+//---------+------------+-----------------------------------------------------
+//
+// HOWTO:
+// Create your board outline on layer 50.
+// In your library, draw the component outlines on layer 57 (tCad) and use the line thickness to set component height.
+// 1000 mic = 1 mm (e.g. if your grid is in mm, then a line thickness of 0.001 equals a component height of 1 mm).
+// More info can be found here: ftp://ftp.cadsoft.de/eagle/userfiles/ulp/generate_3d_data_eng.pdf
+//
+//############################################################################
+
+
+int Layer3dBoardDimension = 50;
+int tLayer3Ddata = 57;
+int bLayer3Ddata = 58;
+int SelectSide[] = { 1, 1 }; // select Part output on side Top / Bottom
+int maxCutoutLineWidth = 0; // -->> is linewidth 0.0 -> line is a cutout ??
+string UlpName = filename(argv[0]); // gets ulp name
+
+
+// partoptions
+int NumParts; // number of parts
+string PartName[]; // name of part
+
+// vars for polygon calculation
+int NumSegments = 0; // number of points
+int PointX1[]; // start x
+int PointY1[]; // start y
+int PointX2[]; // end x
+int PointY2[]; // end y
+int SegmentType[]; // LINE, ARC, CIRCLE
+real SegmentCurve[]; // used by ARCs : - if drawn CCW, + if drawn CW
+int SegmentWidth[]; // linewitdh = partheight
+
+int CutoutNumSegments = 0;
+int CutoutPointX1[]; // start x
+int CutoutPointY1[]; // start y
+int CutoutPointX2[]; // end x
+int CutoutPointY2[]; // end y
+int CutoutSegmentType[]; // LINE, ARC, CIRCLE
+int CutoutSegmentCurve[]; // used by ARCs : -180 if drawn CCW, +180 if drawn CW
+int CutoutSegmentWidth[]; // linewitdh = partheight
+
+int LoopCounter = 0; // 2015-04-02 für Boardoutline und Cutoutline
+
+
+enum { LINE = 1, ARC = 2, CIRCLE = 3 };
+enum { CUTOUT = 0, OUTLINE = -1 };
+enum { false = 0, true = 1};
+string Type[];
+ Type[0] = "0";
+ Type[LINE] = "LINE";
+ Type[ARC] = "ARC";
+ Type[CIRCLE] = "CIRCLE";
+
+// vars for library
+int NumPacInLib = 0; // number of pacs in library
+int PacIn_LIB_heights[]; // if 0 = only one partheight, if != 0 more than one height
+real PacIn_LIB_angle[]; // rotation of part in board
+string PacIn_LIB_name[]; // names of pack's in library
+int PacIn_LIB_Device_mountside[]; // TOP, BOTTOM
+string PacIn_LIB_SubPart_mountside[]; // mountside of subparts
+
+
+int NumCutouts = 0; // number of holes in the pcb (drills, millings)
+int OutlineInDeviceFound = false; // is outline drawn in device symbol
+
+int CloseOpenPoly = false; // close polygon if gap is smaller than ...mm
+real MaxGapWidth = 0.1; // value of maximum gap to close
+
+int DrillViaHoles = true; // drill via-holes in pcb
+real MinViaHoleDia = 0.254; // diameter of drill
+
+
+////////////////////////////////////////////////////
+void CollectPartData(UL_BOARD brd) { // read out all parts
+ NumParts = 0;
+ brd.elements(E) {
+ PartName[NumParts] = E.name;
+ PacIn_LIB_angle[NumParts] = -1; // fill with invalid rotation and ...
+ PacIn_LIB_Device_mountside[NumParts] = -1; // fill with invalid mountside (mirror) for "void IDF_LibaryElectrical(UL_BOARD BRD)" function
+ PacIn_LIB_heights[NumParts] = 0; // part is only one package
+ NumParts++;
+ }
+}
+
+////////////////////////////////////////////////////
+void IDF_Circle(int x1, int y1, int x2, int y2, int type) { // output circle to file in IDF format
+ int loopcount = 0;
+ if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19
+ printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1));
+ printf("%d %.6f %.6f 360\n", loopcount, u2mm(x2), u2mm(y2));
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_Arc(int x1, int y1, int x2, int y2, real angle, int type, int first) { // output arc to file in IDF format
+ int loopcount = 0;
+ if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19
+ if (first) printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1));
+ printf("%d %.6f %.6f %.1f\n", loopcount, u2mm(x2), u2mm(y2), angle);
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_Line(int x1, int y1, int x2, int y2, int type, int first) { // output line to file in IDF format
+ int loopcount = 0;
+ if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19
+ if (first) printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1));
+ printf("%d %.6f %.6f 0\n", loopcount, u2mm(x2), u2mm(y2));
+ return;
+}
+
+////////////////////////////////////////////////////
+void OutputLines(int originx, int originy, int type) { // write to file
+ int first = 1;
+ int i = 0;
+ int startx = PointX1[i];
+ int starty = PointY1[i];
+ for(i = 0; i < NumSegments; i++) {
+ NumCutouts = LoopCounter;
+ switch(SegmentType[i]) {
+ case LINE : IDF_Line(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, type, first);
+ first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
+ // bis zum Ende sprich schliessen der Schleife
+ break;
+ case ARC : IDF_Arc(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, SegmentCurve[i], type, first);
+ first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
+ // bis zum Ende sprich schliessen der Schleife
+ break;
+ case CIRCLE : IDF_Circle(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, type);
+ LoopCounter++;
+ NumCutouts = LoopCounter;
+ startx = PointX1[i+1];
+ starty = PointY1[i+1];
+ first = 1;
+ break;
+ default : string s;
+ sprintf(s, "Unknown type in Segment %d", i);
+ if (dlgMessageBox(s, "OK", "esc") != 0) exit(-182);
+ }
+ if (startx == PointX2[i] && starty == PointY2[i]) {
+ first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben
+ startx = PointX1[i+1];
+ starty = PointY1[i+1];
+ LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben.
+ }
+ }
+ return;
+}
+
+////////////////////////////////////////////////////
+void OutputBoardOutLines(int originx, int originy, int type) { // write to file :: type ist hier irrelevant
+ int first = 1;
+ int i = 0;
+ int startx = PointX1[i];
+ int starty = PointY1[i];
+ for(i = 0; i < NumSegments; i++) {
+ NumCutouts = LoopCounter;
+ switch(SegmentType[i]) { // 2013-12-18
+ case LINE : IDF_Line(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, CUTOUT, first);
+ first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
+ // bis zum Ende sprich schliessen der Schleife
+ break;
+ case ARC : IDF_Arc(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, SegmentCurve[i], CUTOUT, first);
+ first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
+ // bis zum Ende sprich schliessen der Schleife
+ break;
+ case CIRCLE : IDF_Circle(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, CUTOUT);
+ LoopCounter++;
+ NumCutouts = LoopCounter;
+ startx = PointX1[i+1];
+ starty = PointY1[i+1];
+ first = 1;
+ break;
+ default : string s;
+ sprintf(s, "Unknown type in Segment %d", i);
+ }
+ if (startx == PointX2[i] && starty == PointY2[i]) {
+ first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben
+ startx = PointX1[i+1];
+ starty = PointY1[i+1];
+ LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben.
+ }
+ }
+ return;
+}
+
+void OutputBoardCutOutLines(int originx, int originy, int type) { // write to file :: type ist hier irrelevant
+ int first = 1;
+ int i = 0;
+ int startx = CutoutPointX1[i];
+ int starty = CutoutPointY1[i];
+ for(i = 0; i < CutoutNumSegments; i++) {
+ NumCutouts = LoopCounter;
+ switch(CutoutSegmentType[i]) { // 2013-12-18
+ case LINE : IDF_Line(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CUTOUT, first);
+ first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
+ // bis zum Ende sprich schliessen der Schleife
+ break;
+ case ARC : IDF_Arc(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CutoutSegmentCurve[i], CUTOUT, first);
+ first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2,
+ // bis zum Ende sprich schliessen der Schleife
+ break;
+ case CIRCLE : IDF_Circle(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CUTOUT);
+ LoopCounter++;
+ NumCutouts = LoopCounter;
+ startx = CutoutPointX1[i+1];
+ starty = CutoutPointY1[i+1];
+ first = 1;
+ break;
+ default : string s;
+ sprintf(s, "Unknown type in Segment %d", i);
+ }
+ if (startx == CutoutPointX2[i] && starty == CutoutPointY2[i]) {
+ first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben
+ startx = CutoutPointX1[i+1];
+ starty = CutoutPointY1[i+1];
+ LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben.
+ }
+ }
+ return;
+}
+
+////////////////////////////////////////////////////
+int IsPointEqual (int x1, int y1, int x2, int y2) { // really need a func-description ??
+ if(x1 == x2 && y1 == y2) return true;
+ return false;
+}
+
+////////////////////////////////////////////////////
+real getPartHeight() { // returns maximum partlevel
+ real ret = u2mm(SegmentWidth[0])*1000.0; // 2012-02-08
+ return ret;
+}
+
+////////////////////////////////////////////////////
+int IsPointInCircle(int target_x, int target_y, int circle_x, int circle_y, real radius) {
+ real dist,a,b;
+ a = abs(target_y-circle_y);
+ b = abs(target_x-circle_x);
+ // calculate distance
+ dist = sqrt(a*a + b*b);
+ if(dist <= radius) return true;
+ return false;
+}
+
+////////////////////////////////////////////////////
+//int GetArcOptions(UL_WIRE w) { // is arc drawn CW or CCW
+// if(IsPointEqual(w.x1, w.y1, w.x2, w.y2)) return (w.arc.angle1 - w.arc.angle2);
+// else return (w.arc.angle2 - w.arc.angle1);
+//}
+
+////////////////////////////////////////////////////
+int DataOnLayerPresent(UL_ELEMENT E, int layer) {
+ E.package.circles(CIR) { // circle found
+ if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) return true;
+ }
+ E.package.wires(W) {
+ if(W.arc) { // arc found
+ if(W.layer == layer && W.width > maxCutoutLineWidth) return true;
+ }
+ else { // straight line found
+ if(W.layer == layer && W.width > maxCutoutLineWidth) return true;
+ }
+ }
+ return false; // no 3d-data on given layer found
+}
+
+////////////////////////////////////////////////////
+void CollectRemainingPoints(int start, int nr) {
+ int i;
+ for(i = 0; i < nr; i++) {
+ PointX1[i] = PointX1[i+start];
+ PointY1[i] = PointY1[i+start];
+ PointX2[i] = PointX2[i+start];
+ PointY2[i] = PointY2[i+start];
+ SegmentType[i] = SegmentType[i+start];
+ SegmentCurve[i] = SegmentCurve[i+start];
+ SegmentWidth[i] = SegmentWidth[i+start];
+ }
+ NumSegments = nr;
+ return;
+}
+
+////////////////////////////////////////////////////
+int SortPointsEx (void) { // sort all points to a continous polygon
+ int i;
+ int ptfound;
+ int ResultPointX1[]; // start x
+ int ResultPointY1[]; // start y
+ int ResultPointX2[]; // end x
+ int ResultPointY2[]; // end y
+ int ResultSegmentType[]; // SegmentType
+ int ResultSegmentCurve[]; // options of segment (only used for ARCs)
+ int ResultSegmentWidth[]; // width of line
+ int PointUsed[];
+ enum { NOT_FOUND = 0, FOUND = 1, ERROR = 2 };
+ enum { NOT_USED = 0, USED = 1 };
+ for(i = 0; i < NumSegments; i++) PointUsed[i] = NOT_USED;
+
+ ResultPointX1[0] = PointX1[0]; // startpoint
+ ResultPointY1[0] = PointY1[0];
+ ResultPointX2[0] = PointX2[0];
+ ResultPointY2[0] = PointY2[0];
+ ResultSegmentType[0] = SegmentType[0];
+ ResultSegmentWidth[0] = SegmentWidth[0];
+ ResultSegmentCurve[0] = SegmentCurve[0];
+ PointUsed[0] = USED;
+
+ for(int x=1; x= (NumSegments-1)) {
+ if(ptfound != FOUND) ptfound = ERROR;
+ }
+ } while(ptfound == NOT_FOUND);
+ // if point was not found -> end sorting of points
+ if (ptfound == ERROR) break;
+ } // for NumSegments
+ // count how many points are not used
+ int n;
+ int NumPointsUsed = 0;
+ for(i=0; i < NumSegments; i++) {
+ if(PointUsed[i] == USED) NumPointsUsed++;
+ }
+ // copy not used points to end of ResultPoint[]
+ for(i = NumSegments-1; i >= NumPointsUsed; i--) {
+ for(n = 0; n < NumSegments; n++) {
+ if(PointUsed[n] == NOT_USED) { // copy if point is not used
+ PointUsed[n] = USED;
+ ResultPointX1[i] = PointX1[n];
+ ResultPointY1[i] = PointY1[n];
+ ResultPointX2[i] = PointX2[n];
+ ResultPointY2[i] = PointY2[n];
+ ResultSegmentCurve[i] = SegmentCurve[n];
+ ResultSegmentType[i] = SegmentType[n];
+ ResultSegmentWidth[i] = SegmentWidth[n];
+ break;
+ }
+ }
+ }
+ // copy back sorted list
+ for(i=0; i search for points within circle
+ if(IsPointInCircle(PointX1[i], PointY1[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08
+ PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
+ PointY1[NumSegments] = PointY2[LastPoint];
+ PointX2[NumSegments] = PointX1[i];
+ PointY2[NumSegments] = PointY1[i];
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
+ SegmentCurve[NumSegments++] = 0; // 2013-12-11
+ LineAdded = true;
+ break; // point within circle found and added -> escape from "for"-loop
+ }
+ if(IsPointInCircle(PointX2[i], PointY2[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08
+ PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
+ PointY1[NumSegments] = PointY2[LastPoint];
+ PointX2[NumSegments] = PointX2[i];
+ PointY2[NumSegments] = PointY2[i];
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
+ SegmentCurve[NumSegments++] = 0; // 2013-12-11
+ LineAdded = true;
+ break; // point within circle found and added -> escape from "for"-loop
+ }
+ }
+ }
+ } while(LineAdded); // resort points and close gaps if new line added
+ // finished correct -> but is polygon closed ?!? (firstpoint and lastpoint may no be the same coordinate !)
+ if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) { // poly closed ?
+ if(IsPointInCircle(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08
+ PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
+ PointY1[NumSegments] = PointY2[LastPoint];
+ PointX2[NumSegments] = PointX1[0];
+ PointY2[NumSegments] = PointY1[0];
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
+ SegmentCurve[NumSegments++] = 0; // 2013-12-11
+ }
+ }
+ return;
+}
+
+////////////////////////////////////////////////////
+int SortPoints(string ElementName) { // sort all points to a continous polygon
+ int LastPoint, RemainingPoints;
+ // close open polygon
+ if (CloseOpenPoly) CloseOpenPolygon();
+ // do final sorting
+ RemainingPoints = SortPointsEx();
+ // check if polygon is closed
+ LastPoint = NumSegments - RemainingPoints - 1;
+ if (LastPoint < 0) {
+ dlgMessageBox("!Negativ Index in function SortPoints().", "OK");
+ exit(-472);
+ }
+ if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) {
+ if(SegmentType[0] != CIRCLE) {
+ string x;
+ int pt_x, pt_y;
+ pt_x = PointX2[LastPoint];
+ pt_y = PointY2[LastPoint];
+ sprintf(x,"!%s contains an open polygon !\n\ncoordinate : X= %.6f[mm], Y= %.6f[mm]", ElementName, u2mm(pt_x), u2mm(pt_y));
+ if (dlgMessageBox(x, "OK", "Show") != 0) {
+ sprintf(x, "WIN (%.6fmm %.6fmm);\n", u2mm(pt_x), u2mm(pt_y));
+ exit(x);
+ }
+ }
+ }
+ return RemainingPoints;
+}
+
+////////////////////////////////////////////////////
+void IDF_LibaryHeader(UL_BOARD BRD) { //-> create header of libary
+ int t = time();
+ string date;
+ string sourceID;
+ sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t));
+ sprintf(sourceID, "Commend International >%s %s %s<", UlpName, UlpVersion, EAGLE_SIGNATURE); // 2013-01-14
+ printf(".HEADER\n");
+ printf("LIBRARY_FILE 3.0 \"%s\" %s 1\n", sourceID, date);
+ printf(".END_HEADER\n");
+ return;
+}
+
+////////////////////////////////////////////////////
+int CollectLibOutlineSegments(UL_ELEMENT E, int layer) { // get all segments of elements on 3D-layer
+ NumSegments=0;
+ E.package.circles(CIR) { // create circles
+ if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentCurve[NumSegments++] = 0; // 2013-12-11
+ }
+ }
+ E.package.wires(W) {
+ if(W.curve) { // create arcs
+ if(W.layer == layer && W.width > maxCutoutLineWidth) {
+ PointX1[NumSegments] = W.x1; // 2013-03-14 use wire coordinate, not arc!
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentCurve[NumSegments++] = W.curve; //GetArcOptions(W);
+ }
+ }
+ else { // create straight lines
+ if(W.layer == layer && W.width > maxCutoutLineWidth) {
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentCurve[NumSegments++] = 0; // 2013-12-11
+ }
+ }
+ }
+ if(NumSegments != 0) { // show warningbox if element contains no 3d-data
+ if(layer == bLayer3Ddata) { // is given layer the bottom layer -> mirror
+ for(int i=0; i create electrical parts (R, C, IC, ...)
+ int i,x,inlib,NrOfPolygon;
+ int RemainingPoints;
+ string MountSide[] = {"TOP", "BOTTOM"};
+ int layer[] = { tLayer3Ddata, bLayer3Ddata };
+
+ for(i=0;i subract given offsets -> E.x, E.y
+ printf(".END_ELECTRICAL\n");
+ CollectRemainingPoints(NumSegments, RemainingPoints);
+ PacIn_LIB_heights[NumPacInLib] = NrOfPolygon; // 0=package has only 1 poly; >0 package has more than one poly-outline
+ PacIn_LIB_name[NumPacInLib] = E.package.name; // mark that package is now in LIB-file
+ PacIn_LIB_Device_mountside[NumPacInLib] = E.mirror; // safe top- or bottom-side
+ PacIn_LIB_SubPart_mountside[NumPacInLib] = MountSide[tb]; // safe mountside of subparts
+ PacIn_LIB_angle[NumPacInLib++] = E.angle; // safe angle of partplacement
+ if(RemainingPoints != 0 || NrOfPolygon != 0) NrOfPolygon++;
+ } while(RemainingPoints != 0); // get multiple outline with multiple partheights
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_LibaryMechanical(UL_BOARD BRD) { //-> create mechanical parts (drills, holes, ...)
+ // not implemented yet
+ return;
+}
+
+////////////////////////////////////////////////////
+int CollectBoardOutlineSegments(UL_BOARD BRD) { //++ get all segments of boardoutline
+ NumSegments = 0;
+ // first search board outline in board direct
+ BRD.circles(CIR) {
+ if(CIR.layer == Layer3dBoardDimension) {
+ if (CIR.width > maxCutoutLineWidth) {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentCurve[NumSegments++] = 0;
+ }
+ else {
+ CutoutPointX1[CutoutNumSegments] = CIR.x;
+ CutoutPointY1[CutoutNumSegments] = CIR.y;
+ CutoutPointX2[CutoutNumSegments] = CIR.x + CIR.radius;
+ CutoutPointY2[CutoutNumSegments] = CIR.y;
+ CutoutSegmentType[CutoutNumSegments] = CIRCLE;
+ CutoutSegmentWidth[CutoutNumSegments] = CIR.width;
+ CutoutSegmentCurve[CutoutNumSegments++] = 0;
+ }
+ }
+ }
+ BRD.wires(W) {
+ if(W.layer == Layer3dBoardDimension) {
+ if (W.width > maxCutoutLineWidth) {
+ if(W.curve) { // create arcs board-outline board
+ PointX1[NumSegments] = W.x1; // 2013-03-14 use direct wire coordinate, not arc-coordinate
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentCurve[NumSegments] = W.curve; // GetArcOptions(W);
+ }
+ else { // create straight lines board-outline board
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentCurve[NumSegments] = 0;
+ }
+ NumSegments++;
+ }
+ else {
+ if(W.curve) { // create arcs board-outline board
+ CutoutPointX1[CutoutNumSegments] = W.x1;
+ CutoutPointY1[CutoutNumSegments] = W.y1;
+ CutoutPointX2[CutoutNumSegments] = W.x2;
+ CutoutPointY2[CutoutNumSegments] = W.y2;
+ CutoutSegmentType[CutoutNumSegments] = ARC;
+ CutoutSegmentWidth[CutoutNumSegments] = W.width;
+ CutoutSegmentCurve[CutoutNumSegments] = W.curve; //GetArcOptions(W);
+ }
+ else {
+ CutoutPointX1[CutoutNumSegments] = W.x1;
+ CutoutPointY1[CutoutNumSegments] = W.y1;
+ CutoutPointX2[CutoutNumSegments] = W.x2;
+ CutoutPointY2[CutoutNumSegments] = W.y2;
+ CutoutSegmentType[CutoutNumSegments] = LINE;
+ CutoutSegmentWidth[CutoutNumSegments] = W.width;
+ CutoutSegmentCurve[CutoutNumSegments] = 0;
+ }
+ CutoutNumSegments++;
+ }
+ }
+ }
+ // second search board outline in packages
+ BRD.elements(E) {
+ E.package.circles(CIR) { // create board-outline of package-libary
+ if(CIR.layer == Layer3dBoardDimension) {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentCurve[NumSegments++] = 0;
+ }
+ }
+ }
+ BRD.elements(E) {
+ E.package.wires(W) {
+ if(W.layer == Layer3dBoardDimension) {
+ if (W.width > maxCutoutLineWidth) {
+ if(W.curve) { // create arcs board-outline of package-libary
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentCurve[NumSegments] = W.curve; // GetArcOptions(W);
+ }
+ else { // create straight lines board-outline of package-libary
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentCurve[NumSegments] = 0;
+ }
+ NumSegments++;
+ }
+ else {
+ if(W.curve) { // create arcs board-cutout of package-libary
+ CutoutPointX1[CutoutNumSegments] = W.x1;
+ CutoutPointY1[CutoutNumSegments] = W.y1;
+ CutoutPointX2[CutoutNumSegments] = W.x2;
+ CutoutPointY2[CutoutNumSegments] = W.y2;
+ CutoutSegmentType[CutoutNumSegments] = ARC;
+ CutoutSegmentWidth[CutoutNumSegments] = W.width;
+ CutoutSegmentCurve[CutoutNumSegments] = W.curve; //GetArcOptions(W);
+ }
+ else { // create line board-cutout of package-libary
+ CutoutPointX1[CutoutNumSegments] = W.x1;
+ CutoutPointY1[CutoutNumSegments] = W.y1;
+ CutoutPointX2[CutoutNumSegments] = W.x2;
+ CutoutPointY2[CutoutNumSegments] = W.y2;
+ CutoutSegmentType[CutoutNumSegments] = LINE;
+ CutoutSegmentWidth[CutoutNumSegments] = W.width;
+ CutoutSegmentCurve[CutoutNumSegments] = 0;
+ }
+ CutoutNumSegments++;
+ }
+ }
+ }
+ }
+
+ if(NumSegments == 0) {
+ string error;
+ sprintf(error,"!No board-outline on layer %d found !", Layer3dBoardDimension);
+ dlgMessageBox(error);
+ exit(-771);
+ }
+ return NumSegments;
+}
+
+
+////////////////////////////////////////////////////
+void IDF_BoardHeader(UL_BOARD BRD) { //-## create header of boardfile
+ int t = time();
+ string date;
+ string sourceID;
+
+ sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t));
+ sprintf(sourceID, "Commend International >%s %s %s<", UlpName, UlpVersion, EAGLE_SIGNATURE);
+ printf(".HEADER\n");
+ printf("BOARD_FILE 3.0 \"%s\" %s 1\n", sourceID, date);
+ printf("\"%s\" MM\n", filename(BRD.name));
+ printf(".END_HEADER\n");
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_BoardOutline(UL_BOARD BRD) { //-## create outline of board
+ // get outline
+ CollectBoardOutlineSegments(BRD);
+ SortPoints("Board-Outline"); // boardname
+ // draw outline
+ printf(".BOARD_OUTLINE UNOWNED\n");
+ printf("%.6f\n", getPartHeight());
+ OutputBoardOutLines(0, 0, OUTLINE); // subract given offsets -> E.x, E.y
+ OutputBoardCutOutLines(0, 0, OUTLINE);
+ printf(".END_BOARD_OUTLINE\n");
+ LoopCounter = 0;
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_BoardPlaceParts(UL_BOARD BRD) { //-## mount parts on board
+ int i, inlib;
+ string MountSide[] = {"TOP","BOTTOM"};
+ printf(".PLACEMENT\n");
+ BRD.elements(E) {
+ inlib = 0;
+ for(i=0; i more than one part on same x/y position
+ int lib_start = i;
+ do {
+ printf("%s_ANGLE%.1f_%s.%d CI_LIB %s.%d\n", E.package.name, E.angle, PacIn_LIB_SubPart_mountside[lib_start], PacIn_LIB_heights[lib_start], E.name, PacIn_LIB_heights[lib_start]);
+ printf("%.6f %.6f 0 0 %s PLACED\n", u2mm(E.x), u2mm(E.y), PacIn_LIB_SubPart_mountside[lib_start]);
+ lib_start++;
+ }while(PacIn_LIB_heights[lib_start] > 1);
+ }
+ }
+ }
+ printf(".END_PLACEMENT\n");
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_BoardHoles(UL_BOARD BRD) { //-## create holes in board (cutout, partholes, ...)
+ printf(".DRILLED_HOLES\n");
+ // drill holes from board direct
+ BRD.holes(H)
+ printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y));
+ // drill holes from elements
+ BRD.elements(E) {
+ E.package.holes(H)
+ printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y));
+ }
+ // drill pad(holes) from elements 2014-01-20
+ BRD.elements(E) {
+ E.package.contacts(C)
+ if (C.pad)
+ if (u2mm(C.pad.drill) > MinViaHoleDia)
+ printf("%.6f %.6f %.2f PTH BOARD Other UNOWNED\n", u2mm(C.pad.drill), u2mm(C.pad.x), u2mm(C.pad.y));
+ }
+ // drill big via's
+ BRD.signals(S) {
+ S.vias(V) {
+ if((DrillViaHoles == true) && (u2mm(V.drill) > MinViaHoleDia)) // drill via-hole
+ printf("%.6f %.6f %.6f PTH BOARD VIA UNOWNED\n", u2mm(V.drill), u2mm(V.x), u2mm(V.y));
+ }
+ }
+ printf(".END_DRILLED_HOLES\n");
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_CreateLibaryFile(UL_BOARD BRD, string fname) { // create libary for the IDF-board
+ output(fname, "wt") {
+ IDF_LibaryHeader(BRD);
+ IDF_LibaryElectrical(BRD);
+ IDF_LibaryMechanical(BRD);
+ }
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_CreateBoardFile(UL_BOARD BRD, string fname) { // create boardfile with parts of libary
+ output(fname, "wt") {
+ IDF_BoardHeader(BRD);
+ IDF_BoardOutline(BRD);
+ IDF_BoardHoles(BRD);
+ IDF_BoardPlaceParts(BRD);
+ }
+ return;
+}
+
+
+////////////////////////////////////////////////////
+void DisplayHelp(void) { // show helptext
+ dlgDialog("Generate 3D IDF data") {
+ dlgLabel("Version " + UlpVersion);
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(200);
+ dlgTextView(usage);
+ }
+ dlgLabel(Docuemantpath);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("-Back") dlgReject();
+ }
+ };
+ return;
+}
+
+////////////////////////////////////////////////////
+// S T A R T of U L P
+//
+if (board) {
+ int proceed = 0;
+ string FileDirectoryName;
+ string FilenamePanel;
+ string FileNameIDB; // Board
+ string FileNameIDL; // Library
+ board(BRD) {
+ FileDirectoryName = filedir(BRD.name);
+ FileNameIDB = filesetext(filename(BRD.name), ".IDB");
+ FileNameIDL = filesetext(filename(BRD.name), ".IDL");
+ }
+ dlgDialog("Generate 3D data format (IDF-file)") {
+ dlgHBoxLayout {
+ dlgGroup(" settings ") {
+ dlgGridLayout {
+ dlgCell(0,0) dlgCheckBox("close polygon if gap is smaller than : ", CloseOpenPoly);
+ dlgCell(0,1) dlgRealEdit(MaxGapWidth);
+ dlgCell(0,2) dlgLabel(" mm");
+
+ dlgCell(1,0) dlgCheckBox("drill via-holes if via is bigger than : ", DrillViaHoles);
+ dlgCell(1,1) dlgRealEdit(MinViaHoleDia);
+ dlgCell(1,2) dlgLabel(" mm");
+
+ dlgCell(2,0) dlgCheckBox("Export top parts", SelectSide[0]);
+ dlgCell(3,0) dlgCheckBox("Export bottom parts", SelectSide[1]);
+ }
+ }
+ }
+ dlgGridLayout {
+ dlgCell(1,0) dlgLabel("Output Directory:");
+ dlgCell(1,1) dlgLabel(FileDirectoryName, 1);
+ dlgCell(1,2) {
+ dlgPushButton("Browse") {
+ string fdn = dlgDirectory("Save IDF file", FileDirectoryName);
+ if (fdn) {
+ int len = strlen(fdn);
+ if (fdn[len] != '/') fdn+="/"; // dlgDirectory gibt den Pfad ohne abschliessenden Slash zurück!
+ FileDirectoryName = fdn;
+ }
+ }
+ }
+ dlgCell(2,0) dlgLabel("Filename IDB (Board)");
+ dlgCell(2,1) dlgStringEdit(FileNameIDB);
+ dlgCell(2,2) {
+ dlgPushButton("Browse") {
+ string fdb = dlgFileSave("Save IDF file", FileDirectoryName, "IDF files (*.IDB)");
+ if (fdb) {
+ FileNameIDB = filename(fdb);
+ if(strchr(FileNameIDB, '.') < 0) // add fileextension if missing
+ FileNameIDB += ".IDB";
+ FileNameIDL = filesetext(FileNameIDB, ".IDL");
+ }
+ }
+ }
+ dlgCell(3,0) dlgLabel("Filename IDL (Library)");
+ dlgCell(3,1) dlgStringEdit(FileNameIDL);
+ dlgCell(3,2) {
+ dlgPushButton("Browse") {
+ string fdl = dlgFileSave("Save IDF file", FileDirectoryName, "IDF files (*.IDL)");
+ if (fdl) {
+ FileNameIDL = filename(fdl);
+ if(strchr(FileNameIDL, '.') < 0) // add fileextension if missing
+ FileNameIDL += ".IDL";
+ FileNameIDB = filesetext(FileNameIDL, ".IDB");
+ }
+ }
+ }
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") { proceed = 1; dlgAccept(); }
+ dlgPushButton("Cancel") dlgReject();
+ dlgStretch(1);
+ dlgLabel("Version: " + UlpVersion);
+ dlgPushButton("Help") DisplayHelp();
+ }
+ };
+ if(proceed) {
+ project.board(BRD) {
+ CollectPartData(BRD); // read out data from BRD
+ IDF_CreateLibaryFile(BRD, FileNameIDL);
+ IDF_CreateBoardFile(BRD, FileNameIDB);
+ }
+ }
+}
+else {
+ dlgMessageBox(usage + "ERROR: No board!
\nThis program can only work in the layout editor.");
+ exit(0);
+}
\ No newline at end of file
diff --git a/trunk/ulp/generate-dummy-package-and-connect.ulp b/trunk/ulp/generate-dummy-package-and-connect.ulp
new file mode 100644
index 00000000..5f39e90c
--- /dev/null
+++ b/trunk/ulp/generate-dummy-package-and-connect.ulp
@@ -0,0 +1,129 @@
+#usage "en:Generates a Dummy Package for the currently displayed Device in the Library Editor \n"
+ "
"
+ "For electro devices it has proved to be useful to use the same names for symbol pins and "
+ "package pads. This program generates a package that has identical pad/pin names."
+ "
"
+ "Start the ULP in the library editor window, after having created a device and "
+ "used the ADD command to add the symbol(s). A package will be created which has "
+ "the same name as the device and the pad names are identical with the pin names. "
+ "Connect pins und pads with the Connect command.
"
+ "Author: alf@cadsoft.de"
+ ,
+ "de:Generiert ein Dummy-Package für das aktuell angezeigte Device im Bibliothekseditor\n"
+ "
"
+ "Für Elektro-Bauteile empfiehlt es sich, dass Symbol-Pins und Package-Pads gleiche "
+ "Namen haben. Dieses Programm erzeugt ein Package mit identischen Pad-/Pin-Namen."
+ "
"
+ "Starten Sie das Programm im Bibliothekseditor, sobald Sie ein Device angelegt "
+ "und die Symbole mit dem Add-Befehl geholt haben. Es wird ein Package angelegt, "
+ "dessen Name dem des Device entspricht (falls noch nicht vorhanden) und dessen "
+ "Pads entsprechend den Pins benannt sind. Pins und Pads sind mit dem Connect-Befehl "
+ "verbunden.
"
+ "Author: alf@cadsoft.de"
+
+string Version = "1.0.2"; // 2012-03-23 Behandlung der Apostrophen in Pin/Pad-Namen berichtig.
+ // 2013-01-25 Bei nur einem Gate den Gate-Namen nicht benutzen um die Pad-Namen zu erzeugen
+string cmd, concmd, s;
+string f;
+string PadName;
+string CurrentDevice;
+int PackagePresent = 0;
+int PADname;
+
+int test = 0;
+
+// Da der ganze String in ' eingeschlossen wird,
+// müssen die Apostrophen verdoppelt werden.
+string addApostroph(string name) { // 2012-03-23
+ string t[];
+ int cnt = strsplit(t, name, '\''); // check Apostroph
+ if (cnt > 1) {
+ name = "";
+ for (int i = 0; i < cnt; i++) {
+ if (i == 0) {
+ if (t[i]) name += t[i];
+ }
+ else if (i) name += "''" + t[i];
+ }
+ }
+ return name;
+}
+
+if (deviceset) {
+ library(L) {
+ f = filename(L.name);
+ f = filesetext(f, "$$$.scr");
+ f = path_scr[0] + '/' + f; // verwende Script-Pfad
+ deviceset(DS) {
+ CurrentDevice = DS.name;
+ DS.devices(D) {
+ if (!D.package && CurrentDevice == DS.name) {
+ sprintf(s, "EDIT %s.PAC;\n", DS.name);
+ cmd += s;
+ sprintf(s, "DESCRIPTION 'Dummy';\n");
+ cmd += s;
+ sprintf(s, "GRID MM; CHANGE DRILL 0.5; CHANGE DIAMETER 1.0;\n");
+ cmd += s;
+ sprintf(s, "EDIT %s.DEV;\n", DS.name);
+ concmd += s;
+ sprintf(s, "PAC '%s' '';\n", DS.name);
+ concmd += s;
+ int cntg = 0;
+ DS.gates(G) {
+ cntg++;
+ }
+ DS.gates(G) {
+ string gname = addApostroph(G.name);
+ if (cntg == 1) gname = ""; // 2013-01-25 bei nur einem Gate, nur den Pin-Namen beutzen.
+ G.symbol.pins(P) {
+ PadName = (P.name);
+ sprintf(s, "PAD '%s%s' (%.4f %.4f);\n",
+ gname, addApostroph(PadName),
+ u2mm(P.x),
+ u2mm(P.y)-7.62
+ ); // Pin-Offset im Device in Y-Richtung
+ cmd += s;
+ sprintf(s, "CONNECT '%s.%s' '%s%s';\n",
+ addApostroph(G.name),
+ addApostroph(P.name),
+ gname,
+ addApostroph(PadName)
+ );
+ concmd += s;
+ }
+ }
+ }
+ }
+ }
+ L.packages(P) {
+ if (CurrentDevice == P.name) PackagePresent = 1;
+ }
+ }
+ cmd += concmd;
+ if (cmd && !PackagePresent) {
+ if (test) {
+ dlgDialog("Check") {
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(500);
+ dlgTextEdit(cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("Cancel") { dlgReject(); exit(-1); }
+ }
+ };
+ }
+ output(f, "wtD") printf("%s", cmd); // temporäre Script-Datei erzeugen
+ exit("SCRIPT '"+ f +"'");
+ }
+ else {
+ if (language() == "de") dlgMessageBox("Das Device besitzt schon ein Package, bzw. es existiert schon ein Package mit entsprechenden Namen.", "OK");
+ else dlgMessageBox("There is already a package defined for this device/package with this name already exists.", "OK");
+ }
+}
+
+else {
+ if (language() == "de") dlgMessageBox("Das ULP kann nur im Device-Editor (Bibliothek) benutzt werden!", "OK");
+ else dlgMessageBox("This ULP can be used in the Device Editor (Library) only!", "OK");
+}
diff --git a/trunk/ulp/generate_3d_data_v10.ulp b/trunk/ulp/generate_3d_data_v10.ulp
new file mode 100644
index 00000000..814873cc
--- /dev/null
+++ b/trunk/ulp/generate_3d_data_v10.ulp
@@ -0,0 +1,1206 @@
+#usage "export 3d-data from board to IDF-FileFormat V3.0\n"
+ "
"
+ "Author: Neubacher Andy "
+ "co-Author: alf@cadsoft.de"
+
+#require 6.0300
+
+//############################################################################
+// Author: Andy Neubacher
+// Version | Date | log
+//---------+------------+-----------------------------------------------------
+// v1.0 | 2012-08-20 | - more resolution %.6f of coordinates
+// | | alf@cadsoft.de
+// v0.9 | 2012-02-08 | - used function u2mm() for Z-axis value
+// | | - fixes by alf@cadsoft.de
+// v0.8 | 2011-05-31 | - changed characters that caused import problems
+// | | - changed output file extension to .emn and .emp
+// | | - fixes by morten@riftlabs.com
+// | |
+// v0.7 | 2006-10-24 | - outline of board can also be drawn direct in brd-file
+// | | - any hole is taken from devices and board direct
+// | | - close open polygons on request
+// | | - drill vias on request
+// | | - bugfix : error if device contains more than one poly on top and bottom
+// | | - bugfix : sorting of points possible failed if polygon was open
+// | | - bugfix : partheights on bottomlayer were ignored
+// v0.6 | 2006-08-31 | now multiple partheights are possible
+// v0.5 | 2006-08-25 | modification to 'RIR-standard'
+// v0.4 | 2005-11-09 | 1st export of a real board+parts successfull
+// v0.3 | 2005-11-03 | correct mirrors at top and bottom side
+// v0.2 | 2005-10-21 | 1st working IDF-data
+// v0.1 | 2005-09-30 | start of project
+//---------+------------+-----------------------------------------------------
+//
+// HOWTO:
+// Create your board outline on layer 50.
+// In your library, draw the component outlines on layer 57 (tCad) and use the line thickness to set component height.
+// 1000 mic = 1 mm (e.g. if your grid is in mm, then a line thickness of 0.001 equals a component height of 1 mm).
+// More info can be found here: ftp://ftp.cadsoft.de/eagle/userfiles/ulp/generate_3d_data_eng.pdf
+//
+//############################################################################
+
+
+int Layer3dBoardDimension = 50;
+int tLayer3Ddata = 57;
+int bLayer3Ddata = 58;
+int maxCutoutLineWidth = 0; // -->> is linewidth 0.0 -> line is a cutout
+
+
+string HelpText = "1)
3D use u2mm()
\n";
+
+string UlpName;
+string UlpVersion = "V0.9";
+
+
+
+
+
+// partoptions
+int NumParts; // number of parts
+string PartName[]; // name of part
+
+
+// vars for polygon calculation
+int NumSegments = 0; // number of points
+int PointX1[]; // start x
+int PointY1[]; // start y
+int PointX2[]; // end x
+int PointY2[]; // end y
+int SegmentType[]; // ARC, LINE, CIRCLE
+int SegmentOptions[]; // used by ARCs : -180 if drawn CCW, +180 if drawn CW
+int SegmentWidth[]; // linewitdh = partheight
+enum { LINE = 0, ARC = 1, CIRCLE = 2 };
+enum { CUTOUT = 0, OUTLINE = -1 };
+enum { false = 0, true = 1};
+
+
+// vars for library
+int NumPacInLib = 0; // number of pacs in library
+int PacIn_LIB_heights[]; // if 0 = only one partheight, if != 0 more than one height
+real PacIn_LIB_angle[]; // rotation of part in board
+string PacIn_LIB_name[]; // names of pack's in library
+int PacIn_LIB_Device_mountside[]; // TOP, BOTTOM
+string PacIn_LIB_SubPart_mountside[]; // mountside of subparts
+
+
+int NumCutouts = 0; // number of holes in the pcb (drills, millings)
+int OutlineInDeviceFound = false; // is outline drawn in device symbol
+
+int CloseOpenPoly = false; // close polygon if gap is smaller than ...mm
+real MaxGapWidth = 0.1; // value of maximum gap to close
+
+int DrillViaHoles = true; // drill via-holes in pcb
+real MinViaHoleDia = 1; // diameter of drill
+
+
+
+
+
+
+
+
+////////////////////////////////////////////////////
+void GetUlpName(void) // reads out the own ULP-name
+{
+ string s = strsub(argv[0], 0, strlen(argv[0])-4);
+ char c = '/';
+ int pos = strrchr(s, c);
+
+ if (pos >= 0)
+ UlpName = strsub(s, pos + 1);
+}
+
+
+
+////////////////////////////////////////////////////
+void CollectPartData(UL_BOARD brd) // read out all parts
+{
+ NumParts = 0;
+
+ brd.elements(E)
+ {
+ PartName[NumParts] = E.name;
+ PacIn_LIB_angle[NumParts] = -1; // fill with invalid rotation and ...
+ PacIn_LIB_Device_mountside[NumParts] = -1; // fill with invalid mountside (mirror) for "void IDF_LibaryElectrical(UL_BOARD BRD)" function
+ PacIn_LIB_heights[NumParts] = 0; // part is only one package
+
+ NumParts++;
+ }
+}
+
+
+
+
+
+
+
+////////////////////////////////////////////////////
+void IDF_Circle(int x1, int y1, int x2, int y2, int type) // output circle to file in IDF format
+{
+ int x=0;
+
+ if(type == CUTOUT)
+ x = NumCutouts;
+
+ printf("%d %.6f %.6f 0\n", x, u2mm(x1), u2mm(y1));
+ printf("%d %.6f %.6f 360\n", x, u2mm(x2), u2mm(y2));
+}
+
+////////////////////////////////////////////////////
+void IDF_Arc(int x1, int y1, int x2, int y2, int angle, int type) // output arc to file in IDF format
+{
+ int x=0;
+
+ if(type == CUTOUT)
+ x = NumCutouts;
+
+ printf("%d %.6f %.6f 0\n", x, u2mm(x1), u2mm(y1));
+ printf("%d %.6f %.6f %d\n", x, u2mm(x2), u2mm(y2), angle);
+}
+
+////////////////////////////////////////////////////
+void IDF_Line(int x1, int y1, int x2, int y2, int type) // output line to file in IDF format
+{
+ int x=0;
+
+ if(type == CUTOUT)
+ x = NumCutouts;
+
+ printf("%d %.6f %.6f 0\n", x, u2mm(x1), u2mm(y1));
+ printf("%d %.6f %.6f 0\n", x, u2mm(x2), u2mm(y2));
+}
+
+////////////////////////////////////////////////////
+void OutputLines(int originx, int originy, int type) // write to file
+{
+ for(int i=0; i maxCutoutLineWidth)
+ return true;
+ }
+ E.package.wires(W)
+ {
+ if(W.arc) // arc found
+ {
+ if(W.arc.layer == layer && W.arc.width > maxCutoutLineWidth)
+ return true;
+ }
+ else // straight line found
+ {
+ if(W.layer == layer && W.width > maxCutoutLineWidth)
+ return true;
+ }
+ }
+ return false; // no 3d-data on given layer found
+}
+
+////////////////////////////////////////////////////
+void CollectRemainingPoints(int start, int nr)
+{
+ int i;
+
+ for(i=0; i= (NumSegments-1))
+ {
+ if(ptfound != FOUND)
+ ptfound = ERROR;
+ }
+
+ } while(ptfound == NOT_FOUND);
+
+
+ // if point was not found -> end sorting of points
+ if (ptfound == ERROR)
+ break;
+
+ } // for NumSegments
+
+
+
+ // count how many points are not used
+ int n;
+ int NumPointsUsed = 0;
+ for(i=0; i=NumPointsUsed; i--)
+ {
+ for(n=0; n search for points within circle
+ {
+ if(IsPointInCircle(PointX1[i], PointY1[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth)))
+ {
+ PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
+ PointY1[NumSegments] = PointY2[LastPoint];
+ PointX2[NumSegments] = PointX1[i];
+ PointY2[NumSegments] = PointY1[i];
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
+ SegmentOptions[++NumSegments] = 0;
+
+ LineAdded = true;
+ break; // point within circle found and added -> escape from "for"-loop
+ }
+ if(IsPointInCircle(PointX2[i], PointY2[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth)))
+ {
+ PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
+ PointY1[NumSegments] = PointY2[LastPoint];
+ PointX2[NumSegments] = PointX2[i];
+ PointY2[NumSegments] = PointY2[i];
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
+ SegmentOptions[++NumSegments] = 0;
+
+ LineAdded = true;
+ break; // point within circle found and added -> escape from "for"-loop
+ }
+ }
+ }
+ } while(LineAdded); // resort points and close gaps if new line added
+
+
+
+ // finished correct -> but is polygon closed ?!? (firstpoint and lastpoint may no be the same coordinate !)
+ if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) // poly closed ?
+ {
+ if(IsPointInCircle(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth)))
+ {
+ PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point
+ PointY1[NumSegments] = PointY2[LastPoint];
+ PointX2[NumSegments] = PointX1[0];
+ PointY2[NumSegments] = PointY1[0];
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = SegmentWidth[LastPoint];
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////
+int SortPoints(string ElementName) // sort all points to a continous polygon
+{
+ int LastPoint, RemainingPoints;
+
+ // close open polygon
+ if(CloseOpenPoly)
+ CloseOpenPolygon();
+
+ // do final sorting
+ RemainingPoints = SortPointsEx();
+
+ // check if polygon is closed
+ LastPoint = NumSegments - RemainingPoints - 1;
+ if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false)
+ {
+ if(SegmentType[0] != CIRCLE)
+ {
+ string x;
+ int pt_x, pt_y;
+
+ pt_x = PointX2[LastPoint];
+ pt_y = PointY2[LastPoint];
+ sprintf(x,"!%s contains an open polygon !\n\ncoordinate : X= %.6f[mm], Y= %.6f[mm]", ElementName, u2mm(pt_x), u2mm(pt_y));
+ if (dlgMessageBox(x, "OK", "Show") != 0) {
+ sprintf(x, "WIN (%.6fmm %.6fmm);\n", u2mm(pt_x), u2mm(pt_y));
+ exit(x);
+ }
+ }
+ }
+
+ return RemainingPoints;
+}
+
+
+
+////////////////////////////////////////////////////
+void IDF_LibaryHeader(UL_BOARD BRD) //-> create header of libary
+{
+ int t = time();
+ string date;
+ string sourceID;
+
+ sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t));
+ sprintf(sourceID, "Commend International >%s.ulp %s<", UlpName, UlpVersion);
+
+ printf(".HEADER\n");
+ printf("LIBRARY_FILE 3.0 \"%s\" %s 1\n", sourceID, date);
+ printf(".END_HEADER\n");
+ return;
+}
+
+
+////////////////////////////////////////////////////
+int CollectLibOutlineSegments (UL_ELEMENT E, int layer) // get all segments of elements on 3D-layer
+{
+ NumSegments=0;
+
+
+ E.package.circles(CIR) // create circles
+ {
+ if(CIR.layer == layer && CIR.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+
+ E.package.wires(W)
+ {
+ if(W.arc) // create arcs
+ {
+ if(W.arc.layer == layer && W.arc.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = W.arc.x1;
+ PointY1[NumSegments] = W.arc.y1;
+ PointX2[NumSegments] = W.arc.x2;
+ PointY2[NumSegments] = W.arc.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.arc.width;
+ SegmentOptions[++NumSegments] = GetArcOptions(W);
+ }
+ }
+ else // create straight lines
+ {
+ if(W.layer == layer && W.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ }
+
+
+ if(NumSegments != 0) // show warningbox if element contains no 3d-data
+ {
+ if(layer == bLayer3Ddata) // is given layer the bottom layer -> mirror
+ {
+ for(int i=0; i create electrical parts (R, C, IC, ...)
+{
+ int i,x,inlib,NrOfPolygon;
+ int RemainingPoints;
+ string MountSide[] = {"TOP","BOTTOM"};
+ int layer[] = {tLayer3Ddata, bLayer3Ddata};
+
+
+ for(i=0;i subract given offsets -> E.x, E.y
+ printf(".END_ELECTRICAL\n");
+
+ CollectRemainingPoints(NumSegments, RemainingPoints);
+
+ PacIn_LIB_heights[NumPacInLib] = NrOfPolygon; // 0=package has only 1 poly; >0 package has more than one poly-outline
+ PacIn_LIB_name[NumPacInLib] = E.package.name; // mark that package is now in LIB-file
+ PacIn_LIB_Device_mountside[NumPacInLib] = E.mirror; // safe top- or bottom-side
+ PacIn_LIB_SubPart_mountside[NumPacInLib] = MountSide[b]; // safe mountside of subparts
+ PacIn_LIB_angle[NumPacInLib++] = E.angle; // safe angle of partplacement
+
+ if(RemainingPoints != 0 || NrOfPolygon != 0)
+ NrOfPolygon++;
+
+ }while(RemainingPoints != 0); // get multiple outline with multiple partheights
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+
+
+////////////////////////////////////////////////////
+void IDF_LibaryMechanical(UL_BOARD BRD) //-> create mechanical parts (drills, holes, ...)
+{
+ // not implemented yet
+ return;
+}
+
+
+
+
+
+
+////////////////////////////////////////////////////
+int CollectBoardOutlineSegments(UL_BOARD BRD) //++ get all segments of boardoutline
+{
+ NumSegments=0;
+
+ BRD.elements(E)
+ {
+ E.package.circles(CIR) // create board-outline of package-libary
+ {
+ if(CIR.layer == Layer3dBoardDimension && CIR.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ }
+ BRD.elements(E)
+ {
+ E.package.wires(W)
+ {
+ if(W.arc) // create arcs direct from board
+ {
+ if(W.arc.layer == Layer3dBoardDimension && W.arc.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = W.arc.x1;
+ PointY1[NumSegments] = W.arc.y1;
+ PointX2[NumSegments] = W.arc.x2;
+ PointY2[NumSegments] = W.arc.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.arc.width;
+ SegmentOptions[++NumSegments] = GetArcOptions(W);
+ }
+ }
+ else // create straight lines direct from board
+ {
+ if(W.layer == Layer3dBoardDimension && W.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ }
+ }
+
+ if(NumSegments != 0)
+ {
+ OutlineInDeviceFound = true;
+ return NumSegments; // outline was found in a device -> return
+ }
+
+
+
+ // outline of board was not found in any device -> check if drawn in boardfile direct
+ BRD.circles(CIR) // create board-outline of package-libary
+ {
+ if(CIR.layer == Layer3dBoardDimension && CIR.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ BRD.wires(W)
+ {
+ if(W.arc) // create arcs direct from board
+ {
+ if(W.arc.layer == Layer3dBoardDimension && W.arc.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = W.arc.x1;
+ PointY1[NumSegments] = W.arc.y1;
+ PointX2[NumSegments] = W.arc.x2;
+ PointY2[NumSegments] = W.arc.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.arc.width;
+ SegmentOptions[++NumSegments] = GetArcOptions(W);
+ }
+ }
+ else // create straight lines direct from board
+ {
+ if(W.layer == Layer3dBoardDimension && W.width > maxCutoutLineWidth)
+ {
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ }
+
+
+ if(NumSegments == 0)
+ {
+ string x;
+ sprintf(x,"!no board-outline on layer %d found !", Layer3dBoardDimension);
+ dlgMessageBox(x);
+ }
+
+ return NumSegments;
+}
+
+
+
+////////////////////////////////////////////////////
+int CollectBoardCutoutSegments(UL_ELEMENT E, int layer, int type)
+{
+ NumSegments=0;
+
+
+ if(type == CIRCLE)
+ {
+ E.package.circles(CIR) // create circles direct from board
+ {
+ if(CIR.layer == layer && CIR.width < (maxCutoutLineWidth+1))
+ {
+ PointX1[NumSegments] = CIR.x;
+ PointY1[NumSegments] = CIR.y;
+ PointX2[NumSegments] = CIR.x + CIR.radius;
+ PointY2[NumSegments] = CIR.y;
+ SegmentType[NumSegments] = CIRCLE;
+ SegmentWidth[NumSegments] = CIR.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ }
+ else
+ {
+ E.package.wires(W)
+ {
+ if(W.arc) // create arcs direct from board
+ {
+ if(W.arc.layer == layer && W.arc.width < (maxCutoutLineWidth+1))
+ {
+ PointX1[NumSegments] = W.arc.x1;
+ PointY1[NumSegments] = W.arc.y1;
+ PointX2[NumSegments] = W.arc.x2;
+ PointY2[NumSegments] = W.arc.y2;
+ SegmentType[NumSegments] = ARC;
+ SegmentWidth[NumSegments] = W.arc.width;
+ SegmentOptions[++NumSegments] = GetArcOptions(W);
+ }
+ }
+ else // create straight lines direct from board
+ {
+ if(W.layer == layer && W.width < (maxCutoutLineWidth+1))
+ {
+ PointX1[NumSegments] = W.x1;
+ PointY1[NumSegments] = W.y1;
+ PointX2[NumSegments] = W.x2;
+ PointY2[NumSegments] = W.y2;
+ SegmentType[NumSegments] = LINE;
+ SegmentWidth[NumSegments] = W.width;
+ SegmentOptions[++NumSegments] = 0;
+ }
+ }
+ }
+ }
+
+ return NumSegments;
+}
+
+
+////////////////////////////////////////////////////
+void DoCutoutsFromElements(UL_BOARD BRD)
+{
+ int ret, RemainingPoints;
+
+ // get cutouts from elements (holes, ...)
+ BRD.elements(E)
+ {
+ // get cutout segments (LINEs and ARCs)
+ ret = CollectBoardCutoutSegments(E, Layer3dBoardDimension, LINE);
+ if(ret)
+ {
+ do
+ {
+ NumCutouts++; // increment board cutouts
+ RemainingPoints = SortPoints(E.name); // elementname
+ NumSegments -= RemainingPoints; // calculate nr of correct points of poly
+ OutputLines(0, 0, CUTOUT); // subract given offsets -> E.x, E.y
+
+ if(RemainingPoints)
+ CollectRemainingPoints(NumSegments, RemainingPoints);
+
+ }while(RemainingPoints != 0);
+ }
+
+ // get cutout holes (CIRCLEs)
+ ret = CollectBoardCutoutSegments(E, Layer3dBoardDimension, CIRCLE);
+ if(ret)
+ {
+ for(int i=0;i E.x, E.y
+ }
+
+ // get cutouts from 3d-bottomlayer (for each device)
+ if(CollectBoardCutoutSegments(E, bLayer3Ddata, LINE))
+ {
+ NumCutouts++; // increment board cutouts
+ SortPoints(E.name); // elementname
+ OutputLines(0, 0, CUTOUT); // subract given offsets -> E.x, E.y
+ }
+
+ } //BRD.elements(E)
+ return;
+}
+
+
+
+////////////////////////////////////////////////////
+void DoCutoutsFromBoardDirect(UL_BOARD BRD)
+{
+ // drill circles if linewidth = 0
+ BRD.circles(CIR) // create circles direct from board
+ {
+ if(CIR.layer == Layer3dBoardDimension && CIR.width < (maxCutoutLineWidth+1))
+ {
+ NumCutouts++;
+ IDF_Circle(CIR.x, CIR.y, CIR.x+CIR.radius, CIR.y, CUTOUT);
+ }
+ }
+ return;
+}
+
+
+
+////////////////////////////////////////////////////
+void IDF_BoardHeader(UL_BOARD BRD) //-## create header of boardfile
+{
+ int t = time();
+ string date;
+ string sourceID;
+
+ sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t));
+ sprintf(sourceID, "Commend International >%s.ulp %s<", UlpName, UlpVersion);
+
+ printf(".HEADER\n");
+ printf("BOARD_FILE 3.0 \"%s\" %s 1\n", sourceID, date);
+ printf("\"%s\" MM\n", filename(BRD.name));
+ printf(".END_HEADER\n");
+ return;
+}
+
+
+
+////////////////////////////////////////////////////
+void IDF_BoardOutline(UL_BOARD BRD) //-## create outline of board
+{
+ // get outline
+ CollectBoardOutlineSegments(BRD);
+ SortPoints("Board-Outline"); // boardname
+
+ // draw outline
+ printf(".BOARD_OUTLINE UNOWNED\n");
+ printf("%.6f\n", getPartHeight());
+ OutputLines(0, 0, OUTLINE); // subract given offsets -> E.x, E.y
+
+ // draw cutouts
+ DoCutoutsFromElements(BRD); // get cutouts from devices -> board is a device
+
+ if(OutlineInDeviceFound) // get cutouts from board direct -> outline direct drawn in board
+ DoCutoutsFromBoardDirect(BRD);
+
+ printf(".END_BOARD_OUTLINE\n");
+ return;
+}
+
+
+////////////////////////////////////////////////////
+void IDF_BoardPlaceParts(UL_BOARD BRD) //-## mount parts on board
+{
+ int i, inlib;
+ string MountSide[] = {"TOP","BOTTOM"};
+
+
+ printf(".PLACEMENT\n");
+
+ BRD.elements(E)
+ {
+ inlib = 0;
+ for(i=0; i more than one part on same x/y position
+ {
+ int lib_start = i;
+
+ do
+ {
+ printf("%s_ANGLE%.1f_%s.%d CI_LIB %s.%d\n", E.package.name, E.angle, PacIn_LIB_SubPart_mountside[lib_start], PacIn_LIB_heights[lib_start], E.name, PacIn_LIB_heights[lib_start]);
+ printf("%.6f %.6f 0 0 %s PLACED\n", u2mm(E.x), u2mm(E.y), PacIn_LIB_SubPart_mountside[lib_start]);
+ lib_start++;
+ }while(PacIn_LIB_heights[lib_start] > 1);
+ }
+ }
+ }
+
+ printf(".END_PLACEMENT\n");
+ return;
+}
+
+
+////////////////////////////////////////////////////
+void IDF_BoardHoles(UL_BOARD BRD) //-## create holes in board (cutout, partholes, ...)
+{
+ printf(".DRILLED_HOLES\n");
+
+ // drill holes from board direct
+ BRD.holes(H)
+ printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y));
+
+ // drill holes from elements
+ BRD.elements(E)
+ {
+ E.package.holes(H)
+ printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y));
+ }
+
+ // drill big via's
+ BRD.signals(S)
+ {
+ S.vias(V)
+ {
+ if((DrillViaHoles == true) && (u2mm(V.drill) > MinViaHoleDia)) // drill via-hole
+ printf("%.6f %.6f %.6f PTH BOARD VIA UNOWNED\n", u2mm(V.drill), u2mm(V.x), u2mm(V.y));
+ }
+ }
+
+ printf(".END_DRILLED_HOLES\n");
+ return;
+}
+
+
+
+////////////////////////////////////////////////////
+void IDF_CreateLibaryFile(UL_BOARD BRD, string fname) // create libary for the IDF-board
+{
+ output(fname, "wt")
+ {
+ IDF_LibaryHeader(BRD);
+ IDF_LibaryElectrical(BRD);
+ IDF_LibaryMechanical(BRD);
+ }
+ return;
+}
+
+
+////////////////////////////////////////////////////
+void IDF_CreateBoardFile(UL_BOARD BRD, string fname) // create boardfile with parts of libary
+{
+ output(fname, "wt")
+ {
+ IDF_BoardHeader(BRD);
+ IDF_BoardOutline(BRD);
+ IDF_BoardHoles(BRD);
+ IDF_BoardPlaceParts(BRD);
+ }
+ return;
+}
+
+////////////////////////////////////////////////////
+void IDF_CreatePanelFile(UL_BOARD BRD, string fname) // create panel, containing board and parts of libary
+{
+ // not yet implemented
+ return;
+}
+
+
+
+
+////////////////////////////////////////////////////
+void DisplayHelp(void) // show helptext
+{
+ dlgDialog("generation of different variants - Help")
+ {
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout
+ {
+ dlgVBoxLayout dlgSpacing(200);
+ dlgTextView(HelpText);
+ }
+ dlgHBoxLayout
+ {
+ dlgStretch(1);
+ dlgPushButton("-Close") dlgReject();
+ }
+ };
+ return;
+}
+
+
+
+////////////////////////////////////////////////////
+// S T A R T of U L P
+//
+if (!board)
+{
+ dlgMessageBox(usage + "ERROR: No board!
\nThis program can only work in the layout editor.");
+ exit(1);
+}
+else
+{
+ int proceed = 0;
+ string FilenameLibary;
+ string FilenameBoard;
+ string FilenamePanel;
+
+
+
+
+ project.board(BRD)
+ {
+ FilenameBoard = filesetext(BRD.name, ".emn");
+ FilenameLibary = filesetext(BRD.name, ".emp");
+ }
+
+ dlgDialog("Generate 3D data format (IDF-file)")
+ {
+ dlgHBoxLayout
+ {
+ dlgGroup(" settings ")
+ {
+ dlgGridLayout
+ {
+ dlgCell(0,0) dlgCheckBox("close polygon if gap is smaller than : ", CloseOpenPoly);
+ dlgCell(0,1) dlgRealEdit(MaxGapWidth);
+ dlgCell(0,2) dlgLabel(" mm ");
+
+ dlgCell(1,0) dlgCheckBox("drill via-holes if via is bigger than : ", DrillViaHoles);
+ dlgCell(1,1) dlgRealEdit(MinViaHoleDia);
+ dlgCell(1,2) dlgLabel(" mm ");
+ }
+ }
+ }
+ dlgHBoxLayout
+ {
+ dlgLabel("enter output-filename : ");
+ dlgStringEdit(FilenameBoard);
+ dlgPushButton("Browse")
+ {
+ string FileName = dlgFileSave("Save IDF file", FilenameBoard, "IDF files (*.emn)");
+ if (FileName)
+ {
+ if(strchr(FileName, '.') < 0) // add fileextension if missing
+ FileName += ".emn";
+
+ FilenameLibary = filesetext(FileName, ".emp");
+ FilenameBoard = FileName;
+ }
+ }
+
+ }
+ dlgHBoxLayout
+ {
+ dlgPushButton("OK")
+ {
+ proceed = 1;
+ dlgAccept();
+ }
+
+ dlgPushButton("Help")
+ DisplayHelp();
+
+ dlgPushButton("Cancel")
+ dlgReject();
+ }
+ };
+
+
+ if(proceed)
+ {
+ project.board(BRD)
+ {
+ GetUlpName(); // gets ulp name
+ CollectPartData(BRD); // read out data from BRD
+
+ IDF_CreateLibaryFile(BRD, FilenameLibary);
+ IDF_CreateBoardFile(BRD, FilenameBoard);
+ IDF_CreatePanelFile(BRD, FilenamePanel);
+ }
+ }
+}
\ No newline at end of file
diff --git a/trunk/ulp/gluemark.ulp b/trunk/ulp/gluemark.ulp
new file mode 100644
index 00000000..367fab70
--- /dev/null
+++ b/trunk/ulp/gluemark.ulp
@@ -0,0 +1,145 @@
+#usage "Export data for SMD glue dispenser equipment\n"
+ "
"
+ "
"
+ "
Define glue points in library as circles on tGlue layer. Use as many circles"
+ " per package as you like. If no circle is defined, one default point is used"
+ " (center of wires in tPlace layer)."
+ "
Run gluemark.ulp to generate circles on layers 111 and 112, indicating glue points"
+ " for smd packages on top or bottom layers."
+ "
Edit 111 + 112 if necessary (you can also add or delete circles) and then use"
+ " glueout4.ulp to generate data for glue dispenser. glueout.ulp has to be changed to"
+ " get the wanted data format."
+ "
Use gluetop.dat and gluebot.dat for your dispenser."
+ "
"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+//******* workaround due to beta version error
+//all min function calls changed to minm, max changed to maxm
+real minm(real a, real b) {
+ if (a <= b) return a;
+ else return b;
+ }
+real maxm(real a, real b) {
+ if (a >= b) return a;
+ else return b;
+ }
+//*******
+
+int issmd, gluedef, ontop;
+real xmin , xmax, ymin, ymax, x, y;
+string h, cmd;
+
+void setgluepoint(UL_ELEMENT E){
+ gluedef = 0;
+ E.package.circles(CI){
+ if (CI.layer == LAYER_TGLUE) {
+ x = u2inch(CI.x); y = u2inch(CI.y);
+ h = "";
+ sprintf(h,"Layer tGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y);
+ cmd += h;
+ gluedef = 1;
+ }
+ if (CI.layer == LAYER_BGLUE) {
+ x = u2inch(CI.x); y = u2inch(CI.y);
+ h = "";
+ sprintf(h,"Layer bGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y);
+ cmd += h;
+ gluedef = 1;
+ }
+ }
+
+ xmin = u2inch(E.x); xmax = xmin;
+ ymin = u2inch(E.y); ymax = ymin;
+ if (gluedef == 0){
+ E.package.wires(W){
+ if (W.layer == LAYER_TPLACE) {
+ ontop = 1;
+ xmin = min(u2inch(W.x1),xmin);output("test.scr") {printf("u2iW.x%f\n",u2inch(W.x1));}
+ xmin = min(u2inch(W.x2),xmin);
+ ymin = min(u2inch(W.y1),ymin);
+ ymin = min(u2inch(W.y2),ymin);
+ xmax = max(u2inch(W.x1),xmax);
+ xmax = max(u2inch(W.x2),xmax);
+ ymax = max(u2inch(W.y1),ymax);
+ ymax = max(u2inch(W.y2),ymax);
+ }
+ if (W.layer == LAYER_BPLACE) {
+ ontop = 0;
+ xmin = min(u2inch(W.x1),xmin);
+ xmin = min(u2inch(W.x2),xmin);
+ ymin = min(u2inch(W.y1),ymin);
+ ymin = min(u2inch(W.y2),ymin);
+ xmax = max(u2inch(W.x1),xmax);
+ xmax = max(u2inch(W.x2),xmax);
+ ymax = max(u2inch(W.y1),ymax);
+ ymax = max(u2inch(W.y2),ymax);
+ }
+ }
+ x = (xmin+xmax)/2; y = (ymin+ymax)/2;
+ if (ontop == 1) {
+ h = "";
+ sprintf(h,"LAYER tGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y);
+ cmd += h;
+ }
+ if (ontop == 0) {
+ h = "";
+ sprintf(h,"LAYER bGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y);
+ cmd += h;
+ }
+ }
+}
+
+cmd = "";
+h = "";
+sprintf(h,"Layer 111 tGTest;\n");
+cmd += h;
+h = "";
+sprintf(h,"Layer 112 bGTest;\n");
+cmd += h;
+h = "";
+sprintf(h,"Set Color_Layer 111 red;\n");
+cmd += h;
+h = "";
+sprintf(h,"Set Color_Layer 112 blue;\n");
+cmd += h;
+h = "";
+sprintf(h,"Grid inch;\n");
+cmd += h;
+
+if (board){
+board(B){
+ B.elements(E) {
+ issmd = 0;
+ E.package.contacts(C) {
+ if (C.smd) {
+ issmd = 1;
+ break;
+ }
+ }
+ if (issmd) {
+ setgluepoint(E);
+ }
+
+ }
+}
+// EditBox
+int Result = dlgDialog("Edit and Execute") {
+ dlgTextEdit(cmd);
+ dlgHBoxLayout {
+ dlgPushButton("+Execute") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ }
+ };
+if (!Result) exit(0);
+
+exit(cmd);
+
+}
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+}
diff --git a/trunk/ulp/glueout.ulp b/trunk/ulp/glueout.ulp
new file mode 100644
index 00000000..f41c3c1c
--- /dev/null
+++ b/trunk/ulp/glueout.ulp
@@ -0,0 +1,53 @@
+#usage "Export data for SMD glue dispenser equipment\n"
+ "
"
+ "This program is used in conjunction with gluemark.ulp. "
+ "It generates top and bottom glue data from circles on layers 111 and 112."
+ "
"
+ "Define output format in function outputdata."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string top_data_filename = "gluetop.dat";
+string bottom_data_filename = "gluebot.dat";
+
+void outputdata (UL_CIRCLE C){
+
+//**** change the following line to adjust the output format ******
+ printf("Gluepoint coordinates: %f %f\n", u2inch(C.x),u2inch(C.y));
+}
+
+void header (UL_BOARD B){
+ printf("#%s\n\n", EAGLE_SIGNATURE);
+ printf("#Gluepoints exported from %s\n#at %s\n\n", B.name, t2string(time()));
+}
+
+if (board) {
+output(top_data_filename) {
+ board(B){
+ header(B);
+ B.circles(C){
+ if (C.layer == 111) {
+ outputdata(C);
+ }
+ }
+ }
+}
+
+output(bottom_data_filename) {
+ board(B){
+ header(B);
+ B.circles(C){
+ if (C.layer == 112) {
+ outputdata(C);
+ }
+ }
+ }
+}
+}
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+}
diff --git a/trunk/ulp/hyperlynx.ulp b/trunk/ulp/hyperlynx.ulp
new file mode 100644
index 00000000..926b4222
--- /dev/null
+++ b/trunk/ulp/hyperlynx.ulp
@@ -0,0 +1,1641 @@
+#usage "nobr>Exports the board to HyperLynx Signal-Integrity Transfer Format (.HYP)
"
+ "* HyprLynx.ULP Written by Frank Hoffman of LLOYD I/O INC "
+ "* Copyright (c) 1997, All Rights Reserved by LLOYD I/O INC "
+ "Author 503/222-0702 frankh@lloydio.com www.lloydio.com"
+ "
"
+ "* 1 sided boards use layer 16 "
+ "* 2 sided boards use layers 1 and 16 "
+ "* 4 layer boards use layers 1,2 and 15, 16 "
+ "* 6 layer boards use layers 1,2,3 and 14,15,16 "
+ "* 8 layer boards use layers 1,2,3,4 and 13,14,15,16 "
+ "* 10 layer boards use layers 1,2,3,4,5 and 12,13,14,15,16 "
+ "* 12 layer boards use layers 1,2,3,4,5,6 and 11,12,13,14,15,16 "
+ "* 14 layer boards use layers 1,2,3,4,5,6,7 and 10,11,12,13,14,15,16 "
+ "* 16 layer boards use layers 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 "
+ "* "
+ "* Adapted for Eagle-Version 4.1 "
+ "* - Unrouted layer not exported "
+ "* - Export also Wire-Arcs "
+ "* - SMD shape Roundnes is included "
+ "* - PAD shape LONG OFFSET (Oblong) is included "
+ "* - PAD accept Top, Bottom and Inner (MDEF) layer "
+ "* - VIA generate only used layer in stack "
+ "* 02.04.2004 alf@cadsoft.de "
+ "* - W.curve correction in C.element.package.wires(W) "
+ "* 21.04.2005 alf@cadsoft.de "
+ "* - {PADSTACK=...%03d correct number while count from 1 "
+ "* 17.08.2005 alf@cadsoft.de "
+ "* - First check filling of polygons and start Ratsnest "
+ "* Export calculated polygon contours and filling "
+ "* 11.03.2012 alf@cadsoft.de "
+ "* - Check if polygon placed "
+ "* 17.12.2012 alf@cadsoft.de "
+ "* ";
+
+
+// Version 4.11 : W.curve correction in C.element.package.wires(W) 21.04.2005
+// Version 4.12 : Correct Padstack number while list from 0 (zerro) 03.05.2005
+// The original ULP counts the PADSTACK-List from 1 (+1),
+// the used Pads counts from 0 ! *** 03.05.2005
+// Version 4.13 : Correct Padstack counter in for { loop } *** 11.08.2005
+// Check if a SMD-Pad dx=0 or dy=0 then aborted this ULP RUN.
+// Version 4.14 : Correct Padstack counter in all function, count now from 1 to total_pad
+// eliminate correction of 4.12 from 03.05.2005
+// Version 4.15 : First check filling of polygons and start Ratsnest
+// Export calulated polygon contours and filling
+// Version 4.16 : Check if a polygon placed to start first RATSNEST
+
+string Version = "Version 2.00 9/11/97 -- 4.16 17/12/2012";
+
+
+string headerline = "* Exports the board to HyperLynx Signal-Integrity Transfer Format (.HYP)";
+
+
+
+//***********************************************
+// Definitions of yes and no! Do not modify!
+char yes = 1; // yes must be different from no.
+char no = 0; // no must be zero (0)
+//********************************************************************************************
+//********************************************************************************************
+//********************************************************************************************
+// USER MODIFYABLE DATA
+
+// Generate Files Options:
+char GenerateReferenceFile = yes; // Generate the Reference File ('yes'/'no')
+char GenerateHyperlynxFile = yes; // Generate the Hyperlynx File ('yes'/'no')
+
+// Generate Component Types Options:
+char UseComponentTypes = yes; // Devices Q, T, U, IC, C, D, L, R, BD, etc. ('yes'/'no')
+
+// Generate Component Pin Direction Options:
+char GeneratePinDirection = no; // If 'yes', slows down many many times.
+
+// Component Value Change Options:
+char TruncateComponentValues = no; // Truncate ".1uf 50v" to ".1uf" ('yes'/'no')
+char ConvertCapValues = yes; // Convert Capacitor Values. i.e. change ".1" to ".1u" ('yes'/'no')
+string ConvertLT1to = "uF"; // values less than 1 are labeled as this unit
+string ConvertGE1to = "uF"; // convert greater than or equal to 1 are labeled as this unit
+
+// Board Thickness AND Stack Up Options:
+char UseBoardStackUp = yes; // Use board thickness data ('yes'/'no')
+real board_thickness = 0.0625; // Board Thickness, if 0: use fixed layer sizes else calc layer thicknesses
+
+// Copper Value Options:
+real zerooz = 0.0000; // zero copper thickness
+real halfoz = 0.0007; // 0.5 oz copper thickness
+real oneoz = 0.0014; // 1.0 oz copper thickness
+real twooz = 0.0028; // 2.0 oz copper thickness
+// Copper Layer Thickness for Each Layer of Copper
+real copper_thickness[] = {0.0, halfoz,halfoz,halfoz,halfoz,halfoz,halfoz,
+ halfoz,halfoz,halfoz,halfoz,halfoz,halfoz,
+ halfoz,halfoz,halfoz,halfoz}; // 1st number is not used (no layer 0)
+// Copper Layer Plating Thickness for Each Layer of Copper.
+// Top and Bottom are used most often.
+real copper_plating[] = {0.0, halfoz,zerooz,zerooz,zerooz,zerooz,zerooz,
+ zerooz,zerooz,zerooz,zerooz,zerooz,zerooz,
+ zerooz,zerooz,zerooz,halfoz}; // 1st number is not used (no layer 0)
+
+// Dielectric Value Options:
+real dicons = 4.8; // default dielectric constant
+real dit1ly = 0.0611; // dielectric thickness for 1 sided board
+real dit2ly = 0.0597; // dielectric thickness for 2 sided board
+real ditmly = 0.0200; // dielectric thickness for multilayered boards
+real dielectric_constant[] = { dicons,dicons,dicons,dicons,dicons,dicons,dicons,dicons,dicons};
+real dielectric_thickness[] = { dit1ly,dit2ly,ditmly,ditmly,ditmly,ditmly,ditmly,ditmly,ditmly};
+
+// Special Wire Width Options:
+real RectOutlineWireWidth = 0.001; // Rectangle outline wire width in inches
+real HoleOutlineWireWidth = 0.001; // Holes outline wire width in inches
+
+// Precision of board components to accurately draw and locate.
+// (After the decimal '.' point.)
+int precision_of_perimeter = 4; // board perimeter dimension precision
+int precision_of_layers = 5; // layer thickness precision
+int precision_of_pads = 3; // pad/smd size precision
+int precision_of_nets = 4; // pin/via/segment/width precision
+
+
+//********************************************************************************************
+//********************************************************************************************
+//********************************************************************************************
+// DO NOT MODIFY ANYTHING BELOW THIS LINE //
+
+int index[]; // sorting index array (indirect)
+
+// pad info
+int ISAPAD = 0; // through hole pad
+int ISASMD = 1; // surface mount device pad
+int ISAVIA = 18; //
+
+// *** HyperLynx pad shapes ***
+int OVALROUND = 0; // '0' means oval or round (pad_sx=pad_sy if round)
+int RECTSQUARE = 1; // '1' means rectangular or square (pad_sx=pad_sy if square)
+int OBLONG = 2; // '2' means oblong (oblong shape is a rectangular with rounded corners)
+
+string PadShapes[]; // list of hyp's pad shapes
+string HypPadShapes[]; // list of hyp's pad shapes
+string EaglePadShapes[]; // list of eagle pad shapes
+int Total_Pads = 0; // total pads
+int pad_type[]; // pad types (ISAPAD,ISASMD)
+int pad_layer[]; // 0 = Pad, 1 or 16 = SMD, 18 = Via
+int pad_shape_Top_rnds[]; // hyperlynx type OVALROUND, RECTSQUARE, OBLONG
+int pad_shape_Inner[]; // hyperlynx type OVALROUND, RECTSQUARE, OBLONG
+int pad_shape_Bott[]; // hyperlynx type OVALROUND, RECTSQUARE, OBLONG
+real pad_angle_end[]; // Pad rotation or Via End layer (Vias can not rotate!)
+int pad_diameter_Top_or_dx[];
+int pad_diameter_Inner[];
+int pad_diameter_Bott[];
+int pad_dy_elong_start[]; // SMD-dy, Pad-Elongation, Via Stack-Start
+int pad_drill[];
+
+string padStackList = "#\ttype\tlayer\tTop_rnd\tInner\tBott\tang_end\tdx_T\tdx_I\tdx_B\tdy_el\tdril\n";
+
+
+
+
+// copper layer info
+string LayerNames[]; // layer names
+int copp_lookup[] = {0, 1,16, 2,15, 3,14, 4,13, 5,12, 6,11, 7,10, 8,9 };
+int copp_used_layer[];
+int Total_Layers; // total number of used layers
+int layer_counter; // layer counter
+real Total_Board_Thickness; // calculated total board thickness
+
+/* ----- Eagle HELP --------------------------------
+PAD_SHAPE_SQUARE square
+PAD_SHAPE_ROUND round
+PAD_SHAPE_OCTAGON octagon
+PAD_SHAPE_LONG long
+PAD_SHAPE_OFFSET offset
+PAD_SHAPE_ANNULUS annulus (only in Supply-Layer)
+PAD_SHAPE_THERMAL thermal (only in Supply-Layer)
+-------------------------------------------------- */
+
+// define the HyperLynx Pad Shapes
+PadShapes[ PAD_SHAPE_SQUARE ] = "1"; // hyp's square and rectangle shape
+HypPadShapes[ PAD_SHAPE_SQUARE ] = "Square"; // HyperLynx's square and rectangle shape
+EaglePadShapes[ PAD_SHAPE_SQUARE ] = "Square"; // Eagle's square and rectangle shape
+PadShapes[ PAD_SHAPE_ROUND ] = "0"; // hyp's round and oval shape
+HypPadShapes[ PAD_SHAPE_ROUND ] = "Round"; // HyperLynx's round and oval shape
+EaglePadShapes[ PAD_SHAPE_ROUND ] = "Round"; // Eagle's round and oval shape
+PadShapes[ PAD_SHAPE_OCTAGON ] = "0"; // hyp's octagon is a round shape
+HypPadShapes[ PAD_SHAPE_OCTAGON ] = "Round"; // HyperLynx's octagon is a round shape
+EaglePadShapes[ PAD_SHAPE_OCTAGON ] = "Octagon"; // Eagle's octagon is a round shape
+PadShapes[ PAD_SHAPE_LONG ] = "2"; // hyp's oblong, rectangle with rounded corners
+HypPadShapes[ PAD_SHAPE_LONG ] = "Oblong"; // HyperLynx's oblong, rectangle with rounded corners
+EaglePadShapes[ PAD_SHAPE_LONG ] = "Long"; // Eagle's oblong, rectangle with rounded corners
+PadShapes[ PAD_SHAPE_OFFSET ] = "0"; // hyp's round and oval shape
+HypPadShapes[ PAD_SHAPE_OFFSET ] = "Round"; // HyperLynx's oblong, rectangle with rounded corners
+EaglePadShapes[ PAD_SHAPE_OFFSET ] = "Offset"; // Eagle's (Long) Offset, rectangle with rounded corners
+
+
+
+// ***************************************************************************
+// layers
+
+// This routine counts visible layers and stores the name in an internal table
+// Layer names beginning with '$' have the leading '$' striped.
+// This routine is called from a loop
+void CountLayers(UL_LAYER L) {
+ if ( ( L.number >= 1 ) && ( L.number <= 16 ) ) {
+ if ( strchr( L.name, '$' ) == 0 ) {
+ LayerNames[L.number] = strsub( L.name, 1 );
+ }
+ else {
+ LayerNames[L.number] = L.name;
+ }
+ if (L.visible) {
+ layer_counter++;
+ if (L.used) copp_used_layer[L.number] = 1;
+ }
+ }
+}
+
+// This routine writes out the layer names as signal layers or power planes
+// It also writes out the dielectric layer info when needed
+// This routine is called from a loop
+string layernam; // layer name buffer
+void PrintLayer(UL_LAYER L) {
+ real diele_thickness; // calculated dielectric thickness
+ real copp_thickness; // calculated total copper thickness
+ int i; // loop counter
+ if (L.visible) {
+ if ( L.number >= 1 && L.number <= 16 ) {
+ if ( strchr( L.name, '$' ) == 0 ) { // ** is it a Power plane?
+ layernam = strsub( L.name, 1 );
+ printf("(PLANE T=%6.*f L=%s)\n",
+ precision_of_layers, copper_thickness[L.number], layernam);
+ }
+ else {
+ printf("(SIGNAL T=%6.*f P=%6.*f L=%s)\n",
+ precision_of_layers, copper_thickness[L.number],
+ precision_of_layers, copper_plating[L.number],
+ L.name);
+ }
+ layer_counter++;
+ if (board_thickness) {
+ Total_Board_Thickness = board_thickness;
+ copp_thickness = 0.0;
+ for (int i = 1; i <= Total_Layers; i++ ) {
+ copp_thickness += copper_thickness[copp_lookup[i]] + copper_plating[copp_lookup[i]];
+ }
+ if (Total_Layers <= 2 ) diele_thickness = ( board_thickness - copp_thickness );
+ else diele_thickness = ( board_thickness - copp_thickness ) / ( real(Total_Layers) - 1.00 );
+ }
+ else {
+ diele_thickness = dielectric_thickness[Total_Layers/2];
+ copp_thickness = 0.0;
+ for (int i = 1; i <= Total_Layers; i++ ) {
+ copp_thickness += copper_thickness[copp_lookup[i]] + copper_plating[copp_lookup[i]];
+ }
+ if (Total_Layers <= 2 ) Total_Board_Thickness = copp_thickness + diele_thickness;
+ else Total_Board_Thickness = copp_thickness + (diele_thickness * ( real(Total_Layers) - 1.00 ));
+ }
+ if (layer_counter < Total_Layers) {
+ printf("(DIELECTRIC T=%6.*f C=%4.*f ",
+ precision_of_layers,diele_thickness,
+ precision_of_layers,dielectric_constant[Total_Layers/2]);
+ printf("L=DL%02d)\n",layer_counter);
+ }
+ if (Total_Layers == 1) {
+ printf("(DIELECTRIC T=%6.*f C=%4.*f ",
+ precision_of_layers,diele_thickness,
+ precision_of_layers,dielectric_constant[Total_Layers/2]);
+ printf("L=DL%02d)\n",layer_counter);
+ }
+ }
+ }
+}
+
+
+
+// ***************************************************************************
+// pads
+
+int search_A_Pad( int apad_type, int apad_layer,
+ int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott,
+ real apad_angle_end,
+ int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott,
+ int apad_dy_elong_start,
+ int apad_dril ) {
+ int found = 0;
+ for ( int i = 1; i <= Total_Pads; i++ ) {
+ if ( pad_type[i] == apad_type &&
+ pad_layer[i] == apad_layer &&
+ pad_shape_Top_rnds[i] == apad_shape_Top_rnds &&
+ pad_shape_Inner[i] == apad_shape_Inner &&
+ pad_shape_Bott[i] == apad_shape_Bott &&
+ pad_angle_end[i] == apad_angle_end &&
+ pad_diameter_Top_or_dx[i] == apad_dx_Top &&
+ pad_diameter_Inner[i] == apad_dx_Inner &&
+ pad_diameter_Bott[i] == apad_dx_Bott &&
+ pad_dy_elong_start[i] == apad_dy_elong_start&&
+ pad_drill[i] == apad_dril )
+ {
+ found = i;
+ break;
+ }
+ }
+ return( found);
+}
+
+// This routine inserts a pad of known type and size into the pad table
+// The returned value reflects the current number of pads in the table
+// If the pad size already exists, the pad is not inserted
+
+void Insert_A_Pad( int apad_type, int apad_layer,
+ int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott,
+ real apad_angle_end,
+ int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott,
+ int apad_dy_elong_start,
+ int apad_dril ) {
+
+ int fnd = search_A_Pad( apad_type, apad_layer, apad_shape_Top_rnds, apad_shape_Inner, apad_shape_Bott, apad_angle_end, apad_dx_Top, apad_dx_Inner, apad_dx_Bott, apad_dy_elong_start, apad_dril);
+ if (fnd == 0) {
+ Total_Pads++;
+ pad_type[Total_Pads] = apad_type;
+ pad_layer[Total_Pads] = apad_layer;
+ pad_shape_Top_rnds[Total_Pads] = apad_shape_Top_rnds;
+ pad_shape_Inner[Total_Pads] = apad_shape_Inner;
+ pad_shape_Bott[Total_Pads] = apad_shape_Bott;
+ pad_angle_end[Total_Pads] = apad_angle_end;
+ pad_diameter_Top_or_dx[Total_Pads] = apad_dx_Top;
+ pad_diameter_Inner[Total_Pads] = apad_dx_Inner;
+ pad_diameter_Bott[Total_Pads] = apad_dx_Bott;
+ pad_dy_elong_start[Total_Pads] = apad_dy_elong_start;
+ pad_drill[Total_Pads] = apad_dril;
+ }
+ return;
+}
+
+// This routine finds a pad of a known type and size and returns the ID
+// of the pad (internal number) that is used to identify the pad.
+
+int Find_A_Pad( int apad_type, int apad_layer,
+ int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott,
+ real apad_angle_end,
+ int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott,
+ int apad_dy_elong_start,
+ int apad_dril ) {
+ int fnd = search_A_Pad( apad_type, apad_layer, apad_shape_Top_rnds, apad_shape_Inner, apad_shape_Bott, apad_angle_end, apad_dx_Top, apad_dx_Inner, apad_dx_Bott, apad_dy_elong_start, apad_dril);
+ return( fnd );
+}
+
+// This routine finds the HyperLynx shape form of eagle shape
+int SmdRoundness(int r) {
+ if (r == 100) return 0; // oval or round
+ if (r == 0) return 1; // rect or square
+ return 2; // oblong
+}
+
+
+// Insert a pin on in a list of associated connected contacts
+int AssPinCount = 0; // Number of associated Contacts
+string AssTabEname[]; // Element Name
+string AssTabCname[]; // Contact Name
+int AssTabLenEname[]; // Element Name Length
+int AssTabLenCname[]; // Contact Name Length
+int InsertAssocatedPin( string ename, string cname ) {
+ int lenofename,lenofcname;
+ lenofename = strlen(ename);
+ lenofcname = strlen(cname);
+ if ( AssPinCount > 0 ) {
+ for ( int i = 0; i < AssPinCount; i++ ) {
+ if ( lenofename == AssTabLenEname[i] )
+ if ( lenofcname == AssTabLenCname[i] )
+ if ( strstr( AssTabEname[i], ename ) != -1 )
+ if ( strstr( AssTabCname[i], cname ) != -1 ) return( AssPinCount );
+ }
+ }
+ AssTabEname[AssPinCount] = ename;
+ AssTabCname[AssPinCount] = cname;
+ AssTabLenEname[AssPinCount] = lenofename;
+ AssTabLenCname[AssPinCount] = lenofcname;
+ AssPinCount++;
+ return( AssPinCount );
+}
+
+int FindAssocatedPin( string ename, string cname ) {
+ int lenofename,lenofcname;
+ lenofename = strlen(ename);
+ lenofcname = strlen(cname);
+ if ( AssPinCount > 0 ) {
+ for ( int i = 0; i < AssPinCount; i++ ) {
+ if ( lenofename == AssTabLenEname[i] )
+ if ( lenofcname == AssTabLenCname[i] )
+ if ( strstr( AssTabEname[i], ename ) != -1 )
+ if ( strstr( AssTabCname[i], cname ) != -1 ) return( AssPinCount );
+ }
+ }
+ return( 0 );
+}
+
+// write a divider
+void printdivider( void ) {
+ printf("**********************************************************************\n");
+ return;
+}
+
+// write a section header with dividers
+void printheader(string hs) {
+ printdivider();
+ printf("* %s\n*\n",hs);
+ return;
+}
+
+// write translated package types from Eagle to Hyperlynx
+int saypackagetype(string pn) {
+ if ( strstr( pn,"TSSOP" ) != -1 ) {
+ printf(" PKG=TSSOP");
+ }
+ else if ( strstr( pn,"TQFP" ) != -1 ) {
+ printf(" PKG=TQFP");
+ }
+ else if ( strstr( pn,"SSOP" ) != -1 ) {
+ printf(" PKG=SSOP");
+ }
+ else if ( strstr( pn,"PLCC" ) != -1 ) {
+ printf(" PKG=PLCC");
+ }
+ else if ( strstr( pn,"LCC" ) != -1 ) {
+ printf(" PKG=LCC");
+ }
+ else if ( strstr( pn,"DIP" ) != -1 ) {
+ printf(" PKG=DIP");
+ }
+ else if ( strstr( pn,"QFP" ) != -1 ) {
+ printf(" PKG=QFP");
+ }
+ else if ( strstr( pn,"BGA" ) != -1 ) {
+ printf(" PKG=BGA");
+ }
+ else if ( strstr( pn,"PGA" ) != -1 ) {
+ printf(" PKG=PGA");
+ }
+ else if ( strstr( pn,"DIL" ) != -1 ) {
+ printf(" PKG=DIP");
+ }
+ else if ( strstr( pn,"DIP" ) != -1 ) {
+ printf(" PKG=DIP");
+ }
+ else if ( strstr( pn,"SO" ) != -1 ) {
+ printf(" PKG=SO");
+ }
+ else return( no ); // no package type recognized
+ return( yes ); // yes, package recognized
+}
+
+
+// truncate trailing zeros and print value
+void TruncateTrailingZeros( real value, int prec ) {
+ string num;
+ int nlen;
+ sprintf( num, "%1.*f", prec, value );
+ nlen = strlen( num );
+ if ( nlen > 0 ) {
+ while ( num[ nlen-1 ] == '0' ) {
+ // truncate with a null
+ num[ nlen-1 ] = 0;
+ // recalc string length
+ nlen = strlen( num );
+ if ( nlen == 0 ) break;
+ }
+ }
+ printf("%s",num);
+ return;
+}
+
+// Convert Capacitor Values. i.e. change ".1" to ".1u"
+// char ConvertCapValues = yes;
+// Cap value conversion rules for values without suffix multipliers
+// string ConvertLT1to = "u"; // values less than 1 are "u" or "something else"
+// string ConvertGE1to = "u"; // convert greater than or equal to 1 as "u" or "p"
+//
+void ConvertCapValue( string capvalue ) {
+ char cstate; // state machine
+ char clabel; // unit label
+ real cvalue; // the value of the capacitor
+ int lenofcapvalue; // length of the string for parsing
+
+ if ( ConvertCapValues == yes ) {
+ cvalue = strtod( capvalue );
+ if ( cvalue != 0.0 ) {
+ lenofcapvalue = strlen( capvalue );
+ cstate = 1; // set state for searching digits
+ for ( int i=0; i 0 ) {
+ ICreflib = "74" + strsub( ICvalue, 2, ICccnt ) + ".PML";
+ }
+ else {
+ ICreflib = "74TTL.PML";
+ }
+ } else
+ if ( strstr( ICvalue, "40" ) == 0 ) {
+ unknownIC = no;
+ ICreflib = "74HC.PML";
+ ICvalue = "74HC" + ICvalue;
+ }
+ if ( unknownIC == no ) {
+ printf("%s, %s, %s",ICname,ICreflib,ICvalue);
+ ICpn =E.package.name;
+ if ( strstr( ICpn,"TSSOP" ) != -1 ) {
+ printf("_TSSOP");
+ }
+ else if ( strstr( ICpn,"TQFP" ) != -1 ) {
+ printf("_TQFP");
+ }
+ else if ( strstr( ICpn,"SSOP" ) != -1 ) {
+ printf("_SSOP");
+ }
+ else if ( strstr( ICpn,"PLCC" ) != -1 ) {
+ printf("_PLCC");
+ }
+ else if ( strstr( ICpn,"LCC" ) != -1 ) {
+ printf("_LCC");
+ }
+ else if ( strstr( ICpn,"DIP" ) != -1 ) {
+ printf("_DIP");
+ }
+ else if ( strstr( ICpn,"QFP" ) != -1 ) {
+ printf("_QFP");
+ }
+ else if ( strstr( ICpn,"BGA" ) != -1 ) {
+ printf("_BGA");
+ }
+ else if ( strstr( ICpn,"PGA" ) != -1 ) {
+ printf("_PGA");
+ }
+ else if ( strstr( ICpn,"DIL" ) != -1 ) {
+ printf("_DIP");
+ }
+ else if ( strstr( ICpn,"DIP" ) != -1 ) {
+ printf("_DIP");
+ }
+ else if ( strstr( ICpn,"SO" ) != -1 ) {
+ printf("_SSOP");
+ }
+ printf("\n");
+ }
+ }
+ }
+ }
+ }
+
+ if ( GenerateHyperlynxFile == no ) {
+ exit( EXIT_SUCCESS );
+ }
+ output( filesetext( B.name, ".HYP" ) ) {
+ printdivider();
+ printf("%s\n", headerline); // 03.05.2005 alf@cadsoft.de
+ printf("* %s\n*\n", Version);
+ printf("* %s\n*\n", EAGLE_SIGNATURE);
+ printf("* HyperLynx Board exported from:\n");
+ printf("* %s\n", B.name);
+ printf("* At %s\n*\n", t2string(time()));
+
+ if (project.schematic) {
+ printf("* Schematic is loaded.\n");
+ }
+ else {
+ printf("* Schematic NOT is loaded.\n");
+ }
+ printf("*\n\n");
+ printf("{VERSION=2.10} Compatible with Hyperlynx version 2.10.\n");
+ printf("{UNITS=ENGLISH WEIGHT}\n\n");
+
+ // BOARD OVERALL AREA DIMENSIONS
+ // Writes the board dimensions found on layer 20
+ printheader("Board Dimensions");
+ printf("{BOARD\n");
+ // wires on the dimension layer
+ B.wires(W) {
+ if (W.layer == 20 ) {
+ if (W.curve) {
+ // arcs in the dimension layer
+ printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Arcs: Board Outline Arc is CCW\n",
+ precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1),
+ precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2),
+ precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc),
+ precision_of_nets,u2inch(W.arc.radius) );
+ }
+ else {
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Wires: From Board\n",
+ precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
+ precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2));
+ }
+ }
+ }
+ // rectangles on the dimension layer
+ B.rectangles(R) {
+ if (R.layer == 20 ) {
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Bottom\n",
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1),
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1) );
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Right\n",
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1),
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2) );
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Top\n",
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2),
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2) );
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Left\n",
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2),
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1) );
+ }
+ }
+ // polygons on the dimension layer
+ B.polygons(P) {
+ if (P.layer == 20 ) {
+ P.wires(W) {
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Polygon Wires: From Board\n",
+ precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
+ precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2));
+ }
+ }
+ }
+ // circles in the dimension layer
+ B.circles(C) {
+ if (C.layer == 20 ) {
+ printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Circles: Board Outline Arc is CCW\n",
+ precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
+ precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
+ precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y),
+ precision_of_nets,u2inch(C.radius) );
+ }
+ }
+ // holes in the board
+ int halfdrilldiameter;
+ B.holes(H) {
+ halfdrilldiameter = H.drill / 2;
+ printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Holes: Board Outline Arc is CCW\n",
+ precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
+ precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
+ precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y),
+ precision_of_nets,u2inch(halfdrilldiameter) );
+ }
+ // package wires on the dimension layer
+ B.elements(E) {
+ E.package.wires(W) {
+ if (W.layer == 20 ) {
+ if (W.curve) {
+ // package arcs in the dimension layer
+ printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Arcs: Board Outline Arc is CCW Package %s in %s.LBR\n",
+ precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1),
+ precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2),
+ precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc),
+ precision_of_nets,u2inch(W.arc.radius),
+ E.package.name,E.package.library );
+ }
+ else {
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Wires: From Package %s in %s.LBR\n",
+ precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
+ precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2),
+ E.package.name,E.package.library);
+ }
+ }
+ }
+ // package rectangles on the dimension layer
+ E.package.rectangles(R) {
+ if (R.layer == 20 ) {
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Bottom\n",
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1),
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1),
+ E.package.name,E.package.library );
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Right\n",
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1),
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2),
+ E.package.name,E.package.library );
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Top\n",
+ precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2),
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2),
+ E.package.name,E.package.library );
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Left\n",
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2),
+ precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1),
+ E.package.name,E.package.library );
+ }
+ }
+ // package polygons on the dimension layer
+ E.package.polygons(P) {
+ if (P.layer == 20 ) {
+ P.wires(W) {
+ printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Polygon Wires: From Package %s in %s.LBR\n",
+ precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
+ precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2),
+ E.package.name,E.package.library);
+ }
+ }
+ }
+ // package circles in the dimension layer
+ E.package.circles(C) {
+ if (C.layer == 20 ) {
+ printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Circles: Board Outline Arc is CCW Package %s in %s.LBR\n",
+ precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
+ precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
+ precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y),
+ precision_of_nets,u2inch(C.radius),
+ E.package.name,E.package.library );
+ }
+ }
+ // package holes
+ int halfdrilldiameter;
+ E.package.holes(H) {
+ halfdrilldiameter = H.drill / 2;
+ printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Holes: Board Outline Arc is CCW Package %s in %s.LBR\n",
+ precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
+ precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
+ precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y),
+ precision_of_nets,u2inch(halfdrilldiameter),
+ E.package.name,E.package.library );
+ }
+ }
+ printf("}\n\n");
+
+ // LAYER INFORMATION
+ printheader("Thickness of Copper and Dielectric Layer Data");
+ if ( UseBoardStackUp == yes ) {
+ printf("{STACKUP\n");
+ layer_counter = 0;
+ B.layers(L) CountLayers(L);
+ Total_Layers = layer_counter; // remember active layers
+ layer_counter = 0;
+ B.layers(L) PrintLayer(L);
+ printf("}\n");
+ // TOTAL BOARD THICKNESS
+ printf("* Total Board Thickness %6.4f inch\n\n",Total_Board_Thickness);
+ }
+ else {
+ printf("* No PCB Thickness Data Generated !!! \n*\n\n");
+ }
+
+ // PACKAGES ON THE BOARD
+ printheader("Components");
+ printf("{DEVICES\n");
+ int unknowncomponenttype, pincount, componentspace;
+ string componentname;
+ string componentvalue;
+ B.elements(E) {
+ // get the number of pins
+ pincount = 0;
+ E.package.contacts(C) {
+ pincount++;
+ }
+ // set component as unknown
+ unknowncomponenttype = yes;
+ // remember component reference designator
+ componentname = E.name;
+ // truncate component values at the first space
+ // ? ASK HYPERLYNX : what about something like .1u 50v
+ componentvalue = E.value;
+ if ( TruncateComponentValues == yes )
+ if ( ( componentspace = strchr( componentvalue, ' ' ) ) != -1 )
+ componentvalue = strsub( componentvalue, 0, componentspace );
+ // parse reference designators ?
+ if ( UseComponentTypes == yes ) {
+ if ( strstr( componentname, "IC" ) == 0 ) {
+ if ( isdigit( componentname[2] ) ) {
+ printf("(IC REF=%s NAME=%s L=%s",componentname,componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ saypackagetype(E.package.name);
+ unknowncomponenttype = no;
+ }
+ }
+ else if ( strstr( componentname, "BD" ) == 0 ) {
+ if ( isdigit( componentname[2] ) ) {
+ printf("(BD REF=%s NAME=%s L=%s",componentname,componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ }
+ else if ( strstr( componentname, "BEAD" ) == 0 ) {
+ if ( isdigit( componentname[4] ) ) {
+ printf("(BD REF=%s NAME=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ }
+ else if ( isdigit( componentname[1] ) ) {
+ if ( strchr( componentname, 'U' ) == 0 ) {
+ printf("(IC REF=%s NAME=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ saypackagetype(E.package.name);
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'C' ) == 0 ) {
+ printf("(C REF=%s VAL=",componentname);
+ ConvertCapValue(componentvalue);
+ printf(" L=%s",E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'R' ) == 0 ) {
+ printf("(R REF=%s VAL=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'L' ) == 0 ) {
+ printf("(L REF=%s VAL=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'D' ) == 0 ) {
+ printf("(CR REF=%s NAME=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'J' ) == 0 ) {
+ printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'Q' ) == 0 ) {
+ printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ else if ( strchr( componentname, 'T' ) == 0 ) {
+ printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ unknowncomponenttype = no;
+ }
+ }
+ }
+
+ // handle unknown component types
+ if ( ( unknowncomponenttype == yes ) || ( UseComponentTypes == no ) ) {
+ printf("(? REF=%s NAME=%s L=%s",componentname,componentvalue,
+ E.mirror ? LayerNames[16] : LayerNames[1] );
+ saypackagetype(E.package.name);
+ }
+
+ // append comment field
+ printf(") R%03.0f X=%5.*f Y=%5.*f : ",E.angle,precision_of_nets,u2inch(E.x),
+ precision_of_nets,u2inch(E.y) );
+ printf(" Lib: %s : %s : ", E.package.library, E.package.name);
+ printf("Pins %d", pincount);
+ printf("\n");
+ }
+ printf("}\n\n");
+
+
+ // PADSTACK CREATION OF PADS, SMDS, AND VIAS
+ // create list of all the different pads and smds (vias are pads)
+ printheader("Pads, Smds, and Via Library");
+ // handle all net contacts and vias
+ B.signals(S) {
+ S.vias(V) {
+ Insert_A_Pad( ISAPAD, ISAVIA,
+ V.shape[1], V.shape[2], V.shape[16],
+ V.end,
+ V.diameter[1], V.diameter[2], V.diameter[16],
+ V.start,
+ V.drill );
+ }
+ }
+ // handle all package pins
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ Insert_A_Pad( ISAPAD, ISAPAD,
+ C.pad.shape[1], C.pad.shape[2], C.pad.shape[16],
+ C.pad.angle,
+ C.pad.diameter[1], C.pad.diameter[2], C.pad.diameter[16],
+ C.pad.elongation,
+ C.pad.drill );
+ }
+ else if (C.smd) {
+ if ( !C.smd.dx || !C.smd.dy) {
+ string h;
+ sprintf(h, "!Found a SMD-Pad with dx or dy = 0 (Zerro) Pad %s' Layer %d Coordinate (%.4f %.4f) mil Package %s.PAC Element %s Library %s.lbr
"
+ "Layer assignment "
+ "Depending on the source system, signal, solder and other layer types have different names. "
+ "For conversion a default assignment is used which may not always be correct. "
+ "For this case you can change this individually with the option \"Adjust layer mapping\"."
+ "
"
+ "Conversion details: "
+ "
Names: "
+ "To follow EAGLE's naming conventions for different types of entities certain characters are replaced "
+ "by '_', in particular '(', ')', '[', ']', ''' and space. '\\\\' is replaced by '/'. " // 4 backslashes here ? Insane. Seems to be a bug in EAGLE.
+ "Control characters like '\\\\r' are not processed in a special way.
"
+ "
Texts: "
+ "All texts are converted to vectorfont in EAGLE. This allows a system independent "
+ "representation for polygon calculation and CAM processing. The font can be changed to fixed or "
+ "proportional where needed. All other text properties are taken over from ACCEL ASCII.
"
+ "
Pads and SMDs: "
+ "For pad and SMD types following conversion agreement is used: "
+ "Square pad/SMD -> SQUARE pad/SMD, "
+ "Rectangle pad -> SQUARE pad with additional rectangle polygon, "
+ "Oval pad -> LONG pad in EAGLE (size and shape of original and converted pads are slightly "
+ "different in this case), "
+ "Ellipse pad -> ROUND pad with additional approximation polygon consisting of four arcs, "
+ "Polygon pad -> SQUARE pad with additional polygon, "
+ "Round rectangle pad -> SQUARE pad and additional polygon with rounded corners, "
+ "Target pad -> ROUND pad, "
+ "Rectangle SMD -> rectangle SMD, "
+ "Oval SMD -> SMD with 100% roundness, "
+ "Ellipse SMD -> round SMD with additional approximation polygon consisting of four arcs, "
+ "Polygon SMD -> square SMD with additional polygon, "
+ "Round rectangle -> SMD with 25% roundness, "
+ "Target SMD -> SMD with 100% roundness.
"
+ "
Standalone pads (Free pads): "
+ "For standalone pads an appropriate library package is created in EAGLE.
"
+ "
Vias: "
+ "Vias are converted the following way to EAGLE: "
+ "Oval -> ROUND, Rectangle -> SQUARE, Ellipse -> ROUND, Round rectangle -> SQUARE and Target -> ROUND. "
+ "The sizes of the EAGLE vias are adjusted to fit within the shape of the ACCEL vias to avoid clearance issues.
"
+ "
Contacts / Routing: "
+ "In EAGLE coordinates of traces, pads, vias etc. have to match exactly in order to be properly routed. "
+ "Otherwise airwires are generated. In some other systems certain deviations are allowed."
+ "In other systems it's possible that a longer trace crosses a pad without connecting point. "
+ "In EAGLE this leads to an airwire to the next connecting point. In this case the trace needs to be splitted with "
+ "SPLIT command in order to create an additional connecting point at the pad position.
"
+ "
Copper polygons general: "
+ "In EAGLE there's only one type for hatched polygons (horizontal and vertical stripes)."
+ "The different possible hatch types in ACCEL ASCII like diagonal style for example, are all "
+ "converted to this. "
+ "Thermals within polygons are also always horizontal and vertical. There's no specific thermal spoke width "
+ "for each polygon, but a general value in the EAGLE design rules. "
+ "The removal of orphan property is converted to EAGLE but without threshold value (only on/off).
"
+ "
Copper polygons in poured state: "
+ "In EAGLE polygons are saved always in unpoured state. The pour state is calculated dynamically "
+ "by RATSNEST and depends on the parameters currently set.
"
+ "
Dimensions: "
+ "As the data model for dimensions in EAGLE is much simpler than in ACCEL ASCII some details are not mapped to EAGLE.
"
+ "
Labels: "
+ "Input, output and bidirectional labels are all converted to Xref labels in EAGLE.
"
+ "
Attributes for layers: "
+ "In EAGLE layers can't have attributes. This is skipped.
"
+ "
'zones' (in ACCEL schematic): "
+ "'zones' are not supported and skipped.
"
+ "
"
+ ,
+ "Allgemeines "
+ "ACCEL ASCII ist auch unter dem Namen TangoPRO ASCII, oder P-CAD ASCII bekannt. "
+ "Es kann von P-CAD, Altium Designer und PROTEL aus exportiert werden und ermöglicht so die "
+ "Konvertierung von Designs in diesen Formaten in EAGLE-Format. Von Altium Designer aus können nur "
+ "Boards in dieses Format exportiert werden. Für die Konvertierung in EAGLE ist Folgendes zu beachten: "
+ "Zunächst wird im Verzeichnis der Inputdatei eine EAGLE-Bibliothek gleichen Namens generiert, "
+ "die die verwendeten Bauteile enthält. Damit wird dann der gleichnamige EAGLE-Schaltplan oder das Board erstellt. "
+ "Da ACCEL-ASCII-Schaltpläne wie EAGLE teilweise die Endung \".sch\" haben, erhalten die EAGLE-Schaltpläne "
+ "die Endung \".eagle.sch\". "
+ "Die Konvertierung eines Schaltplans alleine macht wenig Sinn, da die Package-Information fehlt, "
+ "die für die Generierung eines Boards erforderlich wäre. "
+ "Aufgrund der verschiedenen Datenmodelle und der Mächtigkeit der Fremdsysteme und EAGLE sind der Konvertierung "
+ "Grenzen gesetzt. Idealerweise sollten bestimmte Fälle in den Originaldaten bereits vermieden werden. "
+ "Ansonsten sind gewisse Nachbearbeitungsschritte erforderlich. In jedem Fall sollten Sie nach dem Import einen "
+ "DRC durchführen, um eventuelle Schachstellen des Designs zu finden und zu beseitigen."
+ "
"
+ "Zuordnung der Layer "
+ "Je nach Herkunftssystem haben die Signal- Beschriftungs- und sonstigen Layerarten verschiedene Namen. "
+ "Für die Konvertierung wird eine gewisse Standard-Zuordnung angenommen, die jedoch nicht immer richtig sein muss. "
+ "Für diesen Fall können Sie über die Option \"Manuelle Layer-Zuordnung\" dies individuell einstellen."
+ "
"
+ "Details zur Konvertierung: "
+ "
Namen: "
+ "Um EAGLE's Namenskonventionen für verschiedene Objekttypen zu entsprechen, werden verschiedene Zeichen "
+ "durch '_' ersetzt, insbesondere '(', ')', '[', ']', ''' und Leerzeichen. '\\\\' wird ersetzt durch '/'. "
+ "Kontrollzeichen wie '\\\\r' werden nicht speziell behandelt.
"
+ "
Texte: "
+ "Alle Texte werden in Vektorfont konvertiert. Dies ermöglicht eine systemunabhängige "
+ "Darstellung für das Polygon-Freirechnen und die CAM-Verarbeitung. Die Schriftart kann auf Fixed oder "
+ "Proportional geändert werden wo nötig. Alle anderen Texteigenschaften werden aus ACCEL ASCII übernommen."
+ "
Pads und SMDs: "
+ "Für Pads und SMDs werden folgende Konvertierungsregeln verwendet: "
+ "Square Pad/SMD -> SQUARE Pad/SMD, "
+ "Rectangle Pad -> SQUARE Pad mit umgebendem rechteckigem Polygon, "
+ "Oval Pad -> LONG Pad (Größe und Form weichen leicht voneinander ab), "
+ "Ellipse Pad -> ROUND Pad mit umgebendem Approximation-Polygon aus 4 Kreisbögen, "
+ "Polygon Pad -> SQUARE Pad mit umgebendem Polygon, "
+ "Round rectangle Pad -> SQUARE Pad mit umgebendem Polygon mit Verrundungen, "
+ "Target Pad -> ROUND Pad, "
+ "Rectangle SMD -> rechteckiges SMD, "
+ "Oval SMD -> SMD mit 100% Roundness, "
+ "Ellipse SMD -> rundes SMD mit umgebendem Approximation-Polygon aus 4 Kreisbögen, "
+ "Polygon SMD -> quadratisches SMD with umgebendem Polygon, "
+ "Round rectangle -> SMD with 25% Roundness, "
+ "Target SMD -> SMD with 100% Roundness.
"
+ "
Standalone-Pads (Freie Pads): "
+ "Für Standalone-Pads wird ein entsprechendes Package in EAGLE erzeugt und verwendet.
"
+ "
Vias: "
+ "Vias werden folgendermaßen zu EAGLE konvertiert: "
+ "Oval -> ROUND, Rectangle -> SQUARE, Ellipse -> ROUND, Round rectangle -> SQUARE and Target -> ROUND. "
+ "Die Größen der EAGLE-Vias werden so gesetzt, dass sie in die Form der ACCEL-Vias hineinpassen, um Abstände einzuhalten.
"
+ "
Kontaktierung / Routen: "
+ "In EAGLE müssen die Koordinaten von Leiterbahnen, Pads, Vias etc. exakt aufeinander treffen, um als richtig geroutet "
+ "zu gelten, sonst entstehen Luftlinien. In manchen anderen Systemen sind gewisse Abweichungen zulässig. "
+ "Es kann in anderen Systemen vorkommen, daß eine längere Leiterbahn über einen Pad gelegt ist ohne einen Absetzpunkt. "
+ "Das erzeugt in EAGLE eine Luftlinie bis zum nächsten Absetzpunkt. In diesem Fall muß mit SPLIT die Leiterbahn gesplittet "
+ "werden, um einen zusätzlichen Absetzpunkt an der Pad-Position zu erzeugen.
"
+ "
Kupfer-Polygone allgemein: "
+ "In EAGLE gibt es nur einen Typ für schraffierte Polygone (horizontale und vertikale Streifen). "
+ "Die verschiedenen möglichen Schraffiertypen in ACCEL ASCII wie z.B. diagonale Schraffur werden alle "
+ "dazu konvertiert. "
+ "Thermalstege in den Polygonen verlaufen immer horizontal und vertikal. Es gibt keine spezifische "
+ "Thermalbreite für jedes Polygon, aber einen allgemeinen Wert in den Designregeln. "
+ "Die Orphan-Eigenschaft wird nach EAGLE konvertiert aber ohne Schwellwert (nur Orphans behalten/nicht behalten).
"
+ "
Kupfer-Polygone in freigerechnetem Zustand: "
+ "In EAGLE werden Polygone immer im Definitions-Zustand gespeichert (nicht freigerechnet). Das Freirechnen erfolgt "
+ "dynamisch durch RATSNEST und hängt von den aktuellen Parametern ab.
"
+ "
Bemaßungen: "
+ "Da das Datenmodell für Bemaßungen in EAGLE wesentlich einfacher ist als in ACCEL ASCII, werden einige Details "
+ "nicht in EAGLE abgebildet.
"
+ "
Labels: "
+ "Input- Output- und bidirektionale Labels werden alle in Xref-Labels in EAGLE konvertiert.
"
+ "
Attributes für Layer: "
+ "In EAGLE können Layer keine Attribute haben. Dies wird weggelassen.
"
+ "
'zones' (in ACCEL-Schaltplänen): "
+ "'zones' werden nicht unterstützt und daher weggelassen.
"
+ "
"
+ ,
+ "Общие замечания "
+ "ACCEL ASCII также известен как TangoPRO ASCII или P-CAD ASCII. "
+ "Он может быть экспортирован из Altium Designer, P-CAD и PROTEL. "
+ "Трансляция в EAGLE работает следующим образом: "
+ "В начале, в каталоге входного файла, создаётся библиотека EAGLE с тем же именем. "
+ "Она содержит компоненты, которые будут использованы в дальнейшем. Затем создаётся файл EAGLE с тем же именем, содержащий схему или топологию. "
+ "Для ACCEL ASCII файла схемы \".sch\", создаётся файл EAGLE \".eagle.sch\". "
+ "Преобразование схемы без платы не имеет смысла, так как отсутствует информация,"
+ "необходимая для создания платы."
+ "
"
+ "Присвоение значений слоям "
+ "В зависимости от исходной системы, типы сигналов, припой и другие слои имеют разные названия. "
+ "Соответствие слоёв, заданное по умолчанию, может быть изменено. "
+ "Для этого воспользуйтесь опцией \"Настройка соответствия слоёв\"."
+ "
"
+ "Различия и ограничения, возникающие при преобразовании "
+ "В связи с различными моделями данных и систем, преобразование имеет ограничения. "
+ "В идеале некоторые конфигурации следует избегать в исходных данных. "
+ "В противном случае потребуется постобработка. Это включает в себя, в частности: "
+ "
Имена: "
+ "Следуя соглашениям о именах в EAGLE следующие символы будут преобразованы "
+ "в '_': '(', ')', '[', ']', ''' и пробел. '\\\\' заменяется на '/'. " // 4 backslashes here ? Insane. Seems to be a bug in EAGLE.
+ "Управляющие символы, такие как '\\\\r' в строках не обрабатываются.
"
+ "
Текстовые строки: "
+ "Все текстовые строки преобразуются в векторный шрифт в EAGLE. Это даёт возможность "
+ "представить текст и использовать его для CAM обработки. Шрифт может быть изменен на фиксированный или "
+ "пропорциональный где это необходимо. Все остальные свойства шрифта сохраняются из ACCEL ASCII.
"
+ "
Pad и SMD: "
+ "Pad и SMD преобразуются следующим образом: "
+ "Square pad/SMD -> SQUARE pad/SMD, "
+ "Rectangle pad -> SQUARE pad с дополнительным прямоугольным полигоном, "
+ "Oval pad -> LONG pad в EAGLE (размер и форма отличаются в этом случае),"
+ " "
+ "Ellipse pad -> ROUND pad с дополнительным полигоном, аппроксимированным четыремя дугам, "
+ "Polygon pad -> SQUARE pad с дополнительным полигоном, "
+ "Round rectangle pad -> SQUARE pad с дополнительным полигоном с закругленными углами, "
+ "Target pad -> ROUND pad, "
+ "Rectangle SMD -> прямоугольный SMD, "
+ "Oval SMD -> SMD с 100% закругленностью, "
+ "Ellipse SMD -> ROUND SMD с дополнительным полигоном, аппроксимированным четыремя дугами, "
+ "Polygon SMD -> SQUARE SMD с дополнительным полигоном, "
+ "Round rectangle -> SMD с 25% закругленностью, "
+ "Target SMD -> SMD с 100% закругленностью.
"
+ "
Одиночные контактные площадки: "
+ "Для автономных контактных площадок в EAGLE создаются соответствующие библиотечные элементы.
"
+ "
Переходы: "
+ "Переходы преобразуются следующим образом: "
+ "Oval -> ROUND, Rectangle -> SQUARE, Ellipse -> ROUND, Round rectangle -> SQUARE and Target -> ROUND. "
+ "Размер перехода в EAGLE подбирается таким образом, чтобы исключить нарушение минимального технологического допуска.
"
+ "
Контакты / трассировка: "
+ "В EAGLE координаты проводов, контактных площадок, переходов и т.д. должны в точности совпадать с тем, чтобы быть правильно соединенными. "
+ "В противном случае создаются неподключенные соединения. В некоторых других системах допускаются отклонения.
"
+ "В других системах допускается если провод пересекает контактную площадку без подключения. "
+ "В EAGLE это приводит к созданию airwire к следующей точке цепи. В этом случае соединение должно быть разделено с помощью команды SPLIT "
+ "чтобы создать дополнительные соединительные точки. "
+ "
Преобразование заливки: "
+ "В EAGLE есть только один тип заливки (горизонтальных и вертикальных полос штриховки). "
+ "Различные возможные типы заливки в ACCEL ASCII, как, например, диагональный стиль, "
+ "преобразуется в этот. "
+ "Thermals в пределах полигона также всегда горизонтальные и вертикальные. Там нет конкретных тепловых ширин "
+ "для каждого полигона. Это значение задано в общих настройках EAGLE. "
+ "Удаление одиночных полигонов также преобразуется в EAGLE, но без порогового значения (только вкл / выкл). Li>"
+ "
>Преобразование полигонов заливки: "
+ "В EAGLE полигоны заливки всегда сохраняются в незалитом состоянии. Состояние заливки всегда вычисляется динамически "
+ "с помощью RATSNEST и зависит от текущих установленных параметров.
"
+ "
Линейки: "
+ "Поскольку модель данных в EAGLE существенно проще, чем в ACCEL ASCII некоторые детали линеек не преобразуются в EAGLE.
"
+ "
Знаки подключения: "
+ "Входные, выходные и двунаправленные знаки подключения преобразуются в знак Xref в EAGLE.
"
+ "
Атрибуты слоёв: "
+ "В EAGLE атрибуты слоёв не преобразуются.
"
+ "
'зоны' (в ACCEL принципиальной схеме): "
+ "'зоны' в принципиальной схеме не преобразуются
"
+ "This ULP generates a SCRIPT file that draws rectangles of successional pixels with identical color. "
+ "These rectangles serve as templates in order to draw the image with EAGLE commands like POLYGON, WIRE, CIRCLE, TEXT.
"
+ "Please note: If the generated rectangles are smaller than the half of the resolution of the output device, "
+ "(depending on the scale factor: screen: pixel, printer: diameter of the laser beam or ink jet dropplet), it is "
+ "not possible to display the result. Therefore use the EAGLE commands mentioned above to reduce the number of "
+ "elements (rectangles). Each element has to be drawn and calculated by the display device driver. The more elements "
+ "the slower the display will be. "
+ "The ULP accepts BitMaP files with a maximum of 256 colors. You are allowed to select a maximum of 32 of them. "
+ "[Scan used colors] detects the used number of colors in the image. You have to reduce them to a maximum of 32 "
+ "in the following dialog. "
+ "In the final dialog you can scale the image. Either in Dots per Inch (DPI), Pixel in the units Inch, "
+ "Mil, Millimeter, Micron, or as Aspect Ratio (the width of the image in pixels in X) in Inch, Mil, "
+ "Millimeter, Micron. "
+ "In the case of Aspect ratio, please keep in mind that there should not be pixels in a non-selected color on "
+ "the left or right boarder of the image. Otherwise the resulting width of the image is not the same as the calculated one. "
+ "The start layer for the template is set to 200. Each of the maximum of 32 selected colors will use a separate layer, "
+ "beginning with the start layer. So it is possible to have colored logos in the Schematic or Symbol Editor. "
+ "Reduce the number of colors of an image to two (black/white), if the logo shall be displayed monochrome in one of the copper "
+ "layers. As soon as the image (logo) is drawn with the EAGLE commands (see above) you may delete the template with GROUP DELETE "
+ "and a right mouse click. The layers can be removed with LAYER -number afterwards."
+ "
"
+ "Author: support@cadsoft.de
"
+ ,
+ "de:Importiert ein BitMaP-Bild als Vorlage in eine EAGLE-Zeichnung"
+ "
"
+ "Das ULP erzeugt eine SCRIPT-Datei, in der zusammenhängende gleichfarbige Pixel als Rechteck generiert werden. "
+ "Diese Rechtecke dienen als Vorlage, um das Bild mit EAGLE-Werkzeugen wie POLYGON, WIRE, CIRLE, TEXT zu definieren.
"
+ "Bedenken Sie: Wenn die erzeugten Rechtecke kleiner sind als die Hälfte der Auflösung des Ausgabegerätes"
+ "(je nach Skalierungsfaktor: Bildschirm-Pixel, Drucker-Laserstrahlbreite oder Düsendurchmesser), kann das Ergebnis "
+ "nicht dargestellt werden. Definieren Sie deshalb feine Strukturen mit den oben erwähnten Werkzeugen, um die "
+ "Anzahl der Elemente (Rechtecke) zu reduzieren. Jedes Element muss vom Grafikkartentreiber gezeichnet und "
+ "berechnet werden. Bei sehr vielen Elementen wird die Anzeige entsprechend verlangsamt. "
+ "Es werden nur BitMaP-Dateien mit maximal 256 Farben akzeptiert. Davon kann man bis zu 32 Farben auswählen. "
+ "Mit [Scan used colors] können die benutzten Farben im Bild ermittelt werden. Im folgenden Menue muss man sie "
+ "auf maximal 32 reduzieren. "
+ "Im abschliessenden Menue kann die Skalierung gewählt werden. Entweder Dots per Inch (DPI) oder Pixel in "
+ "der Maßeinheit Inch, Mil, Millimeter, Micron oder Aspect Ratio (die Breite des Bildes Pixel in X) in Inch, "
+ "Mil, Millimeter, Micron."
+ "Bei Aspect ratio sollte darauf geachtet werden, dass im Bild links und rechts keine Pixel in einer "
+ "nichtgewählten Farbe vorkommen. Ansonsten stimmt die Breite des Endergebnisses nicht mit der berechneten Breite überein. "
+ "Der Startlayer für die Vorlage ist der Layer 200. Für jede, der bis zu max. 32 gewählten Farben, wird ein neuer Layer, "
+ "beginnend mit dem Sartlayer, angelegt. So kann ein Logo im Schaltplan (Symbol) auch farbig definiert werden. "
+ "Reduzieren Sie eine BitMaP auf 2 Farben (schwarz/weiss), wenn das Ergebnis in nur einer Farbe für einen Kupferlayer "
+ "dargestellt werden soll. Ist das Bild (Logo) mit EAGLE-Werkzeugen (siehe oben) definiert, können mit GROUP DELETE und rechter "
+ "Maustaste die 'Rechtecke' wieder gelöscht werden. Die Layer selbst können dann mit LAYER -nummer entfernt werden."
+ "
"
+ "This ULP can import DXF files that include polylines. "
+ "Browse to the DXF file, setup your origins, input units, scale factor and linewidth then click convert. "
+ "The ULP will then show you the script in case you want to change the layer the input will be written to. "
+ "Tested in version 5, 6, 7. "
+ "author Written by Jorge Garcia of Cadsoft Computer, heavily based off of Hank Wallace's DXF2SCR program. "
+ "With special thanks to Robert Starr, Alfred Zaffran, Billy Coleman and Holger Moessinger."
+
+string Version = "1.7";
+
+string Help = "DXFimport "+Version+ "\n
This ULP will import a DXF \
+file into EAGLE (Board, Schematic, Package or Symbol-Editor). \
+Use the browse button to find the DXF file, make sure to set \
+the units to whatever units are used by the DXF file. Set the width, Xorg, and \
+Yorg in whatever units you selected. Then set an appropriate scale factor and \
+click the OK button, the generated script will be shown for editing. Once \
+it's adjusted to your liking click Run.
";
+
+/* *******************************************************************
+ REVISION HISTORY
+
+2012-03-03 Initial Release.
+
+2012-06-19 Finally incorporated Holger Moessinger's improvements to
+ the polygon import, added him to special thanks section.
+
+2012-07-10 Added support for LWPOLYLINE.
+
+2013-02-13 Check maximum coodinate of eagle, Alfred Zaffran. This
+ feature keeps track of the size of the DXF file, if it's
+ outside the drawing limits of EAGLE the ULP will recognize
+ this and suggest a corrective offset which the user can
+ approve.
+
+2013-06-12 Discovered that some files don't implement the proper
+ spacing so I modified the ULP to cope with that.
+
+2014-03-12 Implemented the ability to skip the section search state.
+ Some DXF files don't have an ENTITIES section which the old
+ ULP expected. This allows the ULP to try going through the
+ file again without expecting an ENTITIES section. The
+ downside is that some extraneous stuff may come in on the
+ import but usually the user will be able to tell and remove
+ those features. The generated script file has a comment
+ added to it when EAGLE uses that feature.
+
+2014-03-12 Assimilated Billy Coleman's scaling functionality. Added
+ him to the thank you list in the description.
+
+2014-03-13 Implemented a flag in the LWPOLYLINE state of dxf() to
+ make sure the state isn't exited, before processing the
+ object. Similar improvements where made in the VERTEX
+ state of DXF.
+
+2015-02-10 make target layer selectable alf@cadsoft.de
+
+********************************************************************* */
+
+/* ***********************************************************************
+Below I have retained Mr. Wallace's original "licensing" statement for two
+reasons:
+ 1. As a sign of respect for the original author of the code from which this
+ ULP was developed and without which it would have not been possible to
+ develop this ULP.
+ 2. This is quite possibly the funniest licensing statement any one will
+ ever read.
+
+Officially though, I will license this under the MIT open software license
+copied below:
+
+Copyright (c) 2012 Newark, Premier Farnell DBA Cadsoft Computer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to
+do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Jorge Garcia
+03-Mar-2012
+
+----------------------------------------------------------------------
+DXF2SCR.C
+
+Program that crunches a DXF file with circles, arcs and lines into an
+Eagle script file, useful for translating board outlines.
+
+Hank Wallace 20-Mar-03
+Revision 20-Mar-03
+
+There are two licensing options for this program:
+
+1. If you are a fan of the GNU license, and you think you
+understand it, and you think it is reasonable, and you believe
+that 'free to download' means 'high quality' or 'low maintenance
+cost', and you are a computer geek who cannot get a date who
+measures the value of his/her existence by the number of
+marginally useful command line options you can stuff into one
+program on a lonely Friday night, and you write C source code in
+such a manner that there are more #define'd constants and
+conditional compilation directives than there are actual C
+source statements, and you attempt to make your programs so
+'portable' that they runs on no machine whatsoever without
+modification, then you have no license to use this software. Get
+a life.
+
+2. If you one of the other 6 billion people on planet Earth,
+this program source code and executable is free for your use
+without restriction, but NO WARRANTY OR SUPPORT IS GIVEN.
+
+This program compiles under Microsoft's command line compiler, version 12.00.
+-----------------------------------------------------------------------------
+************************************************************************** */
+
+/* ************************************************************************
+* GLOBAL VARIABLES
+************************************************************************** */
+// #include "/home/cadsoft/eagle/debug.ulp"
+
+string ConfigFileName = filesetext(argv[0], ".cfg");
+
+real XMax; /* Maximum dimensions of DXF file */
+real YMax;
+real XMin;
+real YMin;
+real Exmax = REAL_MAX; /* Maximum dimensions EAGLE can draw in um */
+real Eymax = REAL_MAX;
+real Exmin = -REAL_MAX;
+real Eymin = -REAL_MAX;
+real S_factor;
+real GUI_scale = 1.0; /* Additional scale factor that can be used to resize dxf */
+int GUI_in_unit = 0;
+int GUI_scaled_Xorg = 0; /* Checkbox variables */
+int GUI_scaled_Yorg = 0;
+int GUI_scaled_lwidth = 0;
+string GUI_script;
+string GUI_fileName;
+real GUI_Xorg = 0.0;
+real GUI_Yorg = 0.0;
+real GUI_lwidth = 0.001;
+string GUI_layers[];
+ GUI_layers[0] = "select a layer";
+int GUI_layerselect = -1;
+int Lcnt = 1;
+int GUI_TargetLayer = 0;
+int SavedTargetLayer = 0;
+
+/*
+*******************************************************************************
+* NON-GUI FUNCTIONS
+*******************************************************************************
+*/
+
+/*
+*******************************************************************************
+* strcomp2()
+*
+* Description: The purpose of this function is to take the input scompare and
+* compare it to strings s1 and s2 for an exact match. If there is
+* no match to either string it will return -1, if there is a match
+* to one of the strings it will return the index of the
+* corresponding strstr function that succeeded.
+*
+* The strstr function checks to see if a substring shows up within
+* a given string, if it does it gives the index where the
+* substring shows up within the string. This is not enough to
+* ensure an exact match. To ensure an exact match we would need
+* the length of the strings to be the the same.
+*
+* Arguments: scompare String to be compared
+* s1 First item to match
+* s2 Second item to match
+*
+* Return: -1 If there is no match
+* int If there is a match corresponding to index of strstr
+* function that succeeded
+*
+* Caller: dxf
+*
+*******************************************************************************
+*/
+
+int strcomp2(string scompare, string s1, string s2) {
+ int result = strstr(scompare, s1);
+
+ if(result != -1 && strlen(scompare) == strlen(s1)) {
+ return result;
+ }
+ else {
+ result = strstr(scompare, s2);
+ if (result != -1 && strlen(scompare) == strlen(s2)) {
+ return result;
+ }
+ else {
+ return -1;
+ }
+ }
+}
+
+/*
+*******************************************************************************
+* mx() and my()
+*
+* Description: These functions below are used to find the extreme XY points of
+* the DXF file we're importing. This info will later be used to
+* make sure the file fits inside the drawing area of EAGLE. They
+* modify the drawing Max and Min variables in order to find the
+* size of the imported drawing
+*
+* Arguments: real Real x or y value
+*
+* Return: real The original x or y value that was passed
+*
+* Caller: dxf
+*
+*******************************************************************************
+*/
+
+real mx(real x) {
+ if (XMax < x) XMax = x;
+ if (XMin > x) XMin = x;
+ return x;
+}
+
+real my(real y) {
+ if (YMax < y) YMax = y;
+ if (YMin > y) YMin = y;
+ return y;
+}
+
+/*
+*******************************************************************************
+* dxf()
+*
+* Description: This function takes a DXF file path and processes it to produce
+* a script full of commands to draw the contents of the DXF file
+* in EAGLE.
+*
+* Arguments: dxffile Path to the DXF file to be processed
+* units Units of the DXF file
+* xorigin User defined offset in the X direction
+* yorigin User defined offset in the Y direction
+* liwidth User defined line width
+* ent Skips the search for sections and entities,
+* useful for files that don't strictly follow
+* the DXF format.
+* scale Optional scaling factor to increase or decrease
+* the size of the DXF file
+*
+* Return: string A long string full of EAGLE commands
+*
+* Caller: checkscript
+*
+*******************************************************************************
+*/
+
+string dxf(string dxffile, int units, real xorigin, real yorigin, real liwidth, int ent, real scale) {
+ string s[]; // This string array will store the DXF file
+ string out; // Out is the script generated by this function
+ string temp; // Place holder
+ enum { state_SECTION,
+ state_ENTITIES,
+ state_SEARCH,
+ state_LINE,
+ state_ARC,
+ state_CIRCLE,
+ state_POLYLINE,
+ state_VERTEX,
+ state_LWPOLYLINE}; // Defines states for the main state machine
+ enum { order_FIRST,
+ order_SECOND,
+ order_THIRD,
+ order_FOURTH,
+ order_FIFTH}; // Defines states for the secondary state machines
+ int i; // index variable for xa and ya
+ int p; // dummy variable for for loop
+ int m; // dummy variable for main while loop
+ int nlines; // number of lines in the text file
+ int state;
+ int order; // Used for internal state machines
+ int lines;
+ int arcs;
+ int circles;
+ int polylines;
+ int linewidth=1;
+ int LWPOLY_FLAG=1; // See comment in LWPOLYLINE state
+ real x;
+ real y;
+ real x1;
+ real y1;
+ real x2;
+ real y2;
+ real x3;
+ real y3;
+ real r;
+ real theta1;
+ real theta3;
+ real xorg;
+ real yorg;
+ real xa[]; // xa and ya arrays hold the possible vertexes of a polyline
+ real ya[];
+ real plclosed;
+ real bulgevalue[]; // plclosed and bulgevalue array helps in dealing with...
+ // ... closed polylines
+
+ if (units == 1) { // Setup unit scale factor
+ S_factor = 1000; // Convert mm to um
+ XMax = u2mm(INT_MIN)*S_factor;
+ YMax = u2mm(INT_MIN)*S_factor;
+ XMin = u2mm(INT_MAX)*S_factor;
+ YMin = u2mm(INT_MAX)*S_factor;
+ }
+ else {
+ S_factor = 25400; // Convert in to um
+ XMax = u2inch(INT_MIN)*S_factor;
+ YMax = u2inch(INT_MIN)*S_factor;
+ XMin = u2inch(INT_MAX)*S_factor;
+ YMin = u2inch(INT_MAX)*S_factor;
+ }
+
+ linewidth = liwidth * S_factor;
+ xorg = xorigin * S_factor;
+ yorg = yorigin * S_factor;
+ S_factor *= scale; // Added scale factor affects everything except xorg, ...
+ // ... yorg and linewidth those are handled by the GUI
+
+ out += "# dxfimport generated script file.\n";
+ out += "Grid mic 1 off;\n";
+ out += "Set Wire_Bend 2;\n";
+ sprintf(temp, "CHANGE LAYER %d;\n", GUI_TargetLayer); // 2015-02-10
+ out += temp;
+ out += "Change Font Vector;\n";
+
+ if (ent >= 1) { // Allows the section search to be disabled
+ state = state_SEARCH;
+ out += "# Skipped Section Search\n";
+ }
+ else {
+ state = state_SECTION;
+ }
+
+ order = order_FIRST;
+ lines = arcs = circles = polylines = 0;
+ nlines = fileread(s, dxffile);
+
+ for (m = 0;m < nlines;m++) {
+ switch (state) {
+ case state_SECTION: // scan for SECTIONS in the DXF file
+ if (strstr(s[m],"SECTION") != -1) {
+ if (ent >= 1) {
+ state = state_SEARCH;
+ }
+ else {
+ state = state_ENTITIES;
+ }
+ }
+ break;
+ case state_ENTITIES: // scan for ENTITIES in the DXF file
+ if (strstr(s[m],"ENDSEC") != -1) {
+ state = state_SECTION;
+ }
+ if (strstr(s[m],"ENTITIES") != -1) {
+ state = state_SEARCH;
+ }
+ break;
+ case state_SEARCH: // scanning for LINE, ARC, CIRCLE, POLYLINE, SPLINE
+ if (strstr(s[m],"ENDSEC") != -1) {
+ if (ent >= 1) {
+ state = state_SEARCH;
+ }
+ else {
+ state = state_SECTION;
+ }
+ }
+ if (strstr(s[m],"LINE") != -1 && strlen(s[m]) == 4) {
+ state = state_LINE;
+ lines++;
+ }
+ if (strstr(s[m],"ARC") != -1 && strlen(s[m]) == 3) {
+ state = state_ARC;
+ arcs++;
+ }
+ if (strstr(s[m],"CIRCLE") != -1 && strlen(s[m]) == 6) {
+ state = state_CIRCLE;
+ circles++;
+ }
+ if (strstr(s[m],"POLYLINE") != -1 && strlen(s[m]) == 8) {
+ i=0;
+ state = state_POLYLINE;
+ polylines++;
+ }
+ if (strstr(s[m],"LWPOLYLINE") != -1 && strlen(s[m]) == 10) {
+ i=0; // JG Support for LWPOLYLINE added 07/09/2012
+ state = state_LWPOLYLINE;
+ polylines++;
+ }
+ break;
+ case state_LINE: // absorbing LINE
+ switch(order) { // LINE 10, 20, 30 (start point), 11, 21, 31 (end point).
+ case order_FIRST:
+ if (strcomp2(s[m], " 10", "10") != -1) {
+ x = S_factor*strtod(s[m+1]);
+ order = order_SECOND;
+ }
+ break;
+ case order_SECOND:
+ if (strcomp2(s[m], " 20", "20") != -1) {
+ y = S_factor*strtod(s[m+1]);
+ order = order_THIRD;
+ }
+ break;
+ case order_THIRD:
+ if (strcomp2(s[m], " 11", "11") != -1) {
+ x1 = S_factor*strtod(s[m+1]);
+ order = order_FOURTH;
+ }
+ break;
+ case order_FOURTH:
+ if (strcomp2(s[m], " 21", "21") != -1) {
+ y1 = S_factor*strtod(s[m+1]);
+ sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(x+xorg),
+ my(y+yorg),
+ mx(x1+xorg),
+ my(y1+yorg)
+ );
+ out += temp; // Write to script
+ state = state_SEARCH;
+ order = order_FIRST;
+ }
+ break;
+ }
+ break;
+ case state_ARC: // absorbing ARC
+ switch(order) { // ARC 10, 20, 30 (center), 40 (radius), 50 (start angle), 51 (end)
+ case order_FIRST:
+ if (strcomp2(s[m], " 10", "10") != -1) {
+ x = S_factor*strtod(s[m+1]);
+ order = order_SECOND;
+ }
+ break;
+ case order_SECOND:
+ if (strcomp2(s[m], " 20", "20") != -1) {
+ y = S_factor*strtod(s[m+1]);
+ order = order_THIRD;
+ }
+ break;
+ case order_THIRD:
+ if (strcomp2(s[m], " 40", "40") != -1) {
+ r = S_factor*strtod(s[m+1]);
+ order = order_FOURTH;
+ }
+ break;
+ case order_FOURTH:
+ if (strcomp2(s[m], " 50", "50") != -1) {
+ theta1 = strtod(s[m+1]);
+ theta1 *= (PI/180);
+ order = order_FIFTH;
+ }
+ break;
+ case order_FIFTH:
+ if (strcomp2(s[m], " 51", "51") != -1) {
+ theta3 = strtod(s[m+1]);
+ theta3 *= (PI/180);
+
+ x1 = r*cos(theta1)+x; // compute Eagle arc parameters from DXF arc params
+ y1 = r*sin(theta1)+y;
+ x2 = x1-2*r*cos(theta1);
+ y2 = y1-2*r*sin(theta1);
+ x3 = r*cos(theta3)+x;
+ y3 = r*sin(theta3)+y;
+
+ sprintf(temp, "Arc CCW %d (%0.2f %0.2f) (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(x1+xorg),
+ my(y1+yorg),
+ mx(x2+xorg),
+ my(y2+yorg),
+ mx(x3+xorg),
+ my(y3+yorg)
+ );
+ out += temp;
+ state = state_SEARCH;
+ order = order_FIRST;
+ }
+ break;
+ }
+ break;
+ case state_CIRCLE: // absorbing CIRCLE
+ switch(order) { // CIRCLE 10, 20, 30 (center), 40 (radius).
+ case order_FIRST:
+ if (strcomp2(s[m], " 10", "10") != -1) {
+ x = S_factor*strtod(s[m+1]);
+ order = order_SECOND;
+ }
+ break;
+ case order_SECOND:
+ if (strcomp2(s[m], " 20", "20") != -1) {
+ y = S_factor*strtod(s[m+1]);
+ order = order_THIRD;
+ }
+ break;
+ case order_THIRD:
+ if (strcomp2(s[m], " 40", "40") != -1) {
+ y1 = S_factor*strtod(s[m+1]);
+ sprintf(temp, "Circle %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(x+xorg),
+ my(y+yorg),
+ mx(x+xorg),
+ my(y+y1+yorg)
+ );
+ out += temp;
+ state = state_SEARCH;
+ order = order_FIRST;
+ }
+ break;
+ }
+ break;
+ case state_POLYLINE: // absorbing POLYLINE
+ if (strstr(s[m], "VERTEX") != -1) { // VERTEX
+ state = state_VERTEX;
+ }
+ if (strcomp2(s[m], " 70", "70") != -1) { // EDIT HM 20120425: Determine if Polyline is closed and...
+ plclosed = strtod(s[m+1]); // ...take care of bulge values for line segments.
+ }
+ if (strstr(s[m], "SEQEND") != -1) {
+ for (p=0; p < i-1;p++) { // n points give n-1 lines that's why there's an i-1 in...
+ if (bulgevalue[p] != 0) { // ...the conditional
+ sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ (atan(bulgevalue[p])*180/PI*4),
+ mx(xa[p+1]+xorg),
+ my(ya[p+1]+yorg)
+ );
+ out += temp;
+ }
+ else {
+ sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ mx(xa[p+1]+xorg),
+ my(ya[p+1]+yorg)
+ );
+ out += temp;
+ }
+ }
+ if(plclosed) {
+ if(bulgevalue[p] != 0) {
+ sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ (atan(bulgevalue[p])*180/PI*4),
+ mx(xa[0]+xorg),
+ my(ya[0]+yorg)
+ );
+ out += temp;
+ }
+ else {
+ sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ mx(xa[0]+xorg),
+ my(ya[0]+yorg)
+ );
+ out += temp;
+ }
+ }
+ state = state_SEARCH;
+ }
+ break;
+ case state_VERTEX: // absorbing VERTEX
+ switch(order) {
+ case order_FIRST:
+ if (strcomp2(s[m], " 10", "10") != -1) { // 10 (x-value) 20 (y-value)
+ xa[i] = S_factor*strtod(s[m+1]);
+ order = order_SECOND;
+ }
+ break;
+ case order_SECOND:
+ if (strcomp2(s[m], " 20", "20") != -1) {
+ ya[i] = S_factor*strtod(s[m+1]); // This avoids a misalignment of the bulge array should...
+ bulgevalue[i] = 0; // ...one or more polylines not have bulges
+ order = order_THIRD;
+ }
+ break;
+ case order_THIRD:
+ if (strcomp2(s[m], " 42", "42") != -1) {
+ bulgevalue[i] = strtod(s[m+1]); //* Store bulge value for node
+ }
+ if (strcomp2(s[m], " 0", "0") != -1) {
+ i++;
+ state = state_POLYLINE; // Look for next vertex in polyline
+ order = order_FIRST;
+ }
+ break;
+ }
+ break;
+ case state_LWPOLYLINE: // absorbing LWPOLYLINE 07/09/2012
+ if (strcomp2(s[m], " 70", "70") != -1) { // Checks for closed polylines and imports them.
+ plclosed = strtod(s[m+1]);
+ }
+ if (strcomp2(s[m], " 42", "42") != -1) {
+ bulgevalue[i] = strtod(s[m+1]); // Store bulge value for node
+ }
+ if (strcomp2(s[m], " 10", "10") != -1) {
+ xa[i] = S_factor*strtod(s[m+1]);
+ }
+ if (strcomp2(s[m], " 20", "20") != -1) {
+ LWPOLY_FLAG = 0; // On poorly formated files, this state may run into an
+ // improperly formatted zero and exit without
+ // processing any points. This flag guarantees that
+ // the state will not be exited before points are
+ // processed. See the if statement below.
+ ya[i] = S_factor*strtod(s[m+1]);
+ bulgevalue[i] = 0;
+ i++; // This avoids a misalignment of the bulge array should
+ // one or more polylines not have bulges.
+ }
+ if (strcomp2(s[m], " 0", "0") != -1 & LWPOLY_FLAG == 0) {
+ for (p=0; p < i-1;p++) { // n points give n-1 lines that's why there's an i-1 in
+ if (bulgevalue[p] != 0) { // the conditional.
+ sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ (atan(bulgevalue[p])*180/PI*4),
+ mx(xa[p+1]+xorg),
+ my(ya[p+1]+yorg)
+ );
+ out += temp;
+ }
+ else {
+ sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ mx(xa[p+1]+xorg),
+ my(ya[p+1]+yorg)
+ );
+ out += temp;
+ }
+ }
+ if(plclosed) {
+ if(bulgevalue[p] != 0) {
+ sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ (atan(bulgevalue[p])*180/PI*4),
+ mx(xa[0]+xorg),
+ my(ya[0]+yorg)
+ );
+ out += temp;
+ }
+ else {
+ sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
+ linewidth,
+ mx(xa[p]+xorg),
+ my(ya[p]+yorg),
+ mx(xa[0]+xorg),
+ my(ya[0]+yorg)
+ );
+ out += temp;
+ }
+ }
+ state = state_SEARCH;
+ LWPOLY_FLAG = 1;
+ }
+ break;
+ }
+ }
+
+ sprintf(temp, "Window Fit;\n");
+ out += temp;
+ sprintf(temp, "# lines=%d, arcs=%d, circles=%d, polylines=%d\n",
+ lines,
+ arcs,
+ circles,
+ polylines
+ );
+ out += temp;
+ out += "Grid last;";
+ return out;
+}
+
+/*
+********************************************************************************
+* GUI FUNCTIONS
+********************************************************************************
+*/
+
+/*
+*******************************************************************************
+* get_project_path()
+*
+* Description: Returns project path, if in board or schematic, otherwise
+* it will return the library path
+*
+* Arguments: none
+*
+* Return: p String containing full path of project
+*
+* Caller: runscript
+*
+*******************************************************************************
+*/
+
+string get_project_path() {
+ string s = "", p = "";;
+ if (library) { library(L) s = L.name;}
+ if (board) { board(B) s = B.name;}
+ if (schematic){ schematic(S) s = S.name;}
+ char c = '/';
+ int pos = strrchr(s, c);
+ if (pos >= 0) {
+ p = strsub(s, 0, pos + 1);
+ }
+ return p;
+}
+
+/*
+*******************************************************************************
+* LoadConfigSettings()
+*
+* Description: Loads the most recent configuration settings.
+*
+* Arguments: none
+*
+* Return: none
+*
+* Caller: Main GUI code
+*
+*******************************************************************************
+*/
+
+void LoadConfigSettings() {
+ string lines[];
+ string rf[];
+
+ int nrf = fileglob(rf, ConfigFileName);
+
+ if (nrf) {
+ nrf = fileread(lines, rf[0]);
+ }
+ if (nrf == 7) {
+ int i = 0;
+ GUI_fileName = lines[i++];
+ GUI_Xorg = strtod(lines[i++]);
+ GUI_Yorg = strtod(lines[i++]);
+ GUI_scale = strtod(lines[i++]);
+ GUI_lwidth = strtod(lines[i++]);
+ GUI_in_unit = strtol(lines[i++]);
+ SavedTargetLayer = strtol(lines[i++]);
+ }
+}
+
+/*
+*******************************************************************************
+* SaveConfigSettings()
+*
+* Description: Saves the most recent configuration settings.
+*
+* Arguments: none
+*
+* Return: none
+*
+* Caller: runscript
+*
+*******************************************************************************
+*/
+
+void SaveConfigSettings() {
+ output(ConfigFileName, "wt") {
+ printf("%s\n", GUI_fileName);
+ printf("%f\n", GUI_Xorg);
+ printf("%f\n", GUI_Yorg);
+ printf("%f\n", GUI_scale);
+ printf("%f\n", GUI_lwidth);
+ printf("%d\n", GUI_in_unit);
+ printf("%d\n", GUI_TargetLayer);
+ }
+}
+
+/*
+*******************************************************************************
+* runscript()
+*
+* Description: This function writes the commands to a script file, and then
+* exits the ULP. Upon exit the command to run the script is
+* issued to EAGLE.
+*
+* Arguments: scr List of script commands
+*
+* Return: none
+*
+* Caller: checkscript
+*
+*******************************************************************************
+*/
+
+void runscript(string scr) {
+ string filepath = get_project_path() + "dxfimp.scr";
+ SaveConfigSettings();
+
+ output(filepath,"wt") {
+ printf(scr);
+ }
+
+ exit("SCRIPT '" + filepath + "'");
+}
+
+/*
+*******************************************************************************
+* checkscript()
+*
+* Description: This function checks if the DXF file will fit inside EAGLE's
+* drawing area and if not return helpful messages. Addtionally it
+* will display the generated script to the user for modifications
+* before the script is run.
+*
+* Arguments: none
+*
+* Return: none
+*
+* Caller: Main GUI code
+*
+*******************************************************************************
+*/
+
+void checkscript(void) { // This allows the user to inspect the script and make changes
+ real sc_xo = GUI_Xorg; // These allow the scale factor to be applied independently
+ real sc_yo = GUI_Yorg;
+ real sc_lw = GUI_lwidth;
+ string error;
+ if (!GUI_TargetLayer) {
+ dlgMessageBox("First select a layer!", "OK");
+ return;
+ }
+ if (GUI_scaled_Xorg == 1) {
+ sc_xo *= GUI_scale;
+ }
+ if (GUI_scaled_Yorg == 1) {
+ sc_yo *= GUI_scale;
+ }
+ if (GUI_scaled_lwidth ==1) {
+ sc_lw *= GUI_scale;
+ }
+ GUI_script =
+ GUI_script = dxf(GUI_fileName, GUI_in_unit, sc_xo, sc_yo, sc_lw, 0, GUI_scale);
+ string dummy[]; // Dummy array to check of dxf function returned valid data
+ if (strsplit(dummy, GUI_script, '\n') == 8) {
+ GUI_script = dxf(GUI_fileName,
+ GUI_in_unit,
+ sc_xo,
+ sc_yo,
+ sc_lw,
+ 1,
+ GUI_scale); // Run again without searching for sections
+ }
+ real Xdim = XMax - XMin; // Max dimensions of DXF file,must be defined after dxf runs
+ real Ydim = YMax - YMin;
+ real EXdim = Exmax - Exmin; // Max dimensions of EAGLE
+ real EYdim = Eymax - Eymin;
+
+ /* done = Debug(GUI_script); */
+
+ if ((Xdim > EXdim) || (Ydim > EYdim)) { // Checks if DXF file is larger than EAGLE's drawing area
+ dlgMessageBox(":DXF file is larger than EAGLE's drawing area please scale the file in your MCAD software and try again");
+ exit(-1);
+ }
+ if ((Xdim < Exmax) && (Ydim < Eymax)) { // Checks if DXF file is small enough to fit in the
+ // first quadrant (+X +Y)
+
+ if ((XMax > Exmax) || (YMax > Eymax) ||
+ (XMin < Exmin) || (YMin < Eymin)) { // Check if any of the points are outside of EAGLE's drawing area
+ GUI_Xorg = -1.0*(XMin/S_factor); // Lower left corner of DXF file will now be at 0 0
+ GUI_Yorg = -1.0*(YMin/S_factor); // Make sure we return the offset in original units
+ sprintf(error,":DXF file is outside of EAGLE's drawing area would you like to apply an offset in X of %.1f and %.1f in y?",
+ GUI_Xorg, GUI_Yorg);
+ if (dlgMessageBox(error, "Set offset", "CANCEL") != 0) exit(-1);
+ return;
+ }
+ }
+ else { // DXF file is too large to fit in first quadrant
+ if ((XMax > Exmax) || (YMax > Eymax) ||
+ (XMin < Exmin) || (YMin < Eymin)) { // Check if any of the points are outside of EAGLE's drawing area
+ GUI_Xorg = -1.0*(((XMin+XMax)/2)/S_factor); // Center of DXF file will now be at 0 0
+ GUI_Yorg = -1.0*(((YMin+YMax)/2)/S_factor);
+ sprintf(error,":DXF file is outside of EAGLE's drawing area would you like to apply an offset in X of %.1f and %.1f in y?",
+ GUI_Xorg, GUI_Yorg);
+ if (dlgMessageBox(error, "Set offset", "CANCEL") != 0) exit(-1);
+ return;
+ }
+ }
+
+ int Result = dlgDialog("Run Script") {
+ dlgTextEdit(GUI_script);
+ dlgHBoxLayout {
+ dlgPushButton("Run") runscript(GUI_script);
+ dlgPushButton("Cancel") dlgReject();
+ }
+ };
+}
+
+int gettargetlayer(int select) {
+ return strtol(GUI_layers[select]);
+}
+
+/*
+********************************************************************************
+* MAIN() *
+********************************************************************************
+*/
+LoadConfigSettings(); // load the last filename and config settings
+GUI_TargetLayer = 0;
+
+if (board) {
+ board(B) {
+ B.layers(L) {
+ if (L.name) {
+ sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name);
+ if (L.number == SavedTargetLayer) {
+ GUI_TargetLayer = L.number;
+ GUI_layerselect = Lcnt;
+ }
+ Lcnt++;
+ }
+ }
+ }
+}
+else if (schematic) {
+ schematic(SCH) {
+ SCH.layers(L) {
+ if (L.name) {
+ sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name);
+ if (L.number == SavedTargetLayer) {
+ GUI_TargetLayer = L.number;
+ GUI_layerselect = Lcnt;
+ }
+ Lcnt++;
+ }
+ }
+ }
+}
+else if (package || symbol) {
+ library(LIB) {
+ LIB.layers(L) {
+ if (L.name) {
+ sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name);
+ if (L.number == SavedTargetLayer) {
+ GUI_TargetLayer = L.number;
+ GUI_layerselect = Lcnt;
+ }
+ Lcnt++;
+ }
+ }
+ }
+}
+else {
+ dlgMessageBox("Start this ULP in a Schematic- or Board- or Package- or Symbol- Editor!", "OK");
+ exit(-1);
+}
+
+int main() {
+ string stateline = " ";
+ int Result = dlgDialog("DXFIMPORT - "+Version) {
+
+ dlgHBoxLayout {
+ dlgLabel(Help);
+ }
+ dlgHBoxLayout {
+ dlgLabel("File &name:");
+ dlgStringEdit(GUI_fileName);
+ dlgPushButton("Bro&wse") {
+ GUI_fileName = dlgFileOpen("Select a file", GUI_fileName, "*.dxf");
+ }
+ }
+
+ dlgHBoxLayout {
+ dlgLabel("Target layer ");
+ dlgComboBox(GUI_layers, GUI_layerselect) GUI_TargetLayer = gettargetlayer(GUI_layerselect);
+ dlgStretch(1);
+ }
+
+ dlgHBoxLayout {
+ dlgGroup("Input Units") {
+ dlgRadioButton("Imperial(in)", GUI_in_unit); // GUI_in_unit = 0
+ dlgRadioButton("Metric(mm)", GUI_in_unit); // GUI_in_unit = 1
+ }
+ dlgGridLayout {
+ dlgCell(0, 0) dlgLabel("Xorg");
+ dlgCell(1, 0) dlgLabel("Yorg");
+ dlgCell(0, 1) dlgRealEdit(GUI_Xorg);
+ dlgCell(1, 1) dlgRealEdit(GUI_Yorg);
+ dlgCell(2, 0) dlgLabel("Width");
+ dlgCell(2, 1) dlgRealEdit(GUI_lwidth);
+ dlgCell(3, 0) dlgLabel("Scale");
+ dlgCell(3, 1) dlgRealEdit(GUI_scale);
+ dlgCell(0, 2, 3, 2) {
+ dlgGroup("Scaled") {
+ dlgCheckBox("Xorg", GUI_scaled_Xorg); // If checked int contains 1, if unchecked 0
+ dlgCheckBox("Yorg", GUI_scaled_Yorg);
+ dlgCheckBox("Width", GUI_scaled_lwidth);
+ }
+ }
+ dlgCell(1, 3) dlgPushButton("OK") {
+ stateline = "converting file... please wait.";
+ dlgRedisplay();
+ checkscript();
+ stateline = " ";
+ dlgRedisplay();
+ }
+ dlgCell(2, 3) dlgPushButton("-Cancel") dlgReject();
+ }
+ }
+ dlgLabel(stateline, 1);
+ };
+ return Result;
+}
diff --git a/trunk/ulp/import-pads-powerpcb-v5.ulp b/trunk/ulp/import-pads-powerpcb-v5.ulp
new file mode 100644
index 00000000..418bf522
--- /dev/null
+++ b/trunk/ulp/import-pads-powerpcb-v5.ulp
@@ -0,0 +1,1369 @@
+#usage "Import PADS-POWERPCB-V5.0-BASIC! DESIGN DATABASE ASCII FILE 1.0
"
+ "RUN import-pads-powerpcb-v5.ulp "
+ "
"
+ "Author: alf@cadsoft.de"
+
+#require 6.0500
+
+string Version = "1.0.4"; // 2011-10-26
+ // 2012-06-25 option single-lbr to generate a library for each package
+ // 2012-10-08 pad count corrected, polygon corrected
+ // 2012-11-12 changed file handling
+ // 2013-09-11 no message if no .cfg file exist
+
+int test = 0;
+
+string UlpDefCfg = filesetext(argv[0], ".cfg");
+string ImpPADSSym = "";
+string EaglePADSLbrDir = "";
+string DirPADSAsc = "";
+string EaglePADSSchDir = "";
+int fn = 0;
+
+string LbrName;
+string FilePADSSym[];
+int cntFilePADSSym = 0;
+
+int Import_All_Symbols = 1;
+string ImportNames[];
+string ImportFNames[];
+int CntImpAll = 0; // In den Dateien kann es sein, dass der Name des Package
+ // nicht gleich dem Namen der Datei ist, und evtl. somit
+ // doppelt angelegt wird. 2011-11-08 alf
+
+int SingleLbr = 0; // Da es in der Definition der PADS-Dateien immer wieder den gleichen Namen
+ // für ein Package mit unterchiedlichen Paramtern gibt, kann man mit dieser
+ // Option für jedes Package eine eignen LBR anlagen, mit dem Namen der Quell-Datei.
+ // 2012-06-25 alf@cadsoft.de
+
+string SymDevName;
+string CmdDev;
+int CntPinname = 0;
+
+string PadsAscName;
+string FilePADSAsc[];
+int cntFilePADSAsc = 0;
+
+char Delimiter = '@';
+
+string ScriptFile = "";
+string ScriptExt = "~ltPADS~.scr";
+
+string PADS_Headerline;
+string Line[];
+int Cntl;
+int nline = 0;
+
+string Val[];
+int CntV;
+
+string Cmd, h;
+
+string Unit; // Grid-Einheit
+real Devider = 100000;
+
+string LineWidth;
+string PacInfo = "";
+// PADS header line for a package
+string PADSname; // PADS package name
+string PADSunits; // Grid
+int PADSx; // Package Origin x
+int PADSy; // Package Origin y
+int PADSpieces; // Gehäuse-Kontur
+int PADStermals; // PAD-Anzahl
+int PADSstacks;
+string PADStext;
+string PADSlabels; // Name + Value
+
+/*
+string UNITS; // Grid
+string ORIX; // Origin x
+string ORIY; // Origin y
+string PIECES; // Gehäuse-Kontur
+string TERMINALS;
+string STACKS;
+string TEXT;
+string LABELS; // Name + Value
+*/
+
+int Tcnt = 1; // Pad/Smd-Zähler
+string Tname[];
+real Tx1[], Ty1[], TxName[], TyName[]; // PAD/SMD-Koordinaten, nur die ersten beiden sind relevant laut Hr. Preissner
+real Tsizeidia[], Tsizelong[]; // Wird von PAD 0 vorgegeben,
+real Tfinlength[];
+string Tshape[];
+real Tangle[];
+int Troundness[];
+real Tdrill[];
+string Tplatet[];
+
+// Default PAD-Stack, wird durch Pad-Nummer 0 definiert
+int Stacklines; // Zähler für die Anzahl der Zeilen die den Pad-Stack definieren
+int Padstack0_level;
+real Padstack0_size;
+string Padstack0_shape;
+real Padstack0_finori;
+real Padstack0_idia;
+real Padstack0_finlength;
+real Padstack0_finoffset;
+int Padstack0_corner;
+real Padstack0_drill;
+int Padstack0_slotori;
+int Padstack0_slotlength;
+string Padstack0_plated;
+
+
+real SCALE; // SCALE 152.134 Scale of window expansion
+
+
+/*** ######## Functions ######## ***/
+void readconfig(void) { // read configuration file of ULP
+ string line[];
+ string f[];
+ int fn = fileglob(f, UlpDefCfg);
+ if (!fn) {
+ return;
+ }
+ int lines = fileread(line, UlpDefCfg);
+ for (int cl = 0; cl < lines; cl++) {
+ string s[];
+ int cnt = strsplit(s, line[cl], Delimiter);
+ if (s[0] == "EaglePADSLbrDir") EaglePADSLbrDir = s[1]; // "E:/EG/eg5 0/5.0_Projekte/LT-PADS/";
+ else if (s[0] == "EaglePADSSchDir") EaglePADSSchDir = s[1]; // "E:/EG/eg5 0/5.0_Projekte/LT-PADS/";
+ else if (s[0] == "ImpPADSSym") {
+ ImpPADSSym = s[1]; // "E:/Programme/LTC/LTPADSIV/lib/sym/";
+ FilePADSSym[0] = ImpPADSSym;
+ }
+ else if (s[0] == "DirPADSAsc") {
+ DirPADSAsc = s[1]; //"E:/Programme/LTC/LTPADSIV/"
+ FilePADSAsc[0] = DirPADSAsc;
+ }
+ else if (s[0] == "Import_All_Symbols") Import_All_Symbols = strtol(s[1]);
+ else if (s[0] == "SingleLbr") SingleLbr = strtol(s[1]); // 2012-06-25
+ }
+ return;
+}
+
+
+void saveconfig(void) {
+ output(UlpDefCfg, "wt") {
+ printf("EaglePADSLbrDir%c%s\n", Delimiter, EaglePADSLbrDir);
+ printf("ImpPADSSym%c%s\n", Delimiter, ImpPADSSym);
+ printf("EaglePADSSchDir%c%s\n", Delimiter, EaglePADSSchDir);
+ printf("DirPADSAsc%c%s\n", Delimiter, DirPADSAsc);
+ printf("Import_All_Symbols%c%d\n", Delimiter ,Import_All_Symbols);
+ printf("SingleLbr%c%d\n", Delimiter, SingleLbr);
+ }
+}
+
+
+int checkexist_pac(string name) {
+ if (library) {
+ library(L) {
+ L.packages(P) {
+ if (P.name == name) return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+int checkexist_sym(string name) {
+ if (library) {
+ library(L) {
+ L.symbols(S) {
+ if (S.name == name) return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+// wenn alle Dateien eines Verzeichnis eingelesen werden,
+// dann überprüfe ob das Package/Symbol schon angelegt wird.
+// In den Package-Dateien von LT-Spice werden einige Packages doppelt
+// angelegt. Der Dateiname entspricht nicht dem Namen der in der
+// Datei angegeben ist! 2011-11-07 alf@cadsoft.de
+int check_double_defined(string name, string fname) {
+ if(SingleLbr) return 0; // 2012-06-25
+ int found = 0;
+ for (int n = 0; n < CntImpAll; n++) {
+ if (ImportNames[n] == name) return 1;
+ }
+ ImportNames[CntImpAll] = name;
+ ImportFNames[CntImpAll] = name+ "\t" + fname;
+ CntImpAll++;
+ return 0;
+}
+
+
+string del_double_space(string l) {
+ string s[];
+ int cnt = strsplit(s,l, ' ');
+ string l1 = "";
+ for (int i = 0; i < cnt; i++) {
+ if (s[i]) l1+= s[i] + " ";
+ }
+ return l1;
+}
+
+/***
+void getunit(string l) {
+ if (l == "I") {
+ Unit = "MIL";
+ Devider = 100000;
+ }
+ else if (l == "M") {
+ Unit = "MM";
+ Devider = 100000;
+ }
+ return;
+}
+***/
+
+//LINEWIDTH 3810000 Width items will be created with
+void linewidth(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ sprintf(LineWidth , "CHANGE WIDTH %.6f;\n", strtod(s[1]) / Devider);
+ return;
+}
+
+
+void imp_font(string l) { // do nothing
+ return;
+}
+
+
+// MSOP08 I 22418040 18497550 1 8 1 0 2
+// MSOP08 == name | User-defined decal name. The alphanumeric string can be
+// up to 40 characters long
+// I == units | Units used for this part decal. Valid values are:
+// I Imperial units, given in mils
+// M Metric units, given in mm
+// 22418040 18497550 == x y | kann im Package-Editor ignoriert werden
+// Coordinates where the symbol is placed when viewed in the Decal
+// Editor. You can ignore this data when reading in ASCII files. If
+// copying the data, simply preserve the values from the input field. Use
+// the values 1000, 1000 if you are creating this data.
+// 1 == pieces | Number of drawing outline items that make up the part decal.
+// Valid values range from 0 to 32767. A definition follows each piece entry
+// 8 == terminals | Number of terminals that make up the part decal. Valid values range
+// from 0 to 32767. A definition follows each entry.
+// 1 == stacks | Number of unique pad stack descriptions that define the terminals
+// within the decal. A definition follows each entry
+// 0 == text (optional) | Number of text strings associated with the decal item. Valid values
+// range from 0 to 32767.
+// 2 == labels (optional) | Number of attribute labels associated with the decal item.
+//
+// Valid values range from 0 to 32767
+
+//DFN(06)2MMX2MM M 0 0 2 7 2 0 2
+//*REMARK* NAME UNITS ORIX ORIY PIECES TERMINALS STACKS TEXT LABELS
+/***
+Ppcb_ASCII.pdf : PADS Layout ASCII Format Specification : Seite 31
+
+name | User-defined decal name. The alphanumeric string can be up to 40
+ characters long.
+
+units | Units used for this part decal. Valid values are:
+ I Imperial units, given in mils
+ M Metric units, given in mm
+
+x and y | Coordinates where the symbol is placed when viewed in the Decal
+ Editor. You can ignore this data when reading in ASCII files. If
+ copying the data, simply preserve the values from the input field. Use
+ the values 1000, 1000 if you are creating this data.
+
+pieces | Number of drawing outline items that make up the part decal. Valid
+ values range from 0 to 32767. A definition follows each piece entry.
+
+terminals | Number of terminals that make up the part decal. Valid values range
+ from 0 to 32767. A definition follows each entry.
+
+stacks | Number of unique pad stack descriptions that define the terminals
+ within the decal. A definition follows each entry.
+
+text (optional) | Number of text strings associated with the decal item. Valid values
+ range from 0 to 32767.
+
+labels(optional) | Number of attribute labels associated with the decal item. Valid values
+ range from 0 to 32767.
+
+***/
+int imp_pac_name(string l) { // start parsing
+ if (Tcnt > 1) { dlgMessageBox("Tcnt stimmt nicht!", "ok", "esc"); exit(-295); }
+ Tcnt = 1; // reset Tcnt;
+ string s[];
+ int n = strsplit(s, l, ' ');
+ PADSname = s[0];
+ PADSunits = s[1];
+ PADSx = strtol(s[2]) / Devider;
+ PADSy = strtol(s[3]) / Devider;
+ PADSpieces = strtol(s[4]);
+ PADStermals = strtol(s[5]);
+ PADSstacks = strtol(s[6]);
+ PADStext = s[7];
+ PADSlabels = s[8];
+
+ sprintf(PacInfo, "%s\nname %s\nunits %s\nx %d\ny %d\npieces %d\ntermals %d\nstacks %d\ntext %s\nlabel %s",
+ l,
+ PADSname,
+ PADSunits,
+ PADSx,
+ PADSy,
+ PADSpieces,
+ PADStermals,
+ PADSstacks,
+ PADStext,
+ PADSlabels
+ );
+
+ if (test) {
+ if (dlgMessageBox(PacInfo, "ok", "esc") != 0) exit(-324);
+ }
+
+ if (checkexist_pac(strupr(s[0]))) {
+ sprintf(h, "! Package %s.PAC exist.\nDelete the package?", l);
+ if (dlgMessageBox(h, "YES", "NO") != 0) return 1;
+ sprintf(h, "SET CONFIRM YES;\nREMOVE %s.PAC;\nSET CONFIRM OFF;\n", s[0]);
+ Cmd += h;
+ }
+ if (check_double_defined(s[0], FilePADSSym[fn])) {
+ int sel;
+ int srt = 0;
+ sprintf(h, "second definition of %s in %s", s[0], filename(FilePADSSym[fn]));
+ dlgDialog("Import PADS library") {
+ dlgHBoxLayout dlgSpacing(400);
+ dlgStringEdit(h);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(400);
+ dlgListView("Package\tFile", ImportFNames, sel, srt);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("CANCEL") { dlgReject(); exit(-346); }
+ dlgStretch(1);
+ }
+ };
+ }
+ //getunit(PADSunits); // Das Grid des Package
+ if (s[1] == "I") {
+ Unit = "MIL"; // das benutzte Grid
+ Devider = 100000;
+ }
+ else if (s[1] = "M") {
+ Unit = "MM"; // das benutzte Grid
+ Devider = 1000000;
+ }
+ sprintf(h, "EDIT %s.PaC;\nGRID %s;\n", s[0], Unit); // der Package-Name und die Masseinheit
+ Cmd += h;
+ Cmd += "CHANGE STYLE Continuous;\n";
+ Cmd += LineWidth;
+ sprintf(h, "DESCRIPTION 'Package generated from: %s (%s)
\\n\\nwith :%s Version %s at %s';\n",
+ filename(FilePADSSym[fn]), Line[0], filename(argv[0]), Version, t2string(time())
+ );
+ Cmd+=h;
+ return 0;
+}
+
+
+/*****************************/
+string imp_arc(string l) { // 2012-10-08
+ /*
+ *REMARK* XLOC YLOC BEGINANGLE DELTAANGLE
+
+ COPCLS 9 299850 1 28
+ -2250000 330000 1800 900 -2250000 180000 -1950000 480000
+ -2100000 180000
+ 2100000 180000 2700 900 1950000 180000 2250000 480000
+ 2250000 330000
+ 2250000 2850000 0 900 1950000 2700000 2250000 3000000
+ 2100000 3000000
+ -1800000 3000000 44 -900 -2776440 2473560 -1798560 3451440
+ -2250000 2475000
+ -2250000 330000
+
+ # COPCLS 9 ist ein Polygon mit 9 Teillinien bzw. Bögen
+ # 28 ist der 28. Pad von 0 gezählt Beispiel "QFN36(UHE).asc"
+
+ Definition des ARC:
+ Die Koordinaten e/f und g/h definieren die zwei diagonalen Ecken eines umschließenden
+ Rechteck um einen Kreis. Die Mitte dieses Rechteck ist der Mittelpunkt des Kreises,
+ und somit der Mittelpunkt des ARC.
+ Die Koordinate a/b ergibt den Startpunkt des Kreisbogen, und sollte dem Startwinkel c,
+ bezogen auf den Mittelpunkt des zuvor definierten Kreises entsprechen.
+ d ist der Bogenwinkel, also das Ende des ARC in Grad, bezogen auf den Startwinkel.
+ 2011-11-14
+
+ Aus der PDF-Dokumentation: Ppcb_ASCII.pdf / PADS Layout ASCII Format Specification / PADS 9.0
+ Arc corner format:
+ x1 y1 ab aa ax1 ay1 ax2 ay2
+ Format Description:
+ x1 y1 Beginning of the arc
+ ab Beginning angle of the arc in tenths of a degree
+ aa Number of degrees in the arc in tenths of a degree
+ ax1, ay1 Lower left point of the rectangle around the circle of the arc
+ ax2, ay2 Upper right point of the rectangle around the circle of the arc
+ ax2 ax1 = ay2 ay1 Diameter of the circle of the arc
+ (ax1 + ax2)/2, (ay1 + ay2)/2 Coordinates of the center of the arc circle
+ */
+ string s[];
+ int n = strsplit(s, l, ' ');
+
+ real startcoordx = strtod(s[0]) / Devider;
+ real startcoordy = strtod(s[1]) / Devider;
+ real startangle = strtod(s[2]) * 0.1;
+ real diffangle = strtod(s[3]) * 0.1;
+ string arc;
+ sprintf(arc, " (%.8f %.8f) %+.1f ",
+ startcoordx, startcoordy,
+ diffangle
+ );
+ return arc;
+}
+
+/**************************************/
+string get_coordinat(string l) {
+ string s[];
+ string k, m;
+ int n = strsplit(s, l, ' ');
+ if (n > 2) {
+ k = imp_arc(l);
+ }
+ else {
+ sprintf(k, " (%.6f %.6f)", strtod(s[0]) / Devider, strtod(s[1]) / Devider);
+ }
+ k += "\\\n";
+ return k;
+}
+
+
+// CLOSED 9 304800 0
+// CLOSED == type
+// 9 == level
+// == pinnum
+// == restrictions
+void imp_closed_line(string l) {
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ sprintf(h, "# imp_closed_line %s \n", s[1]);
+ Cmd += h;
+ sprintf(h, "SET wIRE_BEND 2;\nCHANGE LAYER 21;\nWIRE %.4f \\\n", strtod(s[2]) / Devider);
+ Cmd += h;
+ for (int p = 1; p <= strtod(s[1]); p++) {
+ Cmd += get_coordinat(del_double_space(Line[++nline]));
+ }
+ Cmd += ";\n";
+ return;
+}
+
+
+// OPEN 3 381000 0
+// OPEN == type
+// 3 == level
+// == pinnum
+// == restrictions
+/*
+OPEN 6 304800 1
+-1500000 2250000
+-1500000 952500
+-1143000 952500
+-1143000 -952500
+-1500000 -952500
+-1500000 -2250000
+*/
+void imp_open_line(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ sprintf(h, "# imp_open_line() %s \n", s[1]);
+ Cmd += h;
+ Cmd += "# LAYeR "+s[3]+"\n";
+ sprintf(h, "SET WiRE_BEND 2;\nCHANGE LAYER 21;\nWIRE %.4f \\\n", strtod(s[2]) / Devider);
+ Cmd += h;
+ for (int p = 1; p <= strtod(s[1]); p++) {
+ Cmd += get_coordinat(del_double_space(Line[++nline]));
+ }
+ Cmd += ";\n";
+ return;
+}
+
+/*
+COPCLS 9 381000 1 1
+-647700 -4000500
+-647700 -1219200
+-1276350 -1219200
+-1276350 2781300
+1276350 2781300
+1276350 -1219200
+647700 -1219200
+647700 -4000500
+-647700 -4000500
+*/
+void imp_copcls(string l) { // Copper Closed?
+ Cmd+="# imp_copcls()\n";
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ sprintf(h, "# imp_imp_copcls %s \n", s[1]);
+ Cmd += h;
+ sprintf(h, "SET WIrE_BEND 2;\nCHANGe LAYER 1;\nChange width %.6f;\n", strtod(s[2]) / Devider);
+ Cmd += h;
+ string cmdpol;
+ sprintf(cmdpol, "POLYGOn ");
+ for (int p = 1; p <= strtod(s[1]); p++) {
+ cmdpol += get_coordinat(del_double_space(Line[++nline]));
+ }
+ cmdpol += ";\n";
+ Cmd += cmdpol; // Kupferpolygon = PAD-Erweiterung
+ sprintf(h, "CHANGE LAYER 29;\nCHANGE WIDTH %.6f;\n", strtod(s[2]) / Devider * 1.2); // Stop-Maske
+ Cmd += h;
+ Cmd += cmdpol; // Kupferpolygon = PAD-Erweiterung
+ sprintf(h, "CHANGE LAYER 31;\nCHANGE WIDTH %.6f;\n", strtod(s[2]) / Devider / 2); // Cream-Maske
+ Cmd += h;
+ Cmd += cmdpol; // Kupferpolygon = PAD-Erweiterung
+ return;
+}
+
+
+/*
+CIRCLE 2 266700 1
+-3429000 -1333500
+-2476500 -1333500
+*/
+void imp_circle(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ //int cntcircle = strtol(s[1]);
+ sprintf(h, ";\nCIRCLE %.6f ", strtod(s[2]) / Devider);
+ Cmd += h;
+ strsplit(s, Line[++nline], ' ');
+ sprintf(h, " (%.6f %.6f)", strtod(s[0]) / Devider, strtod(s[1]) / Devider);
+ Cmd += h;
+ strsplit(s, Line[++nline], ' ');
+ sprintf(h, " (%.6f %.6f);\n", strtod(s[0]) / Devider, strtod(s[1]) / Devider);
+ Cmd += h;
+ return;
+}
+
+
+void imp_copopn(string l) {
+ /*
+ COPOPN 2 190500 21
+ -41405025 3333750
+ -41405025 5333250
+ */
+ string s[];
+ real width, x1, x2, y1, y2, dx, dy;
+
+ int n = strsplit(s, l, ' ');
+
+ if (s[1] == "2") {
+ width = strtod(s[2]) / Devider;
+ if (s[3] == "21") {
+ Cmd += "CHa LAYER 1; # "+s[3]+"\n";
+ }
+ else if (s[3] == "28") {
+ Cmd += "CH LAYER 16; # "+s[3]+"\n";
+ }
+ else {
+ sprintf(h, "Layer unknown %s in line %d", s[3], nline);
+ if (dlgMessageBox(h, "ok", "esc") != 0) exit(-578);
+ }
+ strsplit(s, Line[++nline], ' ');
+ x1 = strtod(s[0]) / Devider;
+ y1 = strtod(s[1]) / Devider;
+
+ strsplit(s, Line[++nline], ' ');
+ x2 = strtod(s[0]) / Devider;
+ y2 = strtod(s[1]) / Devider;
+ sprintf(h, "# imp_copopn() 734\nSMD '%d' %.6f %.6f (%.6f %.6f);\n", Tcnt, x2-x1+width+2, y2-y1+width+2, (x1+x2) / 2, (y1+y2) / 2);
+ Cmd += h;
+ Tcnt++; // Pad counter
+ }
+ else {
+ sprintf(h, "unklnown parameter counter %s in Line %d", s[2], nline);
+ if (dlgMessageBox(h, "ok", "esc") != 0) exit(-593);
+ }
+ return;
+}
+
+void imp_copcut(string l) {
+ Cmd += "# imp_copcut()\n";
+ dlgMessageBox(FilePADSSym[fn]+ "\n\nCUTCUP", "?");
+ exit(-601);
+ return;
+}
+
+void imp_copcco(string l) {
+ Cmd += "# copcco\n";
+ dlgMessageBox(FilePADSSym[fn]+ "\n\nCOPCCO", "?");
+ exit(-608);
+ return;
+}
+
+void imp_copcir(string l) { // Copper Circle?
+ Cmd += "# copcir\n";
+ dlgMessageBox(FilePADSSym[fn]+ "\n\nCOPCIR", "?");
+ exit(-615);
+ return;
+}
+
+void imp_kptcls(string l) {
+ Cmd += "# kptcls\n";
+ dlgMessageBox(FilePADSSym[fn]+ "\n\nKTPCLS", "?");
+ exit(-622);
+ return;
+}
+
+void imp_cptcir(string l) {
+ Cmd += "# cptcir\n";
+ dlgMessageBox(FilePADSSym[fn]+ "\n\nKPRCIR", "?");
+ exit(-629);
+ return;
+}
+
+void imp_tag(string l) {
+ Cmd += "# Tag\n";
+ dlgMessageBox(FilePADSSym[fn]+ "\n\nTAG", "?");
+ exit(-636);
+ return;
+}
+
+
+/*
+VALUE -1800000 -450000 0.000 1 1905000 190500 N LEFT DOWN
+Ref.Des.
+*/
+void imp_ref_des(string l) {
+
+ real offsety;
+ if (Val[9] == "DOWN") offsety = 0.0;
+ else if (Val[9] == "UP") {
+ if (Unit == "MM") offsety = -1.778;
+ else if (Unit == "MIL") offsety = -70.0;
+ }
+
+ sprintf(h, ";\nCHANGE SIZE 70mil;\nCHANGE LAYER 27;\nTEXT '>NAME' R%.1f (%.6f %.6f);\n",
+ strtod(Val[3]), strtod(Val[1]) / Devider, strtod(Val[2]) / Devider + offsety
+ );
+ Cmd += h;
+ return;
+}
+
+
+/*
+VALUE 0 0 0.000 1 1905000 190500 N LEFT UP
+Part Type
+VALUE -1800000 -450000 0.000 1 1905000 190500 N LEFT DOWN
+Ref.Des.
+*/
+void imp_value(string l) {
+
+ //int cntv = 0;
+ string s[];
+ int n = strsplit(s, l, ' ');
+ CntV = 0;
+ for (int i = 0; i < n; i++) {
+ if(s[i]) {
+ Val[CntV++] = s[i];
+ }
+ }
+ return;
+}
+
+
+/*
+VALUE 0 0 0.000 1 1905000 190500 N LEFT UP
+Part Type
+*/
+void imp_part_type(string l) {
+
+ real offsety ;
+ if (Val[9] == "DOWN") offsety = 0.0;
+ else if (Val[9] == "UP") {
+ if (Unit == "MM") offsety = -1.778;
+ else if (Unit == "MIL") offsety = -70.0;
+ }
+ sprintf(h, ";\nCHANGE LAYER 25;\nCHANGE SIZE 70mil;\nTEXT '>VALUE' R%.1f (%.6f %.6f);\n",
+ strtod(Val[3]), strtod(Val[1]) / Devider, strtod(Val[2]) / Devider + offsety
+ );
+ Cmd += h;
+ return;
+}
+
+
+/***
+T-1463040 -3257550 -1644015 -3333750
+T-487680 -3257550 -487680 -3257550
+T487680 -3257550 487680 -3257550
+T1463040 -3257550 1463040 -3257550
+T1463040 3257550 1463040 3257550
+T487680 3257550 487680 3257550
+T-487680 3257550 -487680 3257550
+T-1463040 3257550 -1463040 3257550
+PAD 0 3
+***/
+
+/*** !PADS-POWERPCB-V9.3-BASIC! DESIGN DATABASE ASCII FILE 1.0
+T-2625000 -3225000 -2625000 -3225000 1
+T-1875000 -3225000 -1875000 -3225000 2
+T-1125000 -3225000 -1125000 -3225000 3
+T-375000 -3225000 -375000 -3225000 4
+***/
+
+void imp_tcoord(string l) { // 2012-10-08 Tcnt ist der Zähler und Pointer selbst
+ l[0] = ' '; // replace T with space
+ string s[];
+ int n = strsplit(s, l, ' ');
+ int padnum = strtol(s[5]); // PADS-Version 9 gibt auch Namen aus. 2012-05-25
+ Tx1[Tcnt] = strtod(s[1]) / Devider; // pad coodicnate
+ Ty1[Tcnt] = strtod(s[2]) / Devider; // pad coordinate
+ TxName[Tcnt] = strtod(s[3]) / Devider; // name coodinate
+ TyName[Tcnt] = strtod(s[4]) / Devider; // name coodinate
+ Tname[Tcnt] = s[5];
+ Tcnt++;
+ if (Tcnt-1 > PADStermals) {
+ string h;
+ sprintf(h, "%s\n%s:\n%s\n%d more then %d pads defined!", PacInfo, FilePADSSym[fn], l, Tcnt, PADStermals);
+ if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-736);
+ }
+ return;
+}
+
+
+//PAD 0 3
+//-2 457200 RF 90.000 2286000 0 0
+//-1 0 R
+//0 0 R
+
+// PAD == Keyword
+// 0 == pinno | Terminal number to which the pad stack applies. A value of 0 indicates all
+// pads except those explicitly listed later
+// 3 == stacklines | Number of lines of information pertaining to the pin numbers. The
+// minimum number of entries is 3: top layer, inner layer, and bottom layer
+//
+// -2 == level | Layer number being defined. Valid values are:
+// -2 Top layer
+// -1 Inner layer
+// 0 Bottom layer
+// 1 to 250 Specific layer number
+// 457200 == size | Diameter of the pad for round, odd, and annular pads. Length of a side for
+// square pads. Width of oval or rectangular pads
+// RF == shape | Pad shape. Valid values are:
+// R Round
+// S Square
+// A Annular
+// O Odd
+// OF Oval finger
+// RF Rectangular finger (SMD)
+// RT - Thermal pad for a round pad shape
+// ST - Thermal pad for square pad shape
+// 90.000 == finori | Orientation, in degrees, of oval or rectangular pads. Precision is three
+// digits after the decimal point. Valid values range from 0 to 179.999. If
+// the pad is not oval or rectangular, this field is omitted
+// 2286000 == idia | Inner diameter of an annular pad. If the pad is not annular, this field is omitted.
+// 0 == finlength | Finger length of oval or rectangular pads. Valid values range from +1 to
+// 1000. If the pad is not oval or rectangular, this field is omitted.
+// 0 == finoffset | Offset of the finger of oval or rectangular pads from the electrical center
+// (drill). For fingers with a 0 degree orientation, a positive offset shifts the
+// pad from the electrical center to the right. For fingers with a 90 degree
+// orientation, a positive offset shifts the pad from the electrical center up.
+// Offset values must lie within the pad, and may not be greater than 500. If
+// the pad is not oval or rectangular, this field is omitted.
+//
+// == corner | This field stores the numerical corner radius value and is used to
+// support pads with rounded and chamfered corners. It only exists for
+// square and rectangular finger pad shapes. Zero value is used for 90
+// degree (non-rounded) pad corners; positive value is used for pads with
+// rounded corners; negative value is used for pads with chamfered
+// corners.
+// == drill | Drill size. Valid values range from 0 to 1000. drill only appears on the
+// side where parts are mounted.
+// == plated | If this is N, the drill hole is unplated. If this is P or empty, the drill is
+// plated. plated only appears on the side where parts are mounted.
+// == slotori | Orientation, in degrees, of the slotted drill. Precision is three digits after
+// the decimal point. Valid values range from 0 to 179.999.
+// == slotlength | Length of the slotted drill. Valid values range from +1 to 1000.
+
+/*
+PAD 7 3
+-2 915000 RF 0.000 2130000 0 0 N
+-1 0 R
+0 0 R
+
+PAD 0 4
+-2 1050000 RF 90.000 1350000 0 0
+-1 0 R
+0 0 R
+25 0 R
+
+PAD 0 4
+-2 2286000 R 1219200
+-1 2286000 R
+0 2286000 R
+25 3048000 R
+PAD 1 4
+-2 2286000 S 0 1219200
+-1 2286000 S 0
+0 2286000 S 0
+25 3048000 R
+*/
+int get_pad(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ int pinno = strtol(s[1]);
+ Stacklines = strtod(s[2]); // Anzahl der Zeilen die nach "PAD x n" noch folgen
+ return pinno;
+}
+
+
+void get_pad_size(string l, int pinnumber) {
+ string s[];
+ l = del_double_space(l);
+ int cnt = strsplit(s, l, ' ');
+
+ //if(dlgMessageBox(s[0] + " == 25?", "ok", "esc") != 0) exit(-825);
+
+
+ if (s[0] == "-2") { // Pad/smd dimension Top layer
+ int Padstack_level = strtol(s[0]);
+ real Padstack_size = strtod(s[1]) / Devider;
+ string Padstack_shape = s[2];
+ real Padstack_finori = strtod(s[3]);
+ real Padstack_idia = strtod(s[4]) / Devider;
+ real Padstack_finlength = strtol(s[5]);
+ real Padstack_finoffset = strtol(s[6]);
+ int Padstack_corner = strtol(s[7]);
+ real Padstack_drill = strtod(s[8]) / Devider;
+ int Padstack_slotori = strtol(s[9]);
+ int Padstack_slotlength = strtol(s[10]);
+ string Padstack_plated;
+ if (s[cnt-2] == "N" || s[cnt-2] == "P") {
+ Padstack_plated = s[cnt-2];
+ }
+
+ if (pinnumber == 0) { // alle Pads haben diese Größe, Rotation und Form
+
+ Padstack0_level = strtol(s[0]);
+ Padstack0_size = strtod(s[1]) / Devider;
+ Padstack0_shape = s[2];
+ Padstack0_finori = strtod(s[3]);
+ Padstack0_idia = strtod(s[4]) / Devider;
+ Padstack0_finlength = strtol(s[5]);
+ Padstack0_finoffset = strtol(s[6]);
+ Padstack0_corner = strtol(s[7]);
+ Padstack0_drill = strtod(s[8]) / Devider;
+ Padstack0_slotori = strtol(s[9]);
+ Padstack0_slotlength = strtol(s[10]);
+ if (s[cnt-2] == "N" || s[cnt-2] == "P") {
+ Padstack0_plated = s[cnt-2];
+ }
+ if (Padstack0_shape == "S" || Padstack0_shape == "R") { //
+ Padstack0_idia = Padstack0_size;
+ }
+
+ for (int n = 1; n < Tcnt; n++) { // vorsetzen der PAD/SMD-Grössen
+ Tsizelong[n] = Padstack0_size; // size ist die Höhe
+ Tsizeidia[n] = Padstack0_idia; // inner diameter ist die Breite
+ Tangle[n] = Padstack0_finori;
+ Tshape[n] = Padstack0_shape; // Padform Finger = SMD / R = Rechteck | O = Oval = 100% Roundness
+ if (Padstack0_shape == "RF") Troundness[n] = 0;
+ else if (Padstack0_shape == "OF" || Padstack0_shape == "R") Troundness[n] = 100;
+ Tdrill[n] = Padstack0_drill;
+ Tplatet[n] = Padstack0_plated;
+ }
+ }
+ else {
+ Tsizelong[pinnumber] = Padstack_size; // size ist die Höhe
+ Tsizeidia[pinnumber] = Padstack_idia; // inner diameter ist die Breite
+ Tfinlength[pinnumber] = Padstack_finlength;
+ Tangle[pinnumber] = Padstack_finori;
+ Tshape[pinnumber] = Padstack_shape;
+ Tplatet[pinnumber] = Padstack_plated;
+ }
+ /*
+ string h2;
+ sprintf(h2, "Pinnumber =%d\nLänge %.f\nBreite %.f\nRotation %.f\nForm %s",
+ pinnumber, Tsizelong[pinnumber], Tsizeidia[pinnumber], Tangle[pinnumber], Tshape[pinnumber]
+ );
+ if (dlgMessageBox(h2, "ok", "esc") != 0) exit(-902);
+ */
+ }
+ else if (s[0] == "-1") ; // Eagle can not define innerlayer diameter
+ else if (s[0] == "0") ; // bottom layer
+ else if (s[0] == "25") { // drill
+ Padstack0_drill = strtod(s[1]) / Devider;
+ Padstack0_shape = s[2];
+ if (pinnumber == 0) { // alle Pads haben diesen Drilldurchmesser
+ for (int n = 1; n < Tcnt; n++) { // vorsetzen des Drill und Form
+ Tdrill[n] = Padstack0_drill;
+ Tshape[n] = Padstack0_shape;
+ }
+ //if (dlgMessageBox("alle Drills gesetzt", "ok", "esc") != 0) exit(-902);
+ }
+ else {
+ Tshape[pinnumber] = Padstack0_shape;
+ Tdrill[pinnumber] = Padstack0_drill;
+ }
+ }
+ return;
+}
+
+
+void get_pad_option(string l) {
+ Cmd += "# get_pad_option\n";
+ return;
+}
+
+
+void get_pads(string pacname) { // PAD/SMD ausgeben
+ Cmd += "# get_pads()\nCHANGE LAYER 1;\nSMD '1' ;\n"; // Starte Namenvergabe mit 1, PADS-V5 gibt keine Namen vor!
+ real lastx = -100000.0, lasty = -100000.0;
+ for (int n = 1; n < Tcnt; n++) {
+ if (Tsizelong[n]) { // nur wenn Tsizelong (bei PAD der Drill) nicht 0 ist, dann wird der Pad erzeugt,
+ // PADS kann SMDs mit Size 0 erzeugen, die dann aber nicht dargestellt werden!
+ if (Tdrill[n] && !Tsizeidia[n] && !Tsizelong[n]) {
+ sprintf(h, "# 951\nHOLE %.8f (%.8f %.8f);\n",
+ Tdrill[n],
+ Tx1[n], Ty1[n]
+ );
+ Cmd += h;
+ }
+
+ else {
+ if(lastx == Tx1[n] && lasty == Ty1[n]) {
+ string error;
+ sprintf(error, "Package '%s'\nplace more as 1 PAD/SMD '%s' on coodinate %.8f %.8f",
+ filename(pacname),
+ Tname[n],
+ Tx1[n], Ty1[n]
+ );
+ dlgDialog("Error") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgTextView(error);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-945); }
+ dlgStretch(1);
+ }
+ };
+ }
+ if (Tname[n]) Tname[n] = "'" + Tname[n] + "'"; // PADS V9 gibt Namen vor, wenn der Name nicht leer ist, dann in ' ' einschliessen.
+
+ if (Tdrill[n]) { // bedrahtete Pads
+ string shape;
+ if (Tshape[n] == "S") shape = "SQUARE";
+ else if (Tshape[n] == "R") shape = "ROUND";
+ else if (Tshape[n] == "A") shape = "Round";
+ else if (Tshape[n] == "O") shape = "OCTAGON";
+
+ sprintf(h, "# 977\nCHange Dril %.8f;\nPAD %.8f %s R%.3f %s (%.8f %.8f);\n",
+ Tsizeidia[n],
+ Tsizelong[n],
+ shape,
+ Tangle[n],
+ Tname[n],
+ Tx1[n], Ty1[n]
+ );
+ Cmd += h;
+ }
+
+ else { // 2012-10-08 siehe imp_tcoord()
+ // hier wird nachträglich der Pad-Type und die Form geändert.
+ //if (Tshape[n] == "RF" || Tshape[n] == "OF") { // finger ist ein SMD
+ if (Tshape[n] == "OF" || Tshape[n] == "R") Troundness[n] = 100;
+ else if (Tshape[n] == "RF" || Tshape[n] == "R") Troundness[n] = 0;
+ if (Tshape[n] == "S") {
+ if(!Tsizeidia[n] || !Tsizelong[n]) {
+ if (!Tsizeidia[n] && !Tsizelong[n]) {
+ sprintf(h, "Package %s PAD %s has no dimension %.4f %.4f",
+ filename(pacname), Tname[n],
+ Tsizeidia[n] && !Tsizelong[n]
+ );
+ dlgMessageBox(h, "OK");
+ exit(-975);
+ }
+ else if (!Tsizeidia[n]) Tsizeidia[n] = Tsizelong[n];
+ else if (!Tsizelong[n]) Tsizelong[n] = Tsizeidia[n];
+ }
+ }
+ sprintf(h, "# 967 %d von %d : %s\nSMD %.8f %.8f -%d R%.1f %s (%.8f %.8f);\n",
+ n,
+ Tcnt,
+ Tname[n],
+ Tsizeidia[n], Tsizelong[n],
+ Troundness[n],
+ Tangle[n],
+ Tname[n],
+ Tx1[n], Ty1[n]
+ );
+ Cmd += h;
+ }
+ }
+ lastx = Tx1[n];
+ lasty = Ty1[n];
+ }
+ }
+ return;
+}
+
+void checktest(void) {
+ numeric string check[];
+ sprintf(check[0], "Num.\tTsizeidia\tTsizelong\tTfinlength\tTshape\tTroundness\tTangle\tTname\tTx1\tTy1\tTplatet");
+
+ ;
+ for (int n = 1; n < Tcnt; n++) {
+ sprintf(check[n], "%d\t%f\t%f\t%f\t%s\t%d\t%f\t%s\t%f\t%f\t%s",
+ n,
+ Tsizeidia[n],
+ Tsizelong[n],
+ Tfinlength[n],
+ Tshape[n],
+ Troundness[n],
+ Tangle[n],
+ Tname[n],
+ Tx1[n], Ty1[n],
+ Tplatet[n]
+ );
+
+ }
+
+ int sel;
+ if (test) dlgDialog("check") {
+ dlgListView("", check, sel);
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") { dlgReject(); exit(-1021); }
+ }
+ };
+ return;
+}
+
+
+/******** main ********/
+if (library || schematic);
+else {
+ dlgMessageBox("!Start this ULP in a schematic or library.", "OK");
+ exit(-1);
+}
+
+readconfig();
+
+// ### main menu ###
+//int editPADSsym = 0;
+int editPADSsch = 0;
+dlgDialog("PADS PowerPCB import") {
+ dlgHBoxLayout dlgSpacing(500);
+ if (library) {
+ //library(L) LbrName = L.name;
+ dlgLabel("Import a PADS symbol/library");
+ dlgHBoxLayout dlgSpacing(500);
+ dlgLabel("Directory of imported PADS libraries:");
+ dlgHBoxLayout {
+ dlgStringEdit(EaglePADSLbrDir);
+ dlgPushButton("&Browse") {
+ string mEaglePADSLbrDir = dlgDirectory("Directory: Translated Eagle-LBR from PADS", EaglePADSLbrDir);
+ if (mEaglePADSLbrDir) {
+ int len = strlen(mEaglePADSLbrDir);
+ if (mEaglePADSLbrDir[len-1] != '/') mEaglePADSLbrDir += "/"; // a directory has / on end
+ if (!mEaglePADSLbrDir) {
+ dlgMessageBox("!You must select a directory of translated libraryies.", "OK");
+ }
+ else EaglePADSLbrDir = mEaglePADSLbrDir;
+ }
+ }
+ }
+ dlgLabel("Import PADS symbol(s):");
+ dlgHBoxLayout {
+ dlgStringEdit(FilePADSSym[0]);
+ dlgPushButton("B&rowse") {
+ ImpPADSSym = filename(dlgFileOpen("Select a PADS symbol", EaglePADSLbrDir, "*.asc")); // 2012-11-09
+ if (ImpPADSSym) {
+ FilePADSSym[0] = ImpPADSSym;
+ cntFilePADSSym = 1;
+ }
+ }
+ }
+ dlgCheckBox("Import &all symbols from directory", Import_All_Symbols);
+ dlgHBoxLayout {
+ dlgLabel("New library name ");
+ dlgStringEdit(LbrName);
+ }
+ dlgCheckBox("Generate a separate library for each package file", SingleLbr);
+ }
+ else if (schematic) {
+ dlgLabel("Import a PADS schematic");
+ dlgLabel("Directory of Eagle schematic path");
+ dlgHBoxLayout {
+ dlgStringEdit(EaglePADSSchDir);
+ dlgPushButton("&Browse") {
+ string mEaglePADSSchDir = dlgDirectory("Select a PADS schematic directory", EaglePADSSchDir);
+ if (mEaglePADSSchDir) EaglePADSSchDir = mEaglePADSSchDir;
+ }
+ }
+ dlgLabel("Directory of PADS &Schematic");
+ dlgHBoxLayout {
+ dlgStringEdit(FilePADSAsc[0]);
+ dlgPushButton("&Browse") {
+ FilePADSAsc[0] = dlgFileOpen("Select a PADS schematic", DirPADSAsc , "*.asc");
+ DirPADSAsc = filedir(FilePADSAsc[0]);
+ if (FilePADSAsc[0]) {
+ PadsAscName = filesetext(FilePADSAsc[0], ".sch");
+ cntFilePADSAsc = 1;
+ editPADSsch = 1;
+ }
+ }
+ }
+
+ dlgHBoxLayout {
+ dlgLabel("New schematic name ");
+ dlgStringEdit(PadsAscName);
+ }
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") {
+ if (fileext(FilePADSAsc[0]) == ".asc" || fileext(FilePADSSym[0]) == ".asc") {
+ if (schematic) {
+ if (!PadsAscName) PadsAscName = EaglePADSSchDir + filename(filesetext(FilePADSAsc[0], ".sch"));
+ ScriptFile = filesetext(PadsAscName, ScriptExt);
+ dlgAccept();
+ }
+ else if (library) dlgAccept();
+ }
+ else {
+ if (schematic) dlgMessageBox("First select as PADS schematic file (*.asc)!", "OK");
+ else if (library) {
+ if (fileext(FilePADSSym[0]) != ".asc" ) dlgMessageBox("First select as PADS symbol file (*.asc)!", "OK");
+ }
+ }
+ }
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-2); }
+ dlgStretch(1);
+ dlgLabel(Version);
+ dlgStretch(1);
+ dlgPushButton("Save config") saveconfig();
+ }
+};
+if (!FilePADSSym[0] && !FilePADSAsc[0]) exit(-3);
+
+
+saveconfig();
+
+// # import a library #
+if (cntFilePADSSym) {
+
+ if (Import_All_Symbols) {
+ cntFilePADSSym = fileglob(FilePADSSym, EaglePADSLbrDir+"*.asc"); // alle .asc dateinamen einlesen
+ }
+ else {
+ FilePADSSym[0] = EaglePADSLbrDir+FilePADSSym[0]; // 2012-11-09 ergänze den Pfad
+ }
+ ScriptFile = EaglePADSLbrDir + ScriptExt;
+ if (ScriptFile && FilePADSSym[fn]) {
+ output(ScriptFile, "wtD") { // Datei neu anlegen
+ printf("# This EAGLE script is generated with '%s'\n", argv[0]);
+ }
+ for (fn = 0; fn < cntFilePADSSym; fn++) {
+ Cmd = ""; // Reset command string for next package
+ CntPinname = 0;
+ int len = strlen(FilePADSSym[fn]);
+ if (FilePADSSym[fn] && FilePADSSym[fn][len-1] != '/') { // can not use directorys
+ Cntl = fileread(Line, FilePADSSym[fn]);
+ status(FilePADSSym[fn]);
+ //SymDevName = strupr(filesetext(filename(FilePADSSym[fn]), ""));
+
+ int cntp;
+ int pars_on = 0; // ein Flag ab wann geparsed werden soll
+ Tcnt = 1; // Initialiesierung der Zähler
+ PADSname = "";
+ PADSunits = "";
+ PADSpieces = 0;
+ PADStermals = 0;
+ if (SingleLbr) {
+ sprintf(h, "OPEN '%s%s';\n", EaglePADSLbrDir, filesetext(filename(FilePADSSym[fn]), ".lbr"));
+ Cmd+=h;
+ }
+ for (nline = 0; nline < Cntl; nline++) {
+ if (strstr(Line[nline], "!PADS-") == 0) PADS_Headerline = Line[nline];
+ else if (!Line[nline]); // eine leere Zeile
+ else if (strstr(Line[nline], "*REMARK*") == 0); // Kommentar
+ else if (strstr(Line[nline], "*PARTDECAL*") == 0) { // ab hier startet das eigentliche Parsen des Package
+ pars_on = 1;
+ }
+ else if (pars_on == 2) {
+ /* ab hier wird es interessant */
+ if (strstr(Line[nline], "OPEN") == 0) imp_open_line(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "CLOSED") == 0) imp_closed_line(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "CIRCLE") == 0) imp_circle(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "COPCLS") == 0) imp_copcls(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "COPOPN") == 0) imp_copopn(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "COPCUT") == 0) imp_copcut(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "COPCCO") == 0) imp_copcco(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "COPCIR") == 0) imp_copcir(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "KPTCLS") == 0) imp_kptcls(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "KPTCIR") == 0) imp_cptcir(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "TAG") == 0) imp_tag(Line[nline]);
+ else if (strstr(Line[nline], "PAD") == 0) {
+ // PAD == Keyword
+ // 0 == pinno | Terminal number to which the pad stack applies. A value of 0 indicates all
+ // pads except those explicitly listed later
+ // 3 == stacklines | Number of lines of information pertaining to the pin numbers. The
+ // minimum number of entries is 3: top layer, inner layer, and bottom layer
+ //
+ // -2 == level | Layer number being defined. Valid values are:
+ // -2 Top layer
+ // -1 Inner layer
+ // 0 Bottom layer
+ // 1 to 250 Specific layer number
+ // 457200 == size | Diameter of the pad for round, odd, and annular pads. Length of a side for
+ // square pads. Width of oval or rectangular pads
+ // RF == shape | Pad shape. Valid values are:
+ // R Round
+ // S Square
+ // A Annular
+ // O Odd
+ // OF Oval finger
+ // RF Rectangular finger (SMD)
+ // RT - Thermal pad for a round pad shape
+ // ST - Thermal pad for square pad shape
+ // 90.000 == finori | Orientation, in degrees, of oval or rectangular pads. Precision is three
+ // digits after the decimal point. Valid values range from 0 to 179.999. If
+ // the pad is not oval or rectangular, this field is omitted
+ // 2286000 == idia | Inner diameter of an annular pad. If the pad is not annular, this field is omitted.
+ // 0 == finlength
+ // 0 == finoffset
+ //
+ // == corner
+ // == drill
+ // == plated
+ // == slotori
+ // == slotlength
+
+ /*
+ PAD 7 3
+ -2 915000 RF 0.000 2130000 0 0 N
+ -1 0 R
+ 0 0 R
+
+ PAD 0 4
+ -2 1050000 RF 90.000 1350000 0 0
+ -1 0 R
+ 0 0 R
+ 25 0 R
+ */
+ int pinnumber = get_pad(del_double_space(Line[nline]));
+ Cmd += "# 1257 " + Line[nline]+"\n";
+ get_pad_size(del_double_space(Line[nline]), pinnumber);
+ while(Stacklines) { // get next x lines
+ nline++;
+ get_pad_size(del_double_space(Line[nline]), pinnumber);
+ Stacklines--;
+ }
+ //if (dlgMessageBox(Line[nline] + "\n die nächste Padzeile!?", "ok", "esc") != 0) exit(-1245);
+ }
+ else if (strstr(Line[nline], "VALUE") == 0) imp_value(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "Regular") == 0) imp_font(Line[nline]); //
+ else if (strstr(Line[nline], "Part") == 0) imp_part_type(Line[nline]);
+ else if (strstr(Line[nline], "Ref.Des.") == 0) imp_ref_des(Line[nline]);
+ else if (Line[nline][0] == 'T') imp_tcoord(del_double_space(Line[nline]));
+ else if (strstr(Line[nline], "*PARTTYPE*") == 0 || strstr(Line[nline], "*END*") == 0) { // End of package definition
+ if (PADStermals != Tcnt-1) {
+ string e;
+ sprintf(e, "!Package %s.asc\n\nDifferent counts of PADs\nheader info = %d\nfound = %d", PADSname, PADStermals, Tcnt);
+ if (dlgMessageBox(e, "OK", "CANCEL") != 0) exit(-1256);;
+ }
+ checktest();
+ get_pads(FilePADSSym[fn]);
+ Cmd += "# End of Script\nWIN FIT;\n";
+ break; //n = Cntl; // raus aus der Schleife, alle benötigten Parameter geparsed.
+ }
+ }
+ else if (pars_on == 1) {
+ pars_on++;
+ if (imp_pac_name(del_double_space(Line[nline]))) break; // Package exist, not delete
+ if (test) if (dlgMessageBox(PADSname, "Start new package", "Cancel") != 0) exit(-1267);
+ }
+ }
+ if (SingleLbr) { // 2012-06-25
+ sprintf(h, "WRITE '%s%s';\n", EaglePADSLbrDir, filesetext(filename(FilePADSSym[fn]), ".lbr"));
+ Cmd+=h;
+ //if (dlgMessageBox(h, "ok", "esc") != 0) exit(-1273);
+ }
+
+ if (test) {
+ dlgDialog("test") {
+ dlgHBoxLayout dlgSpacing(700);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(700);
+ dlgTextEdit(Cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("ok") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-1285); }
+ dlgPushButton("do not show next scipt") { test = 0; dlgAccept(); }
+ }
+ };
+ }
+ output(ScriptFile, "atD") { // Erzeugtes Script an die Datei anhängen
+ printf("%s", Cmd);
+ }
+ }
+ }
+ exit ("SCRIPT '"+ ScriptFile + "'");
+ }
+}
+// # Ende Bibliothek #
+
+
+// # import a schematic #
+if (cntFilePADSAsc) {
+ int f = 0;
+ if (ScriptFile && FilePADSAsc[0]) {
+ for (f = 0; f < cntFilePADSAsc; f++) {
+
+ if (FilePADSAsc[f]) {
+ Cntl = fileread(Line, FilePADSAsc[f]);
+ status(FilePADSAsc[f]);
+ if (!checkexist_sym(PadsAscName)) {
+ string cmd;
+ sprintf(cmd, "EDIT '%s.SCH';\nCHANGE LAYER 96;\nGRID MIL 50 2 LINES ON;\nCHANGE WIDTH 10;\n", PadsAscName);
+ Cmd+=cmd;
+ Cmd+= "CHANGE STYLE Continuous;\n";
+ for (f = 0; f < Cntl; f++) {
+ if (strstr(Line[f], "!PADS-POWERPCB") == 0) {
+ sprintf(h, "# %s\n", Line[f]);
+ cmd+= h;
+ }
+ else {
+ sprintf(h, "Line %d unknown:\n%s", f+1, Line[f]);
+ if (dlgMessageBox(h, "OK", "ESC") != 0) exit(-1322);
+ }
+ }
+ Cmd += CmdDev + "WIN FIT;\n"; // make a device and use generated symbol
+ }
+ }
+ }
+
+ if (test) {
+ dlgDialog("Das Rückgabe-SCRIPT") {
+ dlgHBoxLayout dlgSpacing(700);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(700);
+ dlgTextEdit(Cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("ok") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-1339); }
+ }
+ };
+ }
+ output(ScriptFile, "wtD") {
+ printf("%s", Cmd);
+ }
+ //if (dlgMessageBox(ScriptFile, "Ausführen", "Abbrechen") != 0) exit(-9);
+ exit ("SCRIPT '"+ ScriptFile + "'");
+ }
+}
+
diff --git a/trunk/ulp/import-ultiboard-ddf.ulp b/trunk/ulp/import-ultiboard-ddf.ulp
new file mode 100644
index 00000000..1f9b627d
--- /dev/null
+++ b/trunk/ulp/import-ultiboard-ddf.ulp
@@ -0,0 +1,1502 @@
+#usage "Import ULTIBOARD PCB Design Data File format (DDF)\n"
+ "
"
+ "Imports ULTIBOARD PCB Design Data File format (DDF) Version 4.80 & 5.50."
+ "
"
+ "Based on : Ultiboard User Manual, Appendix A, FILE FORMATS."
+ "
"
+ "ULTIBOARD is a registered trademark of Electronics Workbench."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string InfoUS =
+ "Confirm the message:
\n" +
+ "connect Signals
\n" +
+ " S$nn
\n" +
+ " S$nn
\n" +
+ " with OK.
" +
+ "
" +
+ "This message will be prompted if a net segment (track) is connected to another " +
+ "net segment. " +
+ "The reason for this is the way ULTIBOARD exports the tracks, first the " +
+ "horizontal ones, then the vertical ones and at least tracks that run diagonal." +
+ "If ULTIBOARD has not named a segment of a track, EAGLE generates a name of" +
+ "its own and uses the $ sign at second position in it." +
+ "Please notice that the text height (and length) differs in EAGLE and " +
+ "ULTIBOARD. The position of the text will be calculated dependent on " +
+ "the the height and length of each character of the EAGLE vector font.
" +
+ " - ULTIBOARD uses the text center as origin point
" +
+ " - EAGLE uses the left lower corner of the text as origin point.
" +
+ "The DDF format does not provide information about the lenght of characters.
" +
+ " The x_coord and y_coord are expressed in database units (1/1200th of an inch)
" +
+ " The rotation is given in degrees, specified as a floating point number between 0.0 and 360.0 degrees.
" +
+ " Internally, Ultiboard works with a precision of 1/64th degree
" +
+ "
" +
+ "ULTIBOARD Version 5, Revision 50
" +
+ " The x_coord and y_coord are expressed in database units (1 nanometer)
" +
+ " The rotation is given in degrees, specified as a floating point number between 0.0 and 360.0 degrees.
" +
+ " Internally, Ultiboard works with a precision of 1/64th degree
" +
+ "
" +
+ "ULTIBOARD is a registered trademark of Electronics Workbench";
+
+string InfoDE =
+ "Bestätigen sie die Meldung:
\n" +
+ "connect Signals
\n" +
+ " S$nn
\n" +
+ " S$nn
\n" +
+ " mit OK.
" +
+ "Diese Meldung wird dadurch erzeugt, daß ein Netzsegment (Leiterzug) mit " +
+ "einem anderen Netzsegment verbunden wird. " +
+ "Die Ursache ist die Reihenfolge der Ausgabe der Leiterbahn-Segmente aus ULTIBOARD, " +
+ "da ULTIBOARD zuerst waagrechte dann senkrechte und am Schluß diagonale " +
+ "Leiterbahnsegmente ausgibt.
" +
+ "Wird von ULTIBOARD diesen Leitersegmenten kein Netzname zugewiesen, " +
+ "so erzeugt EAGLE einen Namen mit dem Zeichen $ an zweiter Position.
" +
+ "
" +
+ "Beachten Sie, daß die Buchstabengrößen (Zeichenlänge) " +
+ "von ULTIBOARD und EAGLE nicht identisch sind. Die Position der Texte wird " +
+ "berechnet durch die Texthöhe und dem Wert der Zeichenlänge jedes " +
+ "Buchstaben des EAGLE-Vector-Font.
\n" +
+ " - ULTIBOARD plaziert Texte am Mittelpunkt des Textes.
" +
+ " - EAGLE plaziert Texte mit der linken unteren Ecke des 1. Buchstaben.
" +
+ "Das ULP berechnet die Position anhand der Stringlänge und Texthöhe. " +
+ "Im DDF-Format gibt es keine Information bezüglich der Buchstabenlänge, " +
+ "dadurch kann es vorkommen, daß längere Texte nicht exakt an der gleichen " +
+ "Position wie im ULTIBOARD Layout positioniert werden.
" +
+ "
" +
+ "Die Warnung: No forward-/backannotation will be performed!
" +
+ "wird erzeugt, falls ein Schaltplan zur Laufzeit des ULP geladen ist, und muß " +
+ "mit OK bestätigt werden.
"
+ "Author: support@cadsoft.de"
+
+#require 4.1602
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+//
+// Release 1.0 -- November 2003
+// Release 1.0.1 -- May 2006, Added source of specification (ric)
+// Release 2.0.0 -- 2012-02-29, values calculated with u2inch (alf)
+// Release 2.0.1 -- 2012-03-13, corrected calulation of diameter (alf)
+// now generate the same data as the original ulp up to V5.
+// Release 2.0.2 -- corrected line 82, multiplicator 1000 -> 10000
+
+string Version = "2.0.2";
+
+string fileName, RefDes, Access, Xpolarity, Ypolarity, RestOfLine, NoDiameter;
+int n, TypeNumber, Diameter, Xcoord, Ycoord, RectDataX, RectDataY, Angle ;
+
+
+void Header(UL_BOARD B) {
+ printf("C IPC-D-356 generated by %s\n", EAGLE_SIGNATURE);
+ printf("C Database %s -- Exported at %s\n", B.name, t2string(time()));
+ //printf("C ULP-Version %s : Values = Inch/1000\n", Version); // 2012-03-13
+ printf("C \n");
+ printf("P JOB EAGLE %d.%d NETLIST, DATE: %s\n", EAGLE_VERSION, EAGLE_RELEASE , t2string(time()));
+ printf("P UNITS CUST 0\n");
+ printf("P DIM N\n");
+}
+
+
+void TestRecord(UL_BOARD B) {
+ B.signals(S) {
+ S.vias(V) {
+ TypeNumber = 317 ;
+ RefDes = "VIA";
+ Diameter = round(u2inch(V.drill)*1000);
+ if (V.start == 1 && V.end == 16) Access = "A00"; ///gibts auch andere?
+ Xcoord = round(u2inch(V.x)*10000);
+ Ycoord = round(u2inch(V.y)*10000);
+ if (Xcoord >= 0) Xpolarity = "X ";
+ if (Xcoord < 0) Xpolarity = "X-";
+ if (Ycoord >= 0) Ypolarity = "Y ";
+ if (Ycoord < 0) Ypolarity = "Y-";
+ RectDataX = RectDataY = round(u2inch(V.diameter[V.start])*10000);
+ RestOfLine = " " ; // 13 blanks to fill up 80 characters
+
+ printf("%3d%-14s %-12sD%4dP%-3s%2s%6d%2s%6dX%4dY%4d%-13s\n",
+ TypeNumber, S.name, RefDes, Diameter, Access, Xpolarity, abs(Xcoord), Ypolarity, abs(Ycoord),
+ RectDataX, RectDataY, RestOfLine);
+ }
+ }
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ TypeNumber = 317 ;
+ RefDes = E.name;
+ Diameter = round(u2inch(C.pad.drill)*1000);
+ Access = "A00";
+ Xcoord = round(u2inch(C.pad.x)*10000);
+ Ycoord = round(u2inch(C.pad.y)*10000);
+ if (Xcoord >= 0) Xpolarity = "X ";
+ if (Xcoord < 0) Xpolarity = "X-";
+ if (Ycoord >= 0) Ypolarity = "Y ";
+ if (Ycoord < 0) Ypolarity = "Y-";
+ if (C.pad.elongation == 0)
+ RectDataX = RectDataY = round(u2inch(C.pad.diameter[LAYER_TOP])*10000);
+ else { // if (C.pad.elongation != 0)
+ RectDataX = round(u2inch(C.pad.diameter[LAYER_TOP])*10000);
+ RectDataY = round((u2inch(C.pad.diameter[LAYER_TOP])*10000) * (C.pad.elongation / 100) + u2inch(C.pad.diameter[LAYER_TOP])*10000);
+ }
+ Angle = round(C.pad.angle);
+ RestOfLine = " ";
+
+ printf("%3d%-14s %-6s-%-4s D%4dP%-3s%2s%6d%2s%6dX%4dY%4dR%3d%-9s\n",
+ TypeNumber, C.pad.signal, RefDes, C.pad.name, Diameter, Access,
+ Xpolarity, abs(Xcoord), Ypolarity, abs(Ycoord), RectDataX, RectDataY, Angle, RestOfLine);
+ }
+ if (C.smd) {
+ TypeNumber = 327 ;
+ RefDes = E.name;
+ NoDiameter = " "; // No drill ==> coloum 33-38 empty
+ if (C.smd.layer == 1) Access = "A01";
+ if (C.smd.layer == 16) Access = "A16";
+ Xcoord = round(u2inch(C.smd.x)*10000);
+ Ycoord = round(u2inch(C.smd.y)*10000);
+ if (Xcoord >= 0) Xpolarity = "X ";
+ if (Xcoord < 0) Xpolarity = "X-";
+ if (Ycoord >= 0) Ypolarity = "Y ";
+ if (Ycoord < 0) Ypolarity = "Y-";
+ RectDataX = round(u2inch(C.smd.dx) * 10000) ;
+ RectDataY = round(u2inch(C.smd.dy) * 10000) ;
+ Angle = round(C.smd.angle);
+ RestOfLine = " ";
+
+ printf("%3d%-14s %-6s-%-4s %-6s%-3s%2s%6d%2s%6dX%4dY%4dR%3d%-9s\n",
+ TypeNumber, C.smd.signal, RefDes, C.smd.name, NoDiameter, Access,
+ Xpolarity, abs(Xcoord), Ypolarity, abs(Ycoord), RectDataX, RectDataY, Angle, RestOfLine);
+ }
+ }
+ // B.holes(H) TypeNumber = 347 ; printf("%d", TypeNumber);
+ // E.package.holes(H) TypeNumber = 347 ; printf("%d", TypeNumber);
+ }
+}
+
+
+void EndOfFile(void) {
+ printf("999\n");
+}
+
+//==========main===========
+
+
+if (board) {
+ board(B) {
+ fileName = dlgFileSave("Save IPC-D-356 File", filesetext(B.name, ".ipc"), "*.ipc");
+ if (fileName == "") exit(0);
+
+ output(fileName) {
+ Header(B);
+ TestRecord(B);
+ EndOfFile();
+ }
+ }
+}
+
+else {
+ dlgMessageBox("!Start this ULP in a Board.");
+ exit (0);
+}
diff --git a/trunk/ulp/layer-sequence-arrowdown.png b/trunk/ulp/layer-sequence-arrowdown.png
new file mode 100644
index 00000000..4f8f3167
Binary files /dev/null and b/trunk/ulp/layer-sequence-arrowdown.png differ
diff --git a/trunk/ulp/layer-sequence-arrowup.png b/trunk/ulp/layer-sequence-arrowup.png
new file mode 100644
index 00000000..8b735cda
Binary files /dev/null and b/trunk/ulp/layer-sequence-arrowup.png differ
diff --git a/trunk/ulp/layer-sequence.ulp b/trunk/ulp/layer-sequence.ulp
new file mode 100644
index 00000000..0ba7f8fa
--- /dev/null
+++ b/trunk/ulp/layer-sequence.ulp
@@ -0,0 +1,359 @@
+#usage "en:Set Layer Sequence for PRINT command.
"
+ "For printing your drawing it might be important to determine the sequence of printed layers. "
+ "This ULP manages the 'Option.LayerSequence' setting in the file eaglerc.usr.
"
+ "From HELP SET: "
+ "Option.LayerSequence "
+ "The internal layers are rendered in a sequence that mimics the actual layer stack, "
+ "so that the result looks useful even on printers and PDF or Postscript files, where "
+ "layers are not transparent. Sometimes user defined layers may need to be rendered before "
+ "internal layers instead of after them. This parameter can be used to define the "
+ "sequence in which layers are rendered. It consists of a string of layer numbers or "
+ "layer ranges, followed by an optional 't' or 'b'. "
+ "123 renders layer 123 "
+ "123t renders layer 123 if the output is \"viewed from top\" (not mirrored) "
+ "123b renders layer 123 if the output is \"viewed from bottom\" (mirrored) "
+ "123-140 renders layers 123 through 140 in the given sequence "
+ "140-123 renders layers 140 through 123 in the given sequence "
+ "* inserts the default sequence of the internal layers "
+ "123b * 123t makes layer 123 always be rendered first "
+ "Note that each layer is rendered only once, even if it is listed several times. "
+ "The default sequence of the internal layers is: "
+ "48t 49t 19t 47t 20t 46t 23 27 25 59 57 55 53 50 51 21 44t 45t 37 35 31 29 33 39 41 43t 18t 17t 1-16 17b 18b 43b 42 40 34 30 32 36 38 45b 44b 22 52 54 56 58 60 26 28 24 46b 20b 47b 19b 49b 48b 61-99. "
+ "When viewed from top, the layer sequence is rendered from right to left, while "
+ "when viewed from bottom (mirrored) it is rendered from left to right. For instance, "
+ "layer 48 (Document) is entered as 48t and 48b to always have it rendered as the last one. "
+ "Layers 21 (tPlace) and 22 (bPlace), on the other hand, are listed only once, to have "
+ "them rendered at the proper place, depending on whether the output is mirrored or not. "
+ "Any layers that are not explicitly mentioned in the layer sequence are rendered after "
+ "the given sequence in ascending order. "
+ "
"
+ "Author: alf@cadsoft.de"
+ ,
+ "de:Layerreihenfolge für den Ausdruck festlegen.
"
+ "Für den Ausdruck kann die Reihenfolge der Layer wichtig sein. Dieses ULP nutzt die Möglichkeit mit "
+ "'Option.LayerSequence' in der eaglerc.usr diese Reihenfolge fest zu legen.
"
+ "Auszug aus HELP SET: "
+ "Option.LayerSequence "
+ "Die internen Layer werden in der Reihenfolge dargestellt, die dem tatsächlichen Lagenaufbau entspricht, "
+ "so dass das Ergebnis auch auf Druckern und PDF- bzw. Postscript-Dateien brauchbar aussieht, wo die Layer "
+ "nicht transparent sind. Manchmal kann es erforderlich sein, dass benutzerdefinierte Layer vor den internen "
+ "Layern dargestellt werden müssen, anstatt nach diesen. Mit diesem Parameter kann die Reihenfolge, in der "
+ "die Layer dargestellt werden, festgelegt werden. Er besteht aus einer Folge von Layer-Nummern bzw. "
+ "Layer-Bereichen, optional gefolgt von 't' oder 'b'. "
+ "123 stellt Layer 123 dar "
+ "123t stellt Layer 123 dar, wenn die Ausgabe \"von oben gesehen\" erfolgt (nicht gespiegelt) "
+ "123b stellt Layer 123 dar, wenn die Ausgabe \"von unten gesehen\" erfolgt (gespiegelt) "
+ "123-140 stellt die Layer 123 bis 140 in der angegeben Reihenfolge dar "
+ "140-123 stellt die Layer 140 bis 123 in der angegeben Reihenfolge dar "
+ "* fügt die Standard-Sequenz der internen Layer ein "
+ "123b * 123t sorgt dafür, dass Layer 123 immer als erster dargestellt wird "
+ "Beachten Sie, dass jeder Layer nur einmal dargestellt wird, auch wenn er mehrmals aufgeführt ist. "
+ "Die Standard-Sequenz der internen Layer ist: "
+ "48t 49t 19t 47t 20t 46t 23 27 25 59 57 55 53 50 51 21 44t 45t 37 35 31 29 33 39 41 43t 18t 17t 1-16 17b 18b 43b 42 40 34 30 32 36 38 45b 44b 22 52 54 56 58 60 26 28 24 46b 20b 47b 19b 49b 48b 61-99. "
+ "Bei Ansicht von oben, wird die Layer-Sequenz von rechts nach links abgearbeitet, während sie bei Ansicht "
+ "von unten (gespiegelt) von links nach rechts abgearbeitet wird. Zum Beispiel ist Layer 48 (Document) als "
+ "48t und 48b enthalten, damit dieser immer als letzter dargestellt wird. "
+ "Die Layer 21 (tPlace) und 22 (bPlace) hingegen sind nur jeweils einmal aufgelistet, damit Sie an der "
+ "richtigen Stelle erscheinen, je nachdem, ob die Ausgabe gespiegelt erfolgt oder nicht. "
+ "Alle nicht explizit in der Layer-Sequenz aufgeführten Layer werden nach der gegebenen Sequenz, in "
+ "aufsteigender Reihenfolge, dargestellt. "
+ "
"
+ "Creates a list of all signals of a board, together "
+ "with their maximum frequency, length, area, resistance, "
+ "minimum and maximum width and maximum current."
+ "
"
+ "This is a very simplified calculation for a first evaluation "
+ "of the layout."
+ "
"
+ "Parallel tracks and polygons are not taken into consideration."
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+/* German description:
+ "Dieses ULP berechnet alle Signallaengen eines Layouts
"
+ "(nur Layer 1 bis 16) und die zugehoerige Frequenz (f=c/l) "
+ "und erzeugt eine Textdatei length-ri.txt, die alle Signale nach "
+ "Frequenz bzw Laenge sortiert enthaelt.
"
+ "Bei der Frequenzberechnung handelt es sich um eine ganz einfache "
+ "Umrechnung, die eine erste Abschaetzung bzgl. Stoerstrahlung erlaubt.
"
+ "Zusaetzlich wird die minimale und maximale Leiterbahnbreite ermittelt "
+ "und die daraus resultierende Strombelastung.
"
+ "Bei der Widerstands- und Strombelastbarkeits-Berechnung wird die "
+ "minimale Leiterbahnbreite herangezogen.
"
+ "Es wird auch keine eine Parallelführung bzw. Fläche (Polygon) "
+ "berücksichtigt.
"
+ "A. Zaffran 05.04.2000 alf@cadsoft.de
"
+*/
+
+real f, WLtotal;
+int index[];
+
+ // ** aus "Mechanik der Elektronik"
+ // mm <1 1 2 3 4 5 6 7 8 9 10 11 12 13 mm Leiterbreite bei 35 um Cu
+
+real k[] = { 9, 8.8, 6, 4, 3.2, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9 };
+
+ // _______________________
+ // Imax ~ 5.25 V [d x b x (d + b)] x k || (tL ~60)
+ //
+ // d = um Cu-Kaschierung
+ // b = Breite mm
+ // k = Korrekturwert aus Tabelle 02.02.2000 alf
+ // ** aus "Mechanik der Elektronik"
+
+real Cu = 0.035; // 35 um Cu Kaschierung
+
+real Length[], Freq[], Widthmin[], Widthmax[];
+string Signal[];
+
+real c = 299800; // Lichtgechwindigkeit Vakuum in [km/s]
+
+int n = 0;
+int t;
+string data[];
+string h;
+string header;
+int note = 0;
+
+void dialog(void)
+{
+ int select = 0;
+ int Result = dlgDialog("Wire length of Layout") {
+ dlgLabel(header);
+ string lab;
+ sprintf(lab, " Cu thickness = %.3f mm", Cu);
+ dlgLabel(lab);
+ dlgListView("", data, select);
+ dlgStretch(0);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+&Save") {
+ board(B) {
+ string FileName = dlgFileSave("Save list", filesetext(B.name, ".txt"));
+ if (FileName) {
+ output (FileName, "wt") {
+ printf("%s", header);
+ for (int x = 0; x < t; x++)
+ printf("%s\n", data[x]);
+ if (note) {
+ sprintf( h, "\n *** note wire width.\n");
+ data[t] += h;
+ t++;
+ }
+ }
+ }
+ }
+ }
+ dlgPushButton("-Close") dlgReject();
+ }
+ };
+ if (!Result)
+ exit(0);
+}
+
+real WireLength(real x1, real x2, real y1, real y2)
+{
+ return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
+}
+
+real ArcLength(real ang1, real ang2, real radius)
+{
+ return radius * 2 * PI / 360 * (ang2 - ang1);
+}
+
+real Frequency(real c, real l)
+{
+ return c / l;
+}
+
+void WireWidth(string sig, real w)
+{
+ // ermitteln der min-max Leiterbahnbreite
+ if (w < Widthmin[n]) Widthmin[n] = w;
+ if (w > Widthmax[n]) Widthmax[n] = w;
+}
+
+real imax(real breite)
+{
+ return (breite == 0) ? 0 : 5.25 * sqrt((Cu * breite * (Cu + breite)) * k[int(trunc(breite))]);
+}
+
+if (board) board(B) {
+ sprintf(h, "%s\n", EAGLE_SIGNATURE);
+ header += h;
+ sprintf(h, "List of signals with length and its max. frequency / current\n");
+ header += h;
+ sprintf(h, "exported from %s\nat %s\n", B.name, t2string(time()));
+ header += h;
+
+ B.signals(S) {
+ WLtotal = 0;
+ Widthmin[n] = 32000;
+ Widthmax[n] = 0;
+ S.wires(W) {
+ if (W.layer < 17) { // nur Kupfer-Layer
+ if (W.arc) {
+ WLtotal += ArcLength(W.arc.angle1, W.arc.angle2, u2mm(W.arc.radius));
+ }
+ else {
+ WLtotal += WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1));
+ }
+ WireWidth(S.name, u2mm(W.width));
+ }
+ }
+ if (WLtotal != 0) {
+ Signal[n] = S.name;
+ Length[n] = WLtotal;
+ Freq[n] = Frequency(c, WLtotal);
+ ++n;
+ }
+ }
+ sort(n, index, Freq);
+
+ sprintf(h, "Signal\tf max. [MHz]\tl [mm]\tA [mm2]\tR [mOhm]\tw min [mm]\tw max [mm]\tImax [A]");
+ data[0] = h;
+ t = 1;
+
+ for (int i = 0; i < n; ++i) {
+ real mm2 = Widthmin[index[i]] * Cu;
+ real mOhm = 0;
+ string R;
+ if (Widthmin[index[i]]) {
+ mOhm = (174 * Length[index[i]] / 10) / ( Cu * 1000 * Widthmin[index[i]]);
+ sprintf(R, "%7.2f", mOhm);
+ }
+
+ sprintf(h, "%s\t%10.2f\t%7.3f\t%4.3f\t%s\t%6.3f\t%6.3f\t%6.2f", Signal[index[i]], Freq[index[i]], Length[index[i]], mm2, R, Widthmin[index[i]], Widthmax[index[i]], imax(Widthmin[index[i]]));
+ data[t] = h;
+
+ if (!Widthmin[index[i]]) {
+ note = 1;
+ sprintf( h, " ***");
+ data[t] += h;
+ }
+ t++;
+ }
+
+ dialog();
+ }
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+}
diff --git a/trunk/ulp/length.ulp b/trunk/ulp/length.ulp
new file mode 100644
index 00000000..b7480859
--- /dev/null
+++ b/trunk/ulp/length.ulp
@@ -0,0 +1,271 @@
+#usage "This ULP calculates the signal length of routed tracks in the layout
\n"
+ "run length [name | name* | *name | *name*] "
+ "run length name [name name ...]
"
+ "Wires in layers 1 to 16 will be added, airwires will be shown separately. "
+ "If net names are specified, the differences in length will be calculated in procentual values. "
+ "The procentual difference is based on the shortest of the specified tracks which is taken as 100%. "
+ "Parallel tracks and polygons are not taken into consideration. "
+ "Only for all signals it is possible to change the sorting of the displayed signals in the list."
+ "
"
+ "Author: support@cadsoft.de
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+#require 4.1602
+
+// ** German description: **
+string hilfe = "Dieses ULP berechnet die Signallängen von Leiterbahnen eines Layouts.
" +
+ "Die Wire in den Layern 1 bis 16 werden addiert, die Airwire werden gesondert angegeben. " +
+ "Prozentuale Längendifferenzen werden nur berechnet wenn Netznamen angegeben wurden. " +
+ "Für den prozentualen Längenunterschied wird die kürzeste Leiterbahn als 100% angesehen. " +
+ "Es wird keine Parallelführung bzw. Fläche (Polygon) berücksichtigt. " +
+ "Nur bei Anzeige aller Signale kann die Sortierung des Listfeldes beeinflußt werden.
" +
+ "Ein Doppelklick auf einen Listeneintrag, beendet das ULP und zeigt des Singal im Board.
" +
+ "Author: support@cadsoft.de"
+ "
";
+
+// 2008-09-11 Ohne Parameter wird erst die Hilfe aufgerufen. alf@cadsoft.de
+// Wird keines der gesuchten Signale gefunden,
+// wird eine entsprechnede Nachricht angezeigt.
+// 2005-02-10 alf@cadsoft.de
+// 2012-04-05 Doppleklick in Liste beendet das ULP mit SHOW auf den Netznamen
+// 2013-01-09 Jetzt auch mit * ohne das Hilfsmenu un mit 9 Nachkommastellen
+
+
+string Help = usage;
+string HButton = "&Help";
+string SButton = "&Save";
+
+real f, WLtotal;
+int index[];
+
+
+real Length[];
+string signal_list[];
+int sig_n = 0;
+
+real route_length[];
+real Unroute_length[];
+int Unroute_cnt[];
+
+int t;
+numeric string data[];
+
+string h;
+string header;
+
+data[1] = "No signals found.";
+
+if (language() == "de") {
+ data[1] = "Keines der Signale gefunden."; // 2008-09-11
+ Help = hilfe;
+ HButton = "&Hilfe";
+ SButton = "&Sichern";
+}
+
+
+void help(void) {
+ dlgMessageBox(Help, "Ok");
+ return;
+}
+
+
+void show(string line) { // 2012-04-05
+ string s[];
+ int n = strsplit(s, line, '\t');
+ sprintf(line, "SHOW '%s'", s[0]);
+ exit(line);
+}
+
+void dialog(void) {
+ int select = 0;
+ int ssort = 0;
+ if (argc < 2) ssort = 1;
+
+ int Result = dlgDialog("Wire length of Layout") {
+ dlgListView("", data, select, ssort) show(data[select]);
+ dlgHBoxLayout {
+ dlgPushButton("+Ok") dlgReject();
+ dlgPushButton(SButton) {
+ board(B) {
+ string FileName = dlgFileSave("Save list", filesetext(B.name, ".txt"));
+ if (FileName) {
+ output (FileName, "wt") {
+ printf("%s", header);
+ for (int x = 0; x < t; x++) printf("%s\n", data[x]);
+ }
+ }
+ }
+ }
+ dlgStretch(1);
+ dlgPushButton(HButton) help();
+ }
+ };
+ if (!Result)
+ exit(0);
+}
+
+
+real WireLength(real x1, real x2, real y1, real y2) {
+ return sqrt((pow(x2 - x1, 2) + pow(y2 - y1, 2)) );
+}
+
+
+real ArcLength(real ang1, real ang2, real radius) {
+ return radius * 2 * PI / 360 * (ang2 - ang1);
+}
+
+
+int found(string signame) {
+ if (argc < 2) {
+ return 1;
+ }
+ else if (argc == 2 && argv[1] == "*") return 1;
+ int f = 0;
+ int sig = 0;
+ for (int n = 0; n <= sig_n; n++) {
+
+ if (strchr(signal_list[n], '*') >= 0) { // wildcard * in name
+ int l = strlen(signal_list[n]);
+ string s;
+
+ if (signal_list[n][0] == '*' && signal_list[n][l-1] == '*') { // *name*
+ s = strsub(signal_list[n], 1, l-2 );
+ if(strstr(signame, s) > 0) {
+ f = 1;
+ break;
+ }
+ }
+
+ else if (signal_list[n][l-1] == '*') { // name*
+ s = strsub(signal_list[n], 0, l-1);
+ if(strstr(signame, s) == 0) {
+ f = 1;
+ break;
+ }
+ }
+
+ else if (signal_list[n][0] == '*') { // *name
+ s = strsub(signal_list[n], 1);
+ if(strstr(signame, s) > 0) {
+ f = 1;
+ break;
+ }
+ }
+ }
+ else if (signame == signal_list[n]) {
+ f = 1;
+ break;
+ }
+ }
+ return f;
+}
+
+// *** different length to shortesd signals in percent ***
+string percent( real length, real length100) {
+ string s;
+ if (length100) sprintf(s, "%.3f", (length - length100) / (length100 / 100));
+ else s = "--";
+ return s;
+}
+
+// *** Unroutet length ***
+string unroute(real l, int cnt) {
+ string s;
+ if (cnt) sprintf(s, "%.f", l);
+ else s = "--";
+ return s;
+}
+
+
+
+// *** main ***
+if (board) board(B) {
+ if (argc < 2) { // 2008-09-11 alf@cadsoft.de
+ help();
+ }
+ else if (argc == 2 && argv[1] == "*") ;
+ else {
+ string h;
+ int n;
+ string list;
+
+ // *** check only by signal name ***
+ sig_n = argc -2;
+ for (n = 1; n < argc; n++) {
+ signal_list[sig_n] = strupr(argv[n]);
+ list += signal_list[sig_n] + "\n";
+ sig_n++;
+ }
+ }
+
+ sprintf(h, "%s\n", EAGLE_SIGNATURE);
+ header += h;
+ sprintf(h, "List of signals with length");
+ header += h;
+
+ string Signal[];
+ int n = 0;
+ B.signals(S) {
+ if (found(S.name)) {
+ WLtotal = 0;
+ int cntUnroute = 0;
+ real unroute = 0;
+ S.wires(W) {
+ if (W.layer < 17) { // nur Kupfer-Layer
+ if (W.arc) {
+ WLtotal += ArcLength(W.arc.angle1, W.arc.angle2, u2mm(W.arc.radius));
+ }
+ else {
+ WLtotal += WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1));
+ }
+ }
+ if (W.layer == 19) { // unrouted Layer
+ unroute += WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1));
+ cntUnroute++;
+ }
+ }
+ Signal[n] = S.name;
+ Length[n] = WLtotal;
+ Unroute_length[n] = unroute;
+ Unroute_cnt[n] = cntUnroute;
+ ++n;
+ }
+ }
+
+ sort(n, index, Length);
+ sprintf(h, "Signal\tl [mm]\tdiff. [mm]\tdiff. [%%]\tunrouted [mm]");
+ data[0] = h;
+ t = 1;
+ real null_length = Length[index[0]];
+
+ for (int i = 0; i < n; ++i) {
+ sprintf(h, "%s\t%.9f\t%.9f\t%s\t%s",
+ Signal[index[i]],
+ Length[index[i]],
+ Length[index[i]] - null_length,
+ percent(Length[index[i]], null_length),
+ unroute(Unroute_length[index[i]], Unroute_cnt[index[i]])
+ );
+ data[t] = h;
+ t++;
+ }
+ dialog();
+}
+
+else {
+ dlgMessageBox("Start this ULP in a Board");
+ exit (0);
+}
diff --git a/trunk/ulp/lpp.ulp b/trunk/ulp/lpp.ulp
new file mode 100644
index 00000000..7f25ab90
--- /dev/null
+++ b/trunk/ulp/lpp.ulp
@@ -0,0 +1,1023 @@
+#usage "en: Calculate the wire length from pad to pad"
+ "
"
+ "You always have to specify a pair of Elementname + Padname. "
+ "The ULP now calculates the length of the wire connection between the given pads. "
+ "So it is possible to measure the lenght of the trace between two contacts. "
+ "Other PADs/SMDs which are on the way are not taken into consideration. "
+ "Option:/G "
+ "The ULP can be used with option /G, in case you defined a group in the layout before. "
+ "For each signal of the group the ULP searches for a starting point and the PAD/SMD next to it. "
+ " "
+ "Micro, blind and buried vias are supported."
+ "
"
+ "Limitations: "
+ "There shouldn't be several signal branches and vias at the same location, "
+ "otherwise it may happen that the wrong branch will be calculated!
"
+ "Length information of traces that have such a branching point with vias as well as "
+ "non-continuous traces will be especially marked.
"
+ "For displaying possible additional information double-click one of the list entries "
+ "and choose (one of) the available parameter(s) in the menu. "
+ " "
+ "WIREs of an arbitrary PAD/SMD shape within a package will be ignored and might prompt a "
+ "message that tells you that the pad is not routed! "
+ "
"
+ "
"
+ "Autor: info@az-cad.de"
+ ,
+ "de: Berechnet die Länge von Leiterbahnen zwischen zwei PADs."
+ "
"
+ "Es muss immer ein Paar von Elementname + Padname angegeben werden. "
+ "Es wird nur die Länge der Leitung zwischen den beiden angegebenen Pads berechnet. "
+ "Somit ist es möglich eine beliebige Strecke zwischen zwei Kontaktpunkten zu messen. "
+ "Dazwischen liegende PADs/SMDs werden nicht beachtet. "
+ "Option:/G "
+ "Man kann vorher auch eine GROUP definieren und dann mit der Option /G starten. "
+ "Dabei wird von jedem Signal in der Gruppe eine Anfangskoordinate benutzt und bis zum nächsten PAD/SMD gesucht."
+ " "
+ "Micro-, Blind- und Buried-VIAs werden unterstützt."
+ "
"
+ "Einschränkungen: "
+ "Es dürfen keine Mehrfachabzweigungen und VIAs an derselben Koordinate vorkommen, "
+ "da sonst die falsche Abzweigung benutzt werden kann!
"
+ "Längenangaben, bei denen innerhalb der Strecke Mehrfachabzweigung und zugleich VIAs vorkommen sowie "
+ "nicht durchgängig geroutete Leitungen, werden enstprechend markiert.
"
+ "Um mögliche weitere Details anzeigen zu lassen, doppelklicken Sie auf eine Zeile der Liste "
+ "und wählen Sie im sich öffnenden Menü die entsprechenden (Einzel-) Parameter."
+ " "
+ "Die WIREs eines erweiterten PAD/SMD innerhalb eines Package werden nicht berücksichtigt und führen "
+ "u.U. zu der Meldung, dass das Pad nicht geroutet ist!"
+ "
"
+ "
"
+ "Autor: info@az-cad.de"
+
+
+string Version = "1.0.6"; // 2013-01-03 info@az-cad.de
+ // 2013-01-11
+ // 2013-01-13 Option /G
+ // 2013-03-02 Pad am Wire-Ende suchen berichtigt
+ // Signal darf auch aus nur einem Wire-Segement bestehen bei Option /G
+ // 2013-04-16 usage und diverse Meldungen in Englisch
+
+#require 6.0400;
+
+string Option = "";
+enum { null, TypeW, TypeS, TypeP, TypeV };
+string Typ[] = { "null", "Wire", "Smd ", "Pad ", "Via " };
+
+int wx1[]; // X coordinate
+int wy1[]; // Y coordinate
+int wx2[]; // X coordinate
+int wy2[]; // Y coordinate
+int wl[]; // Layer
+int ws[]; // Start Layer for Via & Pad, Smd and Wire
+int we[]; // End Layer for Via & Pad, Smd and Wire == Start Layer
+int wt[]; // Type
+real wlen[]; // Länge des Wire in mm
+real LengthPadPad;
+real LengthDif[];
+string wirelen[]; // Liste der berechneten Längen der Wiresegemente von Pad zu Pad
+int wused[]; // Zähler ob benutzt und zugleich die gefundene Reihenfolge
+ // ein minus Wert signalisiert eine Via
+string wpart[];
+string wpad[];
+int Ucnt = 1;
+int Ncoord = 0; // Anzahl der Koordinaten (WIRE/VIA/SMD/PAD)
+int K2 = 0; // Index auf die aktuell bearbeitete Wire-Koordiante x1y1 x2y2
+int NumSEcoord = 0; // Anzahl aller Start / End-Koordinaten
+int ErrorCoord = 0; // Zeiger auf die Koordinate, an der es klemmt.
+
+string ElementName1;
+string PadName1;
+string ElementName2;
+string padname2;
+string StartElement; // für die Option /G 2013-02-25
+string StartPad;
+string EndElement;
+string EndPad;
+string FoundElement;
+string FoundPad;
+
+int StartPadX, StartPadY, EndPadX, EndPadY;
+int vs[]; // Layerstacktiefe Anfang | VIAs nie als Start benutzen, sondern die Startbedingung
+int ve[]; // Layerstacktiefe Ende | der Wire prüfen, ob er duch die Via angebunden ist.
+
+int LayerStart1, LayerStart2, LayerEnd1, LayerEnd2;
+int LastX, LastY, LastK2, LastI; // da es mehr als eine End-Koordinate geben kann,
+ // muß immer die vorhergehende Koordinate überprüft werden.
+string Header = "diff. mm\t\diff. %\tMM\tSignal\tPart\tPad\tCoord\tPart\tPad\tCoord\tComment";
+
+int Start1X, Start1Y, End2X, End2Y;
+int StartI, EndI, Start2I, End2I; // zum debuggen
+
+string WireCoordText;
+
+// ### ---------------- functions ------------------- ###
+void checkshow(string line) {
+ string s[];
+ int cnt = strsplit(s, line, '\t');
+ string list[];
+ string viewheadline;
+ if (language() == "de") {
+ sprintf(list[0], "mm diff\t%s\tHighlighted das Signal", s[0]);
+ sprintf(list[1], "%c diff\t%s\tHighlighted das Signal", '%', s[1]);
+ sprintf(list[2], "Länge\t%s\tZoomt die Pad-Koordinaten und highlighted das Signal", s[2]);
+ sprintf(list[3], "Signal\t%s\tHighlighted das Signal mit einer Box inkl. Strahl von links oben", s[3]);
+ sprintf(list[4], "Element 1\t%s\tHighlighted das Element mit einer Box inkl. Strahl von links oben", s[4]);
+ sprintf(list[5], "Pad 1\t%s\tZoomt den Pad in die Mitte und highlighted das Element", s[5]);
+ sprintf(list[6], "Start-Koordinate\t%s\tZoomt die Koordinate in die Mitte und highlighted das Signal", s[6]);
+ sprintf(list[7], "Element 2\t%s\tHighlighted das Element mit einer Box inkl. Strahl von links oben", s[7]);
+ sprintf(list[8], "Pad 2\t%s\tZoomt den Pad in die Mitte und highlighted das Element", s[8]);
+ sprintf(list[9], "End-Koordinate\t%s\tZoomt die Koordinate in die Mitte und highlighted das Signal", s[9]);
+ viewheadline = "Zeige\tDetail\tBereich";
+ }
+ else {
+ sprintf(list[0], "mm diff\t%s\thighlight the signal", s[0]);
+ sprintf(list[1], "%c diff\t%s\thighlight the signal", '%', s[1]);
+ sprintf(list[2], "Length\t%s\tzoom in at pad coordinates and highlight the signal", s[2]);
+ sprintf(list[3], "Signal\t%s\thighlight the signal and draw box incl. pointer from upper left corner", s[3]);
+ sprintf(list[4], "Element 1\t%s\thighlight the element and draw a box incl. a pointer from upper left corner", s[4]);
+ sprintf(list[5], "Pad 1\t%s\tzoom and center pad and highlight element", s[5]);
+ sprintf(list[6], "Start coordinate\t%s\tzoom in and center at this coordinate and highlight the signal", s[6]);
+ sprintf(list[7], "Element 2\t%s\thighlight the element and draw a box with a pointer from upper left corner", s[7]);
+ sprintf(list[8], "Pad 2\t%s\tzoom in and center pad and higlight the element", s[8]);
+ sprintf(list[9], "End coordinate\t%s\tzoom in and center at the coordinate and highlight the signal", s[9]);
+ viewheadline = "Show\tDetail\tArea";
+ }
+ int sel;
+ int srt;
+ dlgDialog("List Detail") {
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(220);
+ dlgListView(viewheadline, list, sel, srt) {
+ switch(sel) {
+ case 0 : exit("SHOW "+s[3]);
+ case 1 : exit("SHOW "+s[3]);
+ case 2 : exit("WIN "+s[6]+" "+s[9]+";SHOW @ "+s[3]);
+ case 3 : exit("SHOW @ "+s[sel]);
+ case 4 : exit("SHOW @ "+s[sel]);
+ case 5 : exit("WIN "+s[6]+";"+"SHOW "+s[4]);
+ case 6 : exit("WIN "+s[sel]+";"+"SHOW "+s[sel]);
+ case 7 : exit("SHOW @ "+s[sel]);
+ case 8 : exit("WIN "+s[9]+";"+"SHOW "+s[7]);
+ case 9 : exit("WIN "+s[sel]+";"+"SHOW "+s[sel]);
+ default : ;
+ }
+ }
+ }
+ dlgPushButton("+OK") dlgAccept();
+ };
+}
+
+// *** different length to shortesd signals in percent ***
+string percent( real length, real length100) {
+ string s;
+ if (length100) sprintf(s, "%.3f", (length - length100) / (length100 / 100));
+ else s = "--";
+ return s;
+}
+
+// save data
+void save(string fname, string option) {
+ output(filesetext(fname, option+".lpp"), "wtD") {
+ int n;
+ printf("#%s : Option:%s\n%s\n", filename(argv[0]), option, Header);
+ do {
+ printf("%s\n", wirelen[n]);
+ } while (wirelen[n++]);
+ }
+ exit(0);
+}
+
+real ArcLength(real ang1, real ang2, real radius) {
+ return radius * 2 * PI / 360 * (ang2 - ang1);
+}
+
+real WireLength(real x1, real x2, real y1, real y2) {
+ return sqrt((pow(x2 - x1, 2) + pow(y2 - y1, 2)) );
+}
+
+real addlength(UL_WIRE W) {
+ if (W.curve) {
+ return ArcLength(W.arc.angle1, W.arc.angle2, u2mm(W.arc.radius));
+ }
+ else {
+ return WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1));
+ }
+}
+
+// collect coordinate
+void add(int x1, int y1, int x2, int y2, int lay, int l_start, int l_end, int type, real wirelength) {
+ if (lay == 19) return; // keine Luftlinien benutzen 2013-02-27
+ wx1[Ncoord] = x1;
+ wy1[Ncoord] = y1;
+ wx2[Ncoord] = x2;
+ wy2[Ncoord] = y2;
+ wl[Ncoord] = lay;
+ ws[Ncoord] = l_start;
+ we[Ncoord] = l_end;
+ wt[Ncoord] = type;
+ wlen[Ncoord] = wirelength;
+ wused[Ncoord] = 0; // preset
+ Ncoord++;
+ return;
+}
+
+// get and check signalname on pads
+string get_check_signal(string elementname1, string PadName1, string elementname2, string padname2, int cnt) {
+ string found1 = "", found2 = "";
+ board(B) {
+ B.elements(E) {
+ if (E.name == elementname1) {
+ E.package.contacts(C) {
+ if (C.name == PadName1) {
+ found1 = C.signal;
+ StartPadX = C.x;
+ StartPadY = C.y;
+ if (C.smd) {
+ LayerStart1 = C.smd.layer;
+ LayerStart2 = C.smd.layer;
+ }
+ else if (C.pad) {
+ LayerStart1 = 1;
+ LayerStart2 = 16;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ B.elements(E) {
+ if (E.name == elementname2) {
+ E.package.contacts(C) {
+ if (C.name == padname2) {
+ found2 = C.signal;
+ EndPadX = C.x;
+ EndPadY = C.y;
+ if (C.smd) {
+ LayerEnd1 = C.smd.layer;
+ LayerEnd2 = C.smd.layer;
+ }
+ else if (C.pad) {
+ LayerEnd1 = 1;
+ LayerEnd2 = 16;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (!found1 || !found2 || found1 != found2) {
+ string err;
+ if (!found1) {
+ sprintf(err, "!Pad %s of element %s not found!", PadName1, ElementName1);
+ }
+ if (!found2) {
+ sprintf(err, "!Pad %s of element %s not found!", padname2, ElementName2);
+ }
+ if (found1 != found2) {
+ string fe1 = found1, fe2 = found2;
+ if (!fe1) fe1 = "~no signal~";
+ if (!fe2) fe2 = "~no signal~";
+ sprintf(err, "!Different Signal #%d %s [%s %s] : %s [%s %s]", cnt, fe1, ElementName1, PadName1, fe2, ElementName2, padname2);
+ }
+ dlgMessageBox(err + "\nQuit with SHOW command!", "OK");
+ exit("SHOW "+found1+" "+found2);
+ }
+ return found1;
+}
+
+// suche die weiterführende Koordinate auf dem selben Layer,
+// wenn es nicht mehr weiter geht, suche nach einer Via,
+// und dann wieder weiter.
+int getnextcoord(int i, int k) {
+ int x, y, l;
+ l = wl[i]; // der Layer des Wire
+ if (k == 2) { // wenn 2 suche nach Koordinate 1
+ x = wx1[i];
+ y = wy1[i];
+ }
+ else { // wenn 1 suche nach Koordinate 2
+ x = wx2[i];
+ y = wy2[i];
+ }
+
+ for (int n=0; n= LayerEnd2) {
+ if (x == EndPadX && y == EndPadY) {
+ K2 = 0;
+ return n; // Ende durch Via erreicht
+ }
+ }
+ if (via >= 0) { // ist eine Via an diesem "Ende", dann suche in einem anderen Layer weiter.
+ for (int n = 0; n = LayerEnd2) { // passt der Layer
+ if (K2 == 1) { // K2 == 1
+ if (EndPadX == wx2[i] && EndPadY == wy2[i]) { // suche nach der anderen Seite wie k
+ return i;
+ }
+ }
+ else { // dann K2 == 2
+ if (EndPadX == wx1[i] && EndPadY == wy1[i]) { // suche nach der anderen Seite von k
+ return i;
+ }
+ }
+ }// Ende von if gleich mal prüfen ob das Ende schon erreicht ist
+ /* durchsuche die Liste auf die nachfolgende Koordinate */
+
+ /****** VIAs sind in der Suche eingeschlossen, werden also übersprungen. ******/
+ i = getnextcoord(i, K2); // K2 ist Global! Eine Funktion kann nur einen Return-Wert zurückgeben.
+ /****** VIAs sind in der Suche eingeschlossen, werden also übersprungen. ******/
+ if (i < 0) return i; /*** hier ist es zu Ende, wenn keine weiterführende Koordinate gefunden wurde ***/
+
+
+ if (K2 == 1) { // K2 == 1
+ if (EndPadX == wx2[i] && EndPadY == wy2[i]) { // suche nach der anderen Seite wie k
+ LengthPadPad += wlen[i]; // 2013-03-02
+ return i;
+ }
+ }
+ else { // dann K2 == 2
+ if (EndPadX == wx1[i] && EndPadY == wy1[i]) { // suche nach der anderen Seite von k
+ LengthPadPad += wlen[i]; // 2013-03-02
+ return i;
+ }
+ }
+ cntdebug++;
+ } while(i >= 0); /********** suche durch die Liste bis zum End-Pad **********/
+
+ // index zum zuletzt gefundenen Wire der auf den PAD/SMD zeigt
+ return i; // - negative Zahl heisst das Ende nicht gefunden!
+}
+
+// überprüfe ob der Wire über eine Via an den SMD (Pad) angebuden ist.
+int viaandindung(int l, int cntv) {
+ int fehler = 0;
+ string v;
+ for (int cnt = 0; cnt < cntv; cnt++) {
+ if (l >= vs[cnt] && l <= ve[cnt]) return 1; // evtl. noch die Stacktiefe auf die Länge addieren?
+ sprintf(v, "WIRE layer %d : VIA Layer %d-%d", l, vs[cnt], ve[cnt]);
+ }
+ dlgMessageBox(v);
+ return 0;
+}
+
+/*** Hauptschleife der Option [Elementname Pad Elementname Padname] ***/
+// ermittle Start-Koordinaten in den Wire-Koordinaten für dieses Signal
+real checkcoordpadpad(string sigName) {
+ // 2013-01-09 info@az-cad.de
+ NumSEcoord = 0;
+ int cntstart = 0;
+ int cntend = 0;
+ int indexstart[];
+ int wk[];
+ int x;
+ int cnti = 0;
+ int cntv = 0;
+ for (x = 0; x < Ncoord; x++) { // Suche zuerst eventuelle Start-VIAs
+ if (StartPadX == wx1[x] && StartPadY == wy1[x] && (wt[x] == TypeV)) { // Via hat 1. Koordinate gleich wie 2. Koordinate
+ vs[cntv] = ws[x];
+ ve[cntv] = we[x];
+ cntv++;
+ }
+ }
+
+ for (x = 0; x < Ncoord; x++) {
+ // Eine VIA nie als Startbedingung benutzen, sondern gleich die entsprechenden Wire suchen,
+ // die an der Via angebunden sind.
+ if (StartPadX == wx1[x] && StartPadY == wy1[x] && wt[x] == TypeW) { // Die erste Seite des Wire
+ if (LayerStart1 == ws[x] || viaandindung(ws[x], cntv)) {
+ indexstart[cntstart] = x;
+ wk[cntstart] = 1; // die Startseite
+ LayerStart1 = ws[x];
+ LayerStart2 = we[x];
+ cntstart++;
+ NumSEcoord++;
+ }
+ }
+ if (StartPadX == wx2[x] && StartPadY == wy2[x] && wt[x] == TypeW) { // die zweite Seite des Wire
+ if (LayerStart1 == ws[x] || viaandindung(ws[x], cntv)) {
+ indexstart[cntstart] = x;
+ wk[cntstart] = 2; // die Startseite
+ LayerStart1 = ws[x];
+ LayerStart2 = we[x];
+ cntstart++;
+ NumSEcoord++;
+ }
+ }
+ // prüfe auch ob die Enden geroutet sind
+ if (EndPadX == wx1[x] && EndPadY == wy1[x] && (wt[x] == TypeW || wt[x] == TypeV)) {
+ cntend++;
+ }
+ if (EndPadX == wx2[x] && EndPadY == wy2[x] && (wt[x] == TypeW || wt[x] == TypeV)) {
+ cntend++;
+ }
+ }
+
+ string errorinfo = "";
+ if (!cntstart) {
+ if (language() == "de") sprintf(errorinfo, "%s PAD %s nicht geroutet!", ElementName1, PadName1);
+ else sprintf(errorinfo, "%s PAD %s not routed!", ElementName1, PadName1);
+ dlgMessageBox(errorinfo);
+ sprintf(errorinfo, "WIN (%.fmm %.fmm);SHOW (%.fmm %.fmm)", u2mm(StartPadX), u2mm(StartPadY), u2mm(StartPadX), u2mm(StartPadY));
+ exit(errorinfo);
+ }
+ if (!cntend) {
+ if (language() == "de") sprintf(errorinfo, "%s PAD %s nicht geroutet!", ElementName2, padname2);
+ sprintf(errorinfo, "%s PAD %s not routed!", ElementName2, padname2);
+ dlgMessageBox(errorinfo);
+ sprintf(errorinfo, "WIN (%.fmm %.fmm);SHOW (%.fmm %.fmm)", u2mm(EndPadX), u2mm(EndPadY), u2mm(EndPadX), u2mm(EndPadY));
+ exit(errorinfo);
+ }
+
+ int foundend = -1;
+ int n = 0;
+ if (Ncoord > 1) {
+ if (NumSEcoord) {
+ foundend = -1;
+ // ### loop ###
+ for (int s = 0; s < cntstart; s++) { // durchsuche alle Start-Koordinaten
+ LengthPadPad = 0; // die Stelle in der Funktion Pad-Pad zum reseten der Gesamtlänge
+ foundend = getendpadpad(indexstart[s], wk[s], sigName); // suche das Ende (PAD/SMD)
+ if (foundend >= 0) return LengthPadPad;
+ }
+ }
+ }
+
+ return LengthPadPad *= -1.0; // * -1.0; // erzeuge im Fehlerfall ein negatives Vorzeichen
+ //return LengthPadPad;
+}
+
+// ******************************************************
+// suche die weiterführende Koordinate auf dem selben Layer,
+// wenn es nicht mehr weiter geht, suche nach einer Via,
+// und dann wieder weiter.
+int getnextcoordpad(int i, int k) {
+ int x, y, l;
+ l = wl[i]; // der Layer des Wire
+
+ if (k == 2) { // wenn 2 suche nach Koordinate 1
+ x = wx1[i];
+ y = wy1[i];
+ }
+ else { // wenn 1 suche nach Koordinate 2
+ x = wx2[i];
+ y = wy2[i];
+ }
+
+ int e;
+ for (e = Ncoord-1; e; e--) { // suche vom Ende der Liste her, die Pad/Smd stehen am Schluß
+ if (wt[e] == TypeP || wt[e] == TypeS) { // in Type PAD und SMD suchen
+ if (ws[e] >= ws[i] && we[e] <= we[i]) { // Trifft der Layer des Wire auf den PAD
+ if (x == wx1[e] && y == wy1[e]) {
+ wused[e] = Ucnt++; // zum debuggen
+ LastI = e;
+ return e;
+ }
+ }
+ }
+ }
+ // in Type WIRE suchen und mit gleichen Layer
+ for (int n=0; n= 0) { // ist eine Via an diesem "Ende", dann suche in einem anderen Layer weiter.
+ // gleich mal prüfen ob die Via einen Pad/Smd erreicht?
+ for (e = Ncoord-1; e; e--) { // suche vom Ende der Liste her, die Pad/Smd stehen am Schluß
+ if (wt[e] == TypeP || wt[e] == TypeS) { // in Type PAD und SMD suchen
+ if (x == wx1[e] && y == wy1[e]) {
+ if (ws[e] >= ws[n] && we[e] <= we[n]) { // Trifft der Layer des Via auf den PAD
+ wused[e] = Ucnt++; // zum debuggen
+ LastI = e;
+ return e;
+ }
+ }
+ }
+ }
+
+ for (int n = 0; n = ws[i] && we[e] <= we[i]) { // Trifft der Layer des Wire auf den Layer des PAD
+ if (x == wx1[e] && y == wy1[e]) {
+ wused[e] = Ucnt++; // zum debuggen
+ LastI = e;
+ return e;
+ }
+ }
+ }
+ }
+
+ // nichts gefunden? Dann suche nach Via für einen Layer wechsel
+ int via = -1;
+ int n;
+ for (n = 0; n= ws[i] && we[n] <= we[i]) { // Trifft der Layer des Wire auf den Layer des PAD
+ if (x == wx1[n] && y == wy1[n]) {
+ via = n;
+ wused[n] = Ucnt*-1; // zum debuggen
+ break;
+ }
+ }
+ }
+ }
+
+ if (via >= 0) { // ist eine Via an diesem "Ende", dann suche in einem anderen Layer weiter.
+ // gleich mal prüfen ob die Via einen Pad/Smd erreicht?
+ for (e = Ncoord-1; e; e--) { // suche vom Ende der Liste her, die Pad/Smd stehen am Schluß
+ if (wt[e] == TypeP || wt[e] == TypeS) { // in Type PAD und SMD suchen
+ if (x == wx1[e] && y == wy1[e]) {
+ if (ws[e] >= ws[n] && we[e] <= we[n]) { // Trifft der Layer des Via auf den PAD
+ wused[e] = Ucnt++; // zum debuggen
+ LastI = e;
+ return e;
+ }
+ }
+ }
+ }
+ }
+ //
+ for (e = Ncoord-1; e; e--) { // suche vom Ende des Array, die Pad/Smd stehen am Schluß
+ if (x == wx1[e] && y == wy1[e] && (wt[e] == TypeP || wt[e] == TypeS)) { // ist der Type ein SMD oder PAD
+ if (ws[e] <= ws[i] && we[e] >= we[i]) { // Trifft der Layer des Wire auf den PAD
+ LastX = x;
+ LastY = y;
+ LastI = e;
+ return e; // 2013-01-15
+ }
+ }
+ }
+
+ i = getnextcoordpad(i, K2); // K2 ist Global! Weil eine Funktion nur einen Return-Wert zurückgeben kann.
+
+ cnt++;
+ } while(i >= 0);
+ LastI = i;
+ return i; // 2013-01-15 Ende nicht gefunden
+}
+
+
+// Option Gruppe markiert. Suche nach dem ersten Pad/Smd in der Kette
+real searchgrouppad(int n, int k, string signame) {
+ LengthPadPad = 0.0; // die Einzig wahre Stelle zum reseten der Gesamtlänge des Signal in der Group-Option
+ int foundend = -1;
+ foundend = getendgrouppad(n, k, signame); // die Startseite k wird übergeben
+
+ if (foundend >= 0) {
+ FoundElement = wpart[foundend];
+ FoundPad = wpad[foundend];
+ return LengthPadPad;
+ }
+ return LengthPadPad * -1.0; // erzeuge im Fehlerfall ein negatives Vorzeichen
+}
+
+
+// Option Gruppe markiert. Messe die Wire des markierten Signal
+real measuringgroup(UL_WIRE W, UL_SIGNAL S, int wx, int wy) { // samme alle koordinaten und suche nach wx1 wy1
+ Ncoord = 0;
+ S.wires(W) { // zuerst alle Wire sammeln.
+ add(W.x1, W.y1, W.x2, W.y2, W.layer, W.layer, W.layer, TypeW, addlength(W));
+ }
+ S.vias(V) { // dann die Vias sammeln
+ add(V.x, V.y, V.x, V.y, 18, V.start, V.end, TypeV, 0); // hier evtl. die Bohrtiefe aus den DRC-Daten berechnen 2013-01-02
+ }
+ S.contactrefs(C) {
+ if (C.contact) { // jetzt noch die CONTACTs sammeln
+ wpart[Ncoord] = C.element.name;
+ wpad[Ncoord] = C.contact.name;
+ if (C.contact.smd) {
+ add(C.contact.x, C.contact.y, C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, TypeS, 0);
+ }
+ else {
+ add(C.contact.pad.x, C.contact.pad.y, C.contact.pad.x, C.contact.pad.y, 17, 1, 16, TypeP, 0);
+ }
+ }
+ else {
+ if (language() == "de") dlgMessageBox("Signal '"+ S.name + "' ohne Contactrefs gefunden!\nPrüfen Sie die Konsistenz und evtl. korrupte Signale!", "OK");
+ else dlgMessageBox("Found signal '"+ S.name + "' without contactrefs!\nCheck consistency and corrupted signals!", "OK");
+ exit(-1);
+ }
+ }
+ // Das Problem beim Selektieren ist, man kann mit Group keinen Wire in der Mitte selektieren,
+ // sondern nur an den Enden.
+ real len = 0.0;
+ int cntw = 0;
+ int n;
+ /** Reset all global strings **/
+ StartPad = "";
+ FoundPad = "";
+ StartElement = "";
+ FoundElement = "";
+ EndPad = "";
+ FoundPad = "";
+ EndElement = "";
+ FoundElement = "";
+
+ string h;
+ for (n = 0; n < Ncoord; n++) {
+ if (wx == wx1[n] && wy == wy1[n] && TypeW == wt[n]) {
+ len += searchgrouppad(n, 1, S.name);
+ StartPad = FoundPad;
+ StartElement = FoundElement;
+ Start1X = LastX;
+ Start1Y = LastY;
+ len += searchgrouppad(n, 2, S.name) - wlen[n]; // suche auch nach der anderen Seite
+ EndPad = FoundPad;
+ EndElement = FoundElement;
+ End2X = LastX;
+ End2Y = LastY;
+ cntw++;
+ n = Ncoord; // 2013-02-27 den Wire nur einmal benutzen
+ }
+ else {
+ if (wx == wx2[n] && wy == wy2[n] && TypeW == wt[n]) {
+ len += searchgrouppad(n, 2, S.name);
+ StartPad = FoundPad;
+ StartElement = FoundElement;
+ Start1X = LastX;
+ Start1Y = LastY;
+ len += searchgrouppad(n, 1, S.name) - wlen[n]; // suche auch nach der anderen Seite
+ EndPad = FoundPad;
+ EndElement = FoundElement;
+ End2X = LastX;
+ End2Y = LastY;
+ cntw++;
+ n = Ncoord; // 2013-02-27 den Wire nur einmal benutzen
+ }
+ }
+ }
+ if (cntw > 2) {
+ string h;
+ if (language() == "de") sprintf(h, "!Signal %s\nStartkoordinate enthält Abzweigung!", S.name);
+ else sprintf(h, "!Signal %s\nBranching on starting coordinate!", S.name);
+ if (dlgMessageBox(h, "OK", "ESC") != 0) {
+ string s;
+ sprintf(s, "WIN (%.6fmm %.6fmm);", u2mm(wx), u2mm(wy) );
+ exit(s);
+ }
+ }
+ return len;
+}
+
+// Option Gruppe markiert, suche nach Wire im Signal die in der Gruppe enthalten sind.
+int usegroup(void) {
+ int l = 0;
+ board(B) {
+ B.signals(S) {
+ if (ingroup(S)) { // Signal ist in der Group
+ int nx = 0;
+ S.wires(W) {
+ if (ingroup(W)) {
+ real len = measuringgroup(W, S, W.x1, W.y1); // sammel alle koordinaten und suche nach wx1 wy1
+ LengthDif[l] = len;
+ if (StartElement == EndElement && StartPad == EndPad) {
+ sprintf(wirelen[l], "%s\t%s\t?%s\t?%s\t(%.9fmm %.9fmm)\t?%s\t?%s\t(%.9fmm %.9fmm)",
+ "*start==end*", S.name,
+ StartElement, StartPad,
+ u2mm(Start1X), u2mm(Start1Y),
+ EndElement, EndPad,
+ u2mm(End2X), u2mm(End2Y)
+ );
+ }
+ else if ((!StartElement && !StartPad) && EndElement && EndPad) {
+ sprintf(wirelen[l], "%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)",
+ "*not routed*", S.name,
+ "???", "???",
+ u2mm(Start1X), u2mm(Start1Y),
+ EndElement, EndPad,
+ u2mm(End2X), u2mm(End2Y)
+ );
+ }
+ else if (StartElement && StartPad && (!EndElement && !EndPad)) {
+ sprintf(wirelen[l], "%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)",
+ "*not routed*", S.name,
+ StartElement, StartPad,
+ u2mm(Start1X), u2mm(Start1Y),
+ "???", "???",
+ u2mm(End2X), u2mm(End2Y)
+ );
+ }
+ else {
+ if (len < 0.0) {
+ LengthDif[l] = 0.0; // 2013-02-27
+ sprintf(wirelen[l], "*%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)",
+ "not found", S.name,
+ StartElement, StartPad,
+ u2mm(Start1X), u2mm(Start1Y),
+ EndElement, EndPad,
+ u2mm(End2X), u2mm(End2Y)
+ );
+ }
+ else {
+ sprintf(wirelen[l], "%.9f\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)",
+ len, S.name,
+ StartElement, StartPad,
+ u2mm(Start1X), u2mm(Start1Y),
+ EndElement, EndPad,
+ u2mm(End2X), u2mm(End2Y)
+ );
+ }
+ }
+ l++;
+ break; // W-Schleife abbrechen, nur einen Wire (Koordinate) aus der Gruppe benutzen
+ }
+ }
+ }
+ }
+ if (!l) {
+ if (language() == "de") dlgMessageBox("!Keine Gruppe definiert. ", "OK");
+ else dlgMessageBox("!No group defined. ", "OK");
+ exit(-4);
+ }
+ }
+ return l;
+}
+
+// ### main ###
+if (board) {
+ board(B) {
+ int l = 0;
+ if (argc == 2 && argv[1] == "/G") { // benutze Option Group
+ Option = "~group";
+ l = usegroup();
+ } // Ende von benutze definierte Group
+
+ else { // benutze Option [Element Pad Element Pad]
+ Option = "~pad-pad";
+ int cnt = argc-1;
+ if (argc > 1) {
+ string h;
+ if (cnt < 4) {
+ if (language() == "de") sprintf(h, "!Zu wenig Parameter: %d", cnt);
+ else sprintf(h, "!Insufficient number of parameters: %d", cnt);
+ dlgMessageBox(h, "OK");
+ exit(-3);
+ }
+ else {
+ if (cnt & 3 != 2) {
+ if (language() == "de") sprintf(h, "!Ungenügende Anzahl von Parametern: %d", cnt);
+ else sprintf(h, "!Insufficient number of parameters: %d", cnt);
+ dlgMessageBox(h, "OK");
+ exit(-2);
+ }
+ }
+ }
+ else {
+ dlgDialog("HELP: Lenght PAD PAD") {
+ dlgLabel(usage);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ exit(0);
+ }
+ l = 0;
+ string sig;
+ for (int n = 1; n <= cnt; n+=4) {
+ ElementName1 = strupr(argv[n]);
+ PadName1 = strupr(argv[n+1]);
+ ElementName2 = strupr(argv[n+2]);
+ padname2 = strupr(argv[n+3]);
+
+ sig = get_check_signal(ElementName1, PadName1, ElementName2, padname2, n);
+ string h;
+ sprintf(h, "%s %s (%.9f_%.9f) %s %s (%.9f_%.9f)\n",
+ ElementName1, PadName1, u2mm(StartPadX), u2mm(StartPadY),
+ ElementName2, padname2, u2mm(EndPadX), u2mm(EndPadY)
+ );
+ WireCoordText += h;
+
+ B.signals(S) {
+ status(" check "+sig);
+ if (S.name == sig) { // Der Signalname der Pads ist gefunden.
+ Ncoord = 0;
+ S.wires(W) { // zuerst alle Wire sammeln. 2013-01-09
+ add(W.x1, W.y1, W.x2, W.y2, W.layer, W.layer, W.layer, TypeW, addlength(W));
+ }
+ S.vias(V) { // dann die Vias sammeln
+ add(V.x, V.y, V.x, V.y, 18, V.start, V.end, TypeV, 0); // hier evtl. die Bohrtiefe aus den DRC-Daten berechnen 2013-01-02
+ }
+ S.contactrefs(C) {
+ if (C.contact) { // jetzt noch den CONTACT ermitteln, das sind die letzen beiden. 2013-01-09
+ if (C.contact.smd) {
+ add(C.contact.x, C.contact.y, C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, TypeS, 0);
+ }
+ else {
+ add(C.contact.pad.x, C.contact.pad.y, C.contact.pad.x, C.contact.pad.y, 17, 1, 16, TypeP, 0);
+ }
+ }
+ }
+ real len = checkcoordpadpad(S.name); // Suche die Endkoordinaten und ermittle die Länge
+ LengthDif[l] = len;
+ if (len < 0.0) {
+ sprintf(wirelen[l++], "%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)",
+ "*not routet*", // markiere nicht geroutete Verbindung
+ S.name,
+ ElementName1, PadName1, u2mm(StartPadX), u2mm(StartPadY),
+ ElementName2, padname2, u2mm(wx2[ErrorCoord]), u2mm(wy2[ErrorCoord])
+ );
+ }
+ else {
+ sprintf(wirelen[l++], "%.9f\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)",
+ len, S.name,
+ ElementName1, PadName1, u2mm(StartPadX), u2mm(StartPadY),
+ ElementName2, padname2, u2mm(EndPadX), u2mm(EndPadY)
+ );
+ }
+ }
+ }
+ }
+ } // Ende von benutzen Element Pad Element Pad
+
+ int index[];
+ sort(l, index, LengthDif);
+ real null_length = LengthDif[index[0]];
+ string h;
+ for (int i = 0; i < l; ++i) {
+ sprintf(h, "%.6f\t%s\t",
+ LengthDif[index[i]] - null_length,
+ percent(LengthDif[index[i]], null_length)
+ );
+ wirelen[index[i]] = h + wirelen[index[i]];
+ }
+
+ int sel = -1;
+ int srt = 0 ;
+ dlgDialog("Lenght PAD PAD" + Option) {
+ dlgLabel("Option:" + Option);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(200);
+ dlgListView(Header, wirelen, sel, srt) dlgAccept();
+ }
+ if (language() == "de") dlgLabel("Um Details eines Eintrag anzuzeigen, selektieren (doppelklicken) Sie eine Zeile.");
+ else dlgLabel("To show details of a list entry, select (double click) a line.");
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("&Save") { dlgAccept(); save(B.name, Option); }
+ dlgStretch(1);
+ dlgLabel(Version);
+ }
+ };
+ if (sel >= 0) checkshow(wirelen[sel]);
+ exit(0);
+ }
+}
+
+else {
+ if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Board", "OK");
+ else dlgMessageBox("Start this ULP in a Board", "OK");
+}
diff --git a/trunk/ulp/ltspice.ulp b/trunk/ulp/ltspice.ulp
new file mode 100644
index 00000000..09cc1055
--- /dev/null
+++ b/trunk/ulp/ltspice.ulp
@@ -0,0 +1,4603 @@
+#usage "en:Interface to the simulation software LTspice IV "
+ "Export of EAGLE schematics and libraries into LTspice and import of schematics and symbols from LTspice
"
+ "RUN ltspice /E [/S][/G] "
+ "RUN ltspice /I [/S][/G] "
+ "RUN ltspice /? "
+ " /E == Export "
+ " /I == Import "
+ " /? == System info "
+ "Option /S opens the SETUP menu for default settings. "
+ "Option /G exports a group previously created in the schematic with the GROUP command. "
+ "RUN ltspice /I 'importfilename' [RELOAD]
"
+ "Start this ULP with the option /E from a Deviceset (Library), in order to export the current Deviceset. "
+ "Use the ULP without an option in order to export the whole library. "
+ "For the import you can choose the option Import all symbols from directory in the dialog. Select a symbol file then, "
+ "and all symbols from the current directory will be imported into an EAGLE library."
+ "
"
+ "The option RELOAD is planned to check a schematic for modifications. "
+ "This option is not implemented yet! 2012-09 "
+ "
"
+ "SpiceOrder "
+ "The so-called SpiceOrder will be defined in layer 99 'SpiceOrder' as a text. "
+ "It has to be placed exactly at the connection point (coordinate) of the pin. "
+ "While exporting an EAGLE schematic the ULP checks for SpiceOrder and SpiceModel. "
+ "If SpiceOrder is not defined, EAGLE loads the Deviceset and starts spiceorder.ulp. "
+ "This ULP helps to assign pins of the symbol and its Spiceorder. This assignment will be written "
+ "as a text at the pin connection point in layer 99 automatically."
+ "
"
+ "SpiceModel "
+ "SpiceModel is the simulation model. It will be attached with the help of the attribute "
+ "SPICEMODEL in the device. Therefore the LTC icon in the device editor contains the entry SpiceModel."
+ "
"
+ "Value2 "
+ "For some components you have to assign the additional Value2. It has to be created with an attribute, "
+ "as well. There is a further entry in the LTC icon's menu for this."
+ "
"
+ "For an error-free schematic import we need correctly and clearly defined libraries. "
+ "The library lt-spice-simulation.lbr has a special status: "
+ "It should not appear in the list of USEd libraries. Otherwise the ADD dialog will open "
+ "for placing resistors while the import script is running. "
+ "The simulation resistors \"Rload\" are treated like normal resistors in LTSpice. "
+ "Just the device name gets the extension \"_RLOAD\". "
+ "
"
+ "lt-spice-simulation.lbr contains only devices that are used for the simulation, like "
+ "power supply, voltage generator, loads, measurement equipment and so on.). "
+ "All those devices have an attribute with the name \"_EXTERNAL_\". So you don't have to "
+ "assign a package; such components are not transferred into the board and do not "
+ "appear in the bill of materials. "
+ "
"
+ "A FLAG comming from LTspice results in EAGLE in a simple LABEL that is placed on the net line (FLAG 1248 176 BI_Port). "
+ "There is no rotation given for FLAGs. The rotation has to be determined with the help of the orientation of the referring line! "
+ "It can happen that a FLAG is placed onto a pin directly. It's not possible to determine the rotation then. "
+ "In such a case you have to take care on this matter manually! "
+ "
"
+ "An IOPIN is reflected as a cross-reference label in EAGLE. (IOPIN 1248 176 BiDir) "
+ "There is no equivalent for IOPIN in EAGLE, so we use a cross-reference (XREF) label for BI_Port, In and Out."
+ "
"
+ "Supply symbols (FLAGs) like 0 or COM, are taken from lt-supply.lbr directly. "
+ "If you have to use other supply symbols (not 0 and COM), you have to create them in LTspice as *.asy files "
+ "containing the spice symbols. "
+ "Example: "
+ "Version 4 "
+ "SymbolType CELL "
+ "LINE Normal 0 11 0 16 "
+ "LINE Normal -11 14 0 0 "
+ "LINE Normal 0 0 11 14 "
+ "LINE Normal 0 11 -11 14 "
+ "LINE Normal 11 14 0 11 "
+ "TEXT 0 -4 Bottom 2 +3.3V "
+ "SYMATTR Prefix X "
+ "SYMATTR SpiceModel node.sub "
+ "SYMATTR Value node "
+ "SYMATTR Value2 node "
+ "PIN 0 16 NONE 36 "
+ "PINATTR PinName +3.3V "
+ "PINATTR SpiceOrder 1 "
+ "
"
+ "In order to define a supply device in an EAGLE library, place a supply pin in a symbol and "
+ "define a device with ATTRIBUTE 'SPICEMODEL' 'node.sub'; and ATTRIBUTE 'VALUE2' 'node'; . "
+ "These two attributes make the device 'spice-usable'. "
+ "In the transferred schematic you have to place a FLAG with all the neccessary information at the pin's position."
+ "
"
+ "When you start this ULP, EAGLE searches for the path of the LTspice executable in the file eaglerc.usr. If it "
+ "is not yet stored there, it searches in the default program folder and stores it in eaglerc.usr then."
+ " "
+ "For the export of a schematic, EAGLE checks the availability of all necessary LTspice symbols .asy. "
+ "If there is one is missing, EAGLE opens the referring deviceset in the EAGLE library. "
+ "
"
+ "There is a check for the SpiceOrder texts in layer 99 SpiceOrder. "
+ "In devices EAGLE searches for the attribute 'SPICEMODEL'. If one of these items is missing, "
+ "EAGLE opens the library editor. Please add the missing definitions. "
+ "For the SpiceOrder there will be called an ULP automatically."
+ "
"
+ "The names of the symbols in EAGLE must be different compared to the names of the LTspice symbols. "
+ "Example: If you export a symbol/device with name 'DIODE' from EAGLE, LTspice takes its own "
+ "symbol with name 'diode'. To insure that the EAGLE symbol is taken it has to have a unique name. "
+ "You can also combine device name and library name. The library name then reflects a subfolder in the "
+ "LTspice folder /sym . 2012-10-09"
+ "
"
+ "The SPICEMODEL attribute can be created through an entry in the LTC icon menu."
+ " "
+ "This icon is created through the file eagle.scr. It will be executed automatically when you are "
+ "creating a new device or symbol. The icon images (PNG files) should be in "
+ "the subfolder bin of the EAGLE folder."
+ "
"
+ "Export/import Libraries: "
+ "Libraries imported from LTspice have to be created in the subfolder ./lbr/ltspice/... "
+ "So the export function recognizes that the libary file comes from LTspice. "
+ "When you start the ULP for the first time it copies some files to LTspice. "
+ "They have to be copied into the following folder structure: "
+ "./eagle-x.x.x/ "
+ " - /misc/ "
+ " - - /ltspice/ "
+ " - - - /lib/ "
+ " - - - - /sub/ note.sub and other .sub files "
+ " - - - - /sym/ "
+ " - - - - - /eagle/ "
+ " - - - - - - /lbrname/ exported symbols from the EAGLE libraries "
+ " - - - /scr/ Connect scripts (provided by LT) "
+ " "
+ "EAGLE libraries will be created/copied in(to) the following folders: "
+ "./LTC/LTspiceIV/lib/sym/eagle/ "
+ "Each library exported results in a subfolder with the library name. "
+ "
"
+ "Author: alf@cadsoft.de"
+ ,
+
+ "de:Schnittstelle zur Simulationssoftware LTspiceIV "
+ "Export von EAGLE-Schaltplänen und Bibliothekssymbolen nach LTspiceIV und Import von Schaltplänen und Symbolen aus LTspiceIV
"
+ "RUN ltspice /E [/S][/G] "
+ "RUN ltspice /I [/S][/G] "
+ "RUN ltspice /? "
+ " /E == Export "
+ " /I == Import "
+ " /? == Systeminfo "
+ "Option /S öffnet das SETUP-Menü für Grundeinstellungen. "
+ "Option /G exportiert eine Gruppe, die vorher im Schaltplan mit GROUP definiert wurde. "
+ "RUN ltspice /I 'importfilename' [RELOAD]
"
+ "Startet man das ULP mit der Option /E aus einem Deviceset (Bibliothek), wird dieses eine Deviceset exportiert. "
+ "Gibt man keine Option an, wird die gesamte Bibliothek exportiert. "
+ "Beim Import kann man im Dialog die Option Import all symbols from directory aktivieren. Wählen Sie dann eine Symboldatei aus, "
+ "werden alle Symbole aus dem Verzeichnis in die EAGLE-Bibliothek importiert."
+ "
"
+ "Die Option RELOAD soll in Zukunft den Schaltplan auf Änderungen prüfen. "
+ "Diese Option ist noch nicht implementiert! 2012-09 "
+ "
"
+ "SpiceOrder "
+ "Die sogenannte SpiceOrder wird im Layer 99 'SpiceOrder' als Text abgelegt. Dieser muss exakt auf dem Kontaktpunkt (Koordinate) des Pins liegen. "
+ "Beim Export eines EAGLE-Schaltplans wird geprüft, ob SpiceOrder und SpiceModel definiert sind. "
+ "Fehlt die SpiceOrder, lädt EAGLE das entsprechende Deviceset und startet spiceorder.ulp. "
+ "Mit Hilfe dieses ULPs ordnet man den Symbolpins die SpiceOrder zu. Diese Zuordnung wird automatisch an "
+ "den Pins als Text im Layer 99 platziert."
+ "
"
+ "SpiceModel "
+ "Das SpiceModel ist das Simulationsmodell. Es wird in EAGLE im Device "
+ "als Attribut SPICEMODEL hinterlegt. Das LTC-Icon im Device-Editor enthält dazu den Eintrag SpiceModel."
+ "
"
+ "Value2 "
+ "Für manche Bauteile benötigt man zusätzlich Value2. Dieser kann ebenfalls als Attribut "
+ "angelegt werden. Auch hierzu gibt es eine Option im Menü des LTC-Icons."
+ "
"
+ "Für einen fehlerfreien Schaltplan-Import benötigt man passende und eindeutige Bibliotheken. "
+ "Die Bibliothek lt-spice-simulation.lbr hat einen Sonderstatus: "
+ "Sie darf nicht in der USE-Liste enthalten sein, da ansonsten beim Ausführen des Scripts "
+ "und Einfügen von Widerständen das ADD-Menu geöffnet wird. "
+ "Die Simulationswiderstände \"Rload\" werden in LTSpice wie normale Widerstände behandelt, "
+ "nur der Devicename wird mit dem Anhang \"_RLOAD\" erweitert. "
+ "
"
+ "lt-spice-simulation.lbr enthält nur Devices, die für die Simulation benötigt werden, wie "
+ "z.B. (Stromquellen, Spannungsquellen, Lasten, Messgeräte etc.). "
+ "In diesen Devices ist jeweils ein Attribut mit dem Namen \"_EXTERNAL_\" angelegt. Dadurch muss kein Package "
+ "zugeordnet werden; es handelt sich hierbei um Bauteile, die nicht in das Board übertragen "
+ "und auch nicht in die Stückliste aufgenommen werden. "
+ "
"
+ "Ein FLAG aus LTspice wird in EAGLE als einfaches LABEL dargestellt und auf der Netzlinie platziert (FLAG 1248 176 BI_Port). "
+ "Bei FLAGs wird keine Rotation angegeben. Die Rotation muss anhand der Ausrichtung der letzten zugehörigen Linie "
+ "ermittelt werden! Es kann auch vorkommen dass FLAGs direkt auf Pins gesetzt werden. Dann ist es nicht möglich die "
+ "Rotation zu ermitteln. In diesem Fall muss man sich manuell um die korrekte Ausrichtung des Labels anhand des "
+ "Pins im Symbol kümmern! "
+ "
"
+ "Ein IOPIN wird in EAGLE als LABEL mit Querverweis dargestellt. (IOPIN 1248 176 BiDir) "
+ "Da es in EAGLE keine Pendant für IOPIN gibt, wird für BI_Port, In und Out ein Label mit Querverweis (XREF) platziert."
+ "
"
+ "Supply-Symbole (FLAG) wie 0 oder COM, werden direkt aus der lt-supply.lbr genommen. "
+ "Werden andere Supply-Symbole (ausser 0 und COM) benutzt, müssen diese in LTspice als *.asy-Datei "
+ "mit dem entsprechenden Spicemodel angelegt werden. "
+ "Beispiel: "
+ "Version 4 "
+ "SymbolType CELL "
+ "LINE Normal 0 11 0 16 "
+ "LINE Normal -11 14 0 0 "
+ "LINE Normal 0 0 11 14 "
+ "LINE Normal 0 11 -11 14 "
+ "LINE Normal 11 14 0 11 "
+ "TEXT 0 -4 Bottom 2 +3.3V "
+ "SYMATTR Prefix X "
+ "SYMATTR SpiceModel node.sub "
+ "SYMATTR Value node "
+ "SYMATTR Value2 node "
+ "PIN 0 16 NONE 36 "
+ "PINATTR PinName +3.3V "
+ "PINATTR SpiceOrder 1 "
+ "
"
+ "Dazu das Simulationsmodell: "
+ "* Copyright (C) Linear Technology Corp. 1998, 1999, 2000. All rights reserved. "
+ "* "
+ ".subckt node 1 "
+ "R1 1 1 0 "
+ ".ends node "
+ "
"
+ "Um ein Supply-Device in einer EAGLE-Bibliothek anzulegen, platziert man im Symbol einen Supply-Pin und "
+ "legt dann ein Device mit ATTRIBUTE 'SPICEMODEL' 'node.sub'; und ATTRIBUTE 'VALUE2' 'node'; an. "
+ "Diese beiden Attribute machen das Device 'spicetauglich'. "
+ "Im übertragenen Schaltplan, muß an der Position des Pins ein FLAG mit entsprechenden Informationen platziert werden."
+ "
"
+ "Beim Sart des ULPs wird in der Datei eaglerc.usr nach dem Pfad zur Programmdatei von Ltspice gesucht. Ist dieser "
+ "noch nicht hinterlegt, wird im Default-Programme-Ordner gesucht und in eaglerc.usr eingetragen."
+ " "
+ "Das ULP überprüft beim Export des Schaltplan die Verfügbarkeit der benötigten LTspice-Symbole .asy. "
+ "Fehlt eines, öffnet EAGLE das Deviceset in der entsprechenden Bibliothek. "
+ "
"
+ "Geprüft wird, ob in den Symbolen die SpiceOrder-Texte im Layer 99 SpiceOrder vorhanden sind. "
+ "In Devices wird nach dem Attribut 'SPICEMODEL' gesucht. Fehlt eines dieser Merkmale, wird "
+ "die Bibliothek mit dem entsprechenden Symbol bzw. Device geöffnet. Machen Sie dann die nötigen "
+ "Ergänzungen. Für die SpiceOrder ist ein ULP verfügbar, das automatisch aufgerufen wird."
+ "
"
+ "Die Symbolnamen von EAGLE-Symbolen müssen sich von denen in LTspice unterscheiden. "
+ "Beispiel: Exportiert man aus EAGLE ein Symbol/Devic 'DIODE', verwendet LTspice sein eigenes "
+ "Symbol mit Namen 'diode'. Damit das EAGLE-Symbol verwendet wird, muss es einen eigenen Namen haben. "
+ "Man kann auchden Namen mit dem LBR-Namen zusammen angegeben. Der LBR-Name entspricht dann einem "
+ "Unterordner im LTspice-Ordner /sym . 2012-10-09"
+ "
"
+ "Das Attribut SPICEMODEL kann über den Menü-Eintrag des LTC-Icons angelegt werden."
+ " "
+ "Dieses Icon wird durch die Datei eagle.scr angelegt. Diese wird beim Anlegen eines neuen "
+ "Devices bzw. Symbols automatisch ausgeführt. Die benötigten Icons (PNG-Dateien) müssen im "
+ "Unterordner bin des EAGLE-Verzeichnisses abgelegt werden."
+ "
"
+ "Bibliotheken importieren/exportieren: "
+ "Die importierten LTspice-Bilbiotheken müssen im Unterordner ./lbr/ltspice/.. angelegt werden, "
+ "damit die Export-Funktion erkennen kann, dass es sich um eine LTspice-Bibliothek handelt. "
+ "Beim ersten Start des ULPs werden entsprechende Dateien nach LTspice kopiert. "
+ "Die zu kopierenden Dateien müssen in folgender Ordnerstruktur abgelegt sein: "
+ "./eagle-x.x.x/ "
+ " - /misc/ "
+ " - - /ltspice/ "
+ " - - - /lib/ "
+ " - - - - /sub/ note.sub und sonstige .sub Dateien "
+ " - - - - /sym/ "
+ " - - - - - /eagle/ "
+ " - - - - - - /lbrname/ die exportierten Symbole der entsprechenden EAGLE-Bibliotheken "
+ " - - - /scr/ die Connect-Scripte von LT (werden von LT geliefert) "
+ " "
+ "EAGLE-Bibliotheken werden in den folgenden Ordner kopiert/erzeugt: "
+ "./LTC/LTspiceIV/lib/sym/eagle/ "
+ "Dabei wird für jede Bibliothek ein Ordner mit dem Namen der exportierten Bibliothek angelegt. "
+ "
"
+ "Author: alf@cadsoft.de"
+
+
+string LTspiceFormatInfo = "" +
+ "Das Koordinatensystem von LTspice ist entsprechend der BitMap einer Grafikkarte organisiert. " +
+ "Der Nullpunkt ist links oben, und die Vorzeichen der Y-Achse sind invertiert! " +
+ "Positiv nach unten, negativ nach oben. " +
+ "LTspice benutzt ein 16er Grid, das die Auflösung für Symbole etwas einschränkt. " +
+ "Das Raster in LTspice wird ohne Einheit angegeben und ist auf (100) mil umgerechnet. " +
+ "In Device-Namen darf kein Schrägstrich (Slash) oder Rückstrich (Backslash) vorkommen. " +
+ "Der Name des Symbols in LTspice definiert den Device-Namen, der gleichzeitig der Name der .asy-Datei ist. " +
+ "Unter Windows ist der 'Schrägstrich' in Dateinamen nicht erlaubt. " +
+ "Unter Linux würde das einen weiteren Unterordner bedeuten!" +
+ "" +
+ "
" +
+ "alf@cadsoft.de";
+
+if (language() != "de") LTspiceFormatInfo = "" +
+ "The coordinates system of LTspice is similar to the BitMap of a graphics adapter. " +
+ "The origin is located in the upper left corner. The coordinates direction of the y axis is inverted. " +
+ "Positive coodinates down, negative up. " +
+ "LTspice works with a multiple of 16 grid, which limits the resolution for symbols a bit. " +
+ "LTspice uses an inch based grid (units not visible) converted to (100) mil. " +
+ "Device names may not contain slash / or backslash \. " +
+ "The symbol name in LTspice defines the device name. This name is used for the .asy file, as well. " +
+ "Windows does not tolerate a slash in file names. Linux would create a subfolder." +
+ "" +
+ "
" +
+ "alf@cadsoft.de";
+
+#require 6.0500
+string ULP_Version = "1.0.4"; // 1.0.2 - 2013-10-01 alf erweitert mit Option /? Systeminfo für Diagnose
+ // 1.0.3 - 2014-01-23 R C L braucht kein SpiceModel (Attribute)
+ // 1.0.4 - 2014-04-03 Pfadauswertung zur importierten LTspice-Lbr berichtigt
+int Test = 0;
+
+
+/* *** export vaiable **** */
+string LTSpiceExecute = ""; // Pfad-Dateiname zum LTspice-Programm
+string EagleExecute = EAGLE_PATH; // 2012-11-23
+
+string LTSpiceLibDir = ""; // das Directory der LTspice-Symbole .asy
+string ExpEagleSpiceSymDir = ""; // das Directory der exportierten Eagle Library-Symbole
+string ImpSpiceSchematicAsc = ""; // der ausgewählte LTspice-Schaltplan zum importieren
+string SpiceSymbol = "";
+string ExpSchematic2LTpice = ""; // der Eagle-Schaltplan der exportiert wird
+
+string SpiceSimulationLbr = ""; // die LBR für die Generatoren, Messinstrumente, Lastwiderstände etc.
+ // wird mit USE benutzt.
+string SpiceDefaultSymLbr = ""; // die LBR für die default Symbole wie R, C, L, D, T ....
+ // wird ebenfalls mit USE benutzt, damit es keine Konflikte zwischen EAGLE-LBRs
+ // und LTspice-LBRs gibt.
+string EagleSpiceLbrDir = ""; // Das Verzeichnis für die importierten Spice-Bibliotheken (*.asy -> .lbr)
+
+string LbrName; // current eagle lbr name
+string NewLbrName; // new eagle lbr name
+
+
+string FileSpiceSym[]; // file names of spice symbols of a directory
+int CntFileSpiceSym = 0;
+string Import_All_Symbols = "1";
+
+string Imp_SpiceSchematicAsc = "";
+string Imp_SpiceSymbol = "";
+string Imp_SpiceSimulationLbr = ""; // die LBR für die Generatoren, Messinstrumente, Lastwiderstände etc.
+string Imp_SpiceDefaultSymLbr = ""; // die LBR für die default Symbole wie R, C, L, D, T ....
+string Imp_EagleSpiceSchDir = "";
+string Imp_LbrName; // current eagle lbr name
+
+string Imp_FileSpiceSym[]; // file names of spice symbols of a directory
+int Imp_CntFileSpiceSym = 0;
+string Imp_ConnectScriptDir = "";
+
+
+string Ex_AsyName;
+string Ex_SpiceAscDir;
+
+int ExportAll = 1; // 0 to export only a GROUP
+int Ex_cntFileSpiceAsc = 0;
+int CntOutput = 0; // exported devices/technologies as *.asy
+
+int Ex_WaitOnHandShake = 0; // flag for response of external executable (LTspice)
+
+int Ex_PinDirSup = 0; // Flag to generate Supply-Symbols for LTspice as library
+string Ex_SpiceOrder = "SpiceOrder";
+string Ex_AttributeSPICEMODEL = "SPICEMODEL";
+string Ex_AttributeSPICEPREFIX = "SPICEPREFIX";
+
+string Ex_SpiceOrderNum[];
+int Ex_PinX[], Ex_PinY[];
+int Ex_LayerSpiceOrder = 99; // Die Zuordnung der Pins zu der SpiceOrder geschieht über den Text "SpiceOrder XX"
+ // und wird als Text in diesem Layer abgelegt!
+int Ex_CntSymText = 0;
+int ExOnceLib = 0;
+
+string FileNewTemp = "wtD"; // option for function output() for generate temporary file (script).
+string FileAppend = "at"; // option for function output() append data to existing file.
+
+
+/***** import variable ******/
+
+int RELOAD = 0; // Flag zum vergleichen bzw. nachladen nach beenden von export ltspice.ulp
+
+string Imp_InfoExternalSymbol = "In EAGLE besteht jedes reguläre Bauteil aus ein oder mehreren Symbolen "
+ "und ein oder mehreren Package-Varianten!
" +
+ "Simulationssymbole für LTspice (Stromquellen, Spannungsquellen, " +
+ "Generatoren, Messgeräte, Lasten etc.), dürfen nicht in das Board oder in die " +
+ "Stück- Netz- Pin-Listen übernommen werden. " +
+ "Um das zu bewerkstelligen, und alle Pin-Directions in Symbolen " +
+ "nutzen zu können, muß in den Devices für Simulations-Symbole ein " +
+ "Attribute \"_EXTERNAL_\" definiert werden." +
+ "Dieses Attribute veranlasst Eagle (ab Version 6.2), die Überprüfung " +
+ "des Device bezüglich der CONNECT-Liste und Vorhandensein eines " +
+ "Packages zu unterdrücken. ";
+
+if (language() != "de") {
+ Imp_InfoExternalSymbol = "In EAGLE every component definition consists of one or more symbols assigned to " +
+ "one or more package variants
." +
+ "Simulation symbols in LTSpice (like power supply, voltage supply, generators, " +
+ "measurment tools, loads and so on...) do not appear in the board nor in a " +
+ "bill of materials, pin list or net list. " +
+ "In order to have all pin directions available for such symbols, a device for " +
+ "a simulation symbol must have defined an attribute named \"_EXTERNAL_\". " +
+ "This attribute suppresses the connection check and the package check (from " +
+ "EAGLE version 6.2.0 on). ";
+}
+
+string LTspicePrefix[], LTspicePrefixDescript[];
+ LTspicePrefix[ 0] = "none"; LTspicePrefixDescript[0] = "Device used not spice prefix";
+ LTspicePrefix[ 1] = "A"; LTspicePrefixDescript[ 1] = "Special functions";
+ LTspicePrefix[ 2] = "B"; LTspicePrefixDescript[ 2] = "Arbitrary behavioral source";
+ LTspicePrefix[ 3] = "C"; LTspicePrefixDescript[ 3] = "Capacitor";
+ LTspicePrefix[ 4] = "D"; LTspicePrefixDescript[ 4] = "Diode";
+ LTspicePrefix[ 5] = "E"; LTspicePrefixDescript[ 5] = "Voltage dependent voltage";
+ LTspicePrefix[ 6] = "F"; LTspicePrefixDescript[ 6] = "Current dependent current";
+ LTspicePrefix[ 7] = "G"; LTspicePrefixDescript[ 7] = "Voltage dependent current";
+ LTspicePrefix[ 8] = "H"; LTspicePrefixDescript[ 8] = "Current dependent voltage";
+ LTspicePrefix[ 9] = "I"; LTspicePrefixDescript[ 9] = "Independent current source";
+ LTspicePrefix[10] = "J"; LTspicePrefixDescript[10] = "JFET transistor";
+ LTspicePrefix[11] = "K"; LTspicePrefixDescript[11] = "Mutual inductance";
+ LTspicePrefix[12] = "L"; LTspicePrefixDescript[12] = "Inductance";
+ LTspicePrefix[13] = "M"; LTspicePrefixDescript[13] = "MOSFET transistor";
+ LTspicePrefix[14] = "O"; LTspicePrefixDescript[14] = "Lossy transmission line";
+ LTspicePrefix[15] = "Q"; LTspicePrefixDescript[15] = "Bipolar transistor";
+ LTspicePrefix[16] = "R"; LTspicePrefixDescript[16] = "Resistor";
+ LTspicePrefix[17] = "S"; LTspicePrefixDescript[17] = "Voltage controlled switch";
+ LTspicePrefix[18] = "T"; LTspicePrefixDescript[18] = "Lossless transmission line";
+ LTspicePrefix[19] = "U"; LTspicePrefixDescript[19] = "Uniform RC-line";
+ LTspicePrefix[20] = "V"; LTspicePrefixDescript[20] = "Independent voltage source";
+ LTspicePrefix[21] = "W"; LTspicePrefixDescript[21] = "Current controlled switch";
+ LTspicePrefix[22] = "X"; LTspicePrefixDescript[22] = "Subcircuit";
+ LTspicePrefix[23] = "Z"; LTspicePrefixDescript[23] = "MESFET transistor";
+
+string ExternalAttributeName = "_EXTERNAL_"; // Attribute in order to define a device without package in eagle
+string ExternalSymbol = "";
+
+int LayerSpiceOrder = 99; // Die Zuordnung der Pins zu der SpiceOrder geschieht über den Text SpiceOrderXX
+ // und wird als Text in diesem Layer abgelegt!
+int ColorViolett = 5;
+
+string SchName;
+int Imp_CntFileSpiceAsc = 0;
+
+char Delimiter = '@';
+
+int Imp_SetWireStyle = 0; // setze WireStyle auf continuous für den NET-Befehl
+
+string Imp_Coords[]; // LT-Spice rotiert ein FLAG (Supplypin/Label) automatisch
+ // anhand der Ausrichtung des Wire, an dessen Ende das FLAG sitzt.
+ // Dazu muss man alle Wires sammeln, um dann später die Rotation
+ // des FLAGs zu bestimmen.
+int Imp_CntCo = 0;
+
+int Imp_WireX1[], Imp_WireY1[], Imp_WireX2[], Imp_WireY2[];
+int Imp_CntW = 0;
+int Imp_WireSeg[]; // Da ein NET sehr verzweigt, und später mit einem BUSTAB zu einem BUS deklariert werden kann,
+ // werden die Wire, Segmenten zugeordnet.
+int Imp_WireType[]; // Der Index des WireType entspricht der Segmentnummer.
+ // Der Inhalt wird zunächst auf NET gesetzt, wird später im Segment eine Koordinate eines BUSTAB
+ // gefunden, so wird das Segment auf BUS gesetzt.
+int Imp_CntSeg = 0; // Anzahl der Segmente
+int Imp_WireChecked = 0; // Flag ob zusammenhängenden Wire-Segmente schon ermittelt wurden.
+enum { Null, BUS, NET }
+int Imp_DrawNetBus = 0; // Flag ob NET und BUS schon gezeichnet wurde.
+
+string Imp_LineView[]; // nur zum Test
+
+ // Eine Besonderheit beim Simulieren in LTspice sind Lastwiderstände.
+ // Lastwiderständer werden mit Rload benannt.
+string Imp_RloadExtention = "_RLOAD"; // Namenserweiterung innerhalb Eagle, um Simulations-/Last-Widerstände von "Res" zu unterscheiden
+
+string Imp_InstanceName = "";
+
+string Imp_Winattrib[];
+real Imp_InstCoordX, Imp_InstCoordY; // remember coordinate from last instance in schematic
+real Imp_InstNameSmashX, Imp_InstNameSmashY;
+real Imp_InstNameOffset;
+real Imp_InstValueSmashX, Imp_InstValueSmashY;
+real Imp_InstValueOffset;
+real Imp_SpiceModelSmashX, Imp_SpiceModelSmashY;
+real Imp_InstValue2SmashX, Imp_InstValue2SmashY;
+real Imp_InstValue2Offset;
+real Imp_SpiceLineSmashX, Imp_SpiceLineSmashY;
+real Imp_SpiceLine2SmashX, Imp_SpiceLine2SmashY;
+
+real Imp_FlagRotate = 0.0; // used to rotate Label (Flag) on NET-Wire
+
+string Add;
+string AddPart;
+string AddPartLib;
+string AddPartOrientation;
+string TextAlign; // die Textausrichtung für Text allgemein
+string TextAlignRotation; // die Rotation für algemeinen Text
+string TextAlignName; // die Textausrichtung für >NAME
+string TextAlignValue; // die Textausrichtung für >VALUE
+string TextAlignValue2; // die Textausrichtung für Value2
+string TextAlignSpiceLine; // die Textasurichtung für die Spiceline
+string TextAlignSpiceLine2; // die Textasurichtung für die Spiceline2
+
+string ScriptFile = "";
+string CmdNameLabel = "";
+string RememberFlag = ""; // Ein Flag kann ein Label oder ein IOPIN sein,
+ // die Entscheidung fällt erst eine Zeile später
+ // mit IOPIN. Dazu muß man sich das Flag merken
+ // und die Koordinaten mit dem IOPIN vergleichen.
+
+string Lines[];
+int CntLines;
+int n; // Global line counter
+
+string h;
+
+string Imp_Cmd = "";
+string Imp_CmdValueV = "";
+string Imp_CmdPartValue = "";
+string Imp_CmdValue2 = ""; // Das Teilscript für den Wert von Value2, wenn der Instance name erst später zugewiesen wird.
+ // LTspice kann Value2 schon zuweisen, bevor die Instance den Namen erhält.
+ // Im Script darf ein Attribute erst nach bestehen des Part erfolgen.
+string Imp_MemSpiceline = "";
+string Imp_MemSpiceline2 = "";
+
+string Imp_DefaultGateName = "G$1";
+string Imp_SymDevName;
+string Imp_CmdDev;
+string Imp_SymPinName;
+
+// für die Symbolbearbeitung
+real Imp_SpiceLineSymX, Imp_SpiceLineSymY, Imp_SpiceLineSymOffset;
+string Imp_SpiceLineSymAlign;
+real Imp_SpiceLine2SymX, Imp_SpiceLine2SymY, Imp_SpiceLine2SymOffset;
+string Imp_SpiceLine2SymAlign;
+real Imp_SpiceModelSymX, Imp_SpiceModelSymY, Imp_SpiceModelSymOffset;
+string Imp_SpiceModelSymAlign;
+
+string Imp_ScriptExt = "~ltspice~.scr";
+
+string Imp_SpicePinName[];
+int Imp_CntPinname = 0;
+
+string Imp_UsedLbrs[];
+int Imp_CntUsedLbrs = 0;
+
+int LTTextSize = 112; // default zum importieren von LTspice symbolen
+ // in mil bei Font: Arial, Size: 28, unter LT_Spice-Control-Panel / Drafting Options
+ // die Texte können nicht exakt berechnet werden, da die Programme unterschiedliche Fonts,
+ // und innerhalb der Fonts die Zeichen wiederum unterschiedlich definert sind!
+/*
+
+// ********************************
+Syntax Definition Symbol
+// ********************************
+
+// *
+Coordinate System
+
+Anchor Point 0 0 -------> grid 16
+ |
+ |
+ |
+ V grid 16
+// *
+
+// * Generics *
+ ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
+ ::=
+ |
+ ::= [a-zA-Z0-9_]
+ ::=
+ |
+ ::= '.'
+// * Coordinates *
+ ::=
+ ::=
+ ::=
+ ::=
+ ::= [A-MOQ-XZ]
+
+// * Line Styles
+ solid no
+ dash 1
+ dott 2
+ dash dot 3
+ dash dot dot 4
+// *
+
+ ::= 1 | 2 | 3 | 4
+
+// /* Justification *
+
+ ::= Left | Right | Center | Top | Bottom
+ ::= VLeft | VRight | VCenter | VTop | VBottom
+ ::= |
+
+// * Symbol Type *
+
+ ::= CELL | BLOCK
+
+ ::= SymbolType
+
+// * Drawings *
+
+ ::= TEXT
+
+ ::= LINE Normal
+ | LINE Normal
+
+ ::= CIRCLE Normal
+ | CIRCLE Normal
+
+ ::= ARC Normal
+ | ARC Normal
+
+ ::= RECTANGLE Normal
+ | RECTANGLE Normal
+
+ ::= | | | |
+
+ ::=
+ | '\n'
+
+// * Attribute Window *
+ Type 1 -
+ SpiceModel 38 +SYMATTR
+ Value 3 -
+ Value2 123 -
+ SpiceLine 39 -
+ SpiceLine2 40 -
+// *
+
+ ::= 0 | 1 | 3 | 39 | 40 | 123
+
+ ::= 38
+
+ ::= WINDOW
+ | WINDOW '\n' SYMATTR
+
+ ::=
+ | '\n'
+
+// * Symbol Attributes *
+
+ ::= Prefix
+ ::= SpiceModel
+ ::= Value
+ ::= Value2
+ ::= SpiceLine
+ ::= SpiceLine2
+ ::= Description
+ ::= ModelFile
+
+ ::= | | | | | | |
+ ::= SYMATTR
+ ::=
+ | '\n'
+// * Pin Definition *
+ ::= NONE |
+ ::= PIN
+ ::= PinName
+ ::= SpiceOrder
+ ::= |
+ ::= PINATTR
+ ::= '\n' PINATTR '\n' PINATTR
+ ::=
+ | '\n'
+// * File *
+ ::= Version
+// *
+ ::=
+// *
+ ::= SymbolType BLOCK '\n'
+ | SymbolType CELL '\n'
+ ::=
+*/
+
+int showtest = 1;
+
+
+void testsyscommand(string cmdexe, string s) {
+ dlgDialog("DOS comand check") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgLabel(s);
+ dlgTextEdit(cmdexe);
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("ESC") { dlgReject(); exit(-666); }
+ }
+ };
+ return;
+}
+
+
+char SearchStartDrive = 'C'; // *** erstes Windowslaufwerk ***
+string StartFolder; // der Grundpfad
+char SearchLastDrive = 'Z'; // 'Z' *** letztes Windowslaufwerk ***
+
+int SearchnRoot;
+string SearchRoot[];
+//string SearchRootfound;
+string SearchFiles[];
+int SearchStart, SearchEnd;
+string a[];
+int SearchIs_UNC;
+int CntSubDir = 4; // maximal bis in den 4. Unterordner suchen
+
+int OS = strstr(OS_SIGNATURE, "Windows");
+if (OS < 0) {
+ dlgMessageBox("This ULP runs only on Windows", "OK");
+ exit(-1);
+}
+
+
+/* *************** file functions *************** */
+int check_files(string path, string file_ext) {
+ return fileglob(SearchFiles, path + file_ext);
+}
+
+
+// ein Windows-Laufwerk beginnt mit "Buchstabe:\"
+// suche nach ":/" hinter dem Laufwerksbuchstaben
+void check_windows_root(void) {
+ string drv;
+ for(int d = SearchStartDrive; d <= SearchLastDrive; d++) {
+ sprintf(drv, "%c:/", d);
+ if (check_files(drv, "/")) {
+ SearchRoot[SearchnRoot] = drv;
+ SearchnRoot++;
+ }
+ }
+ return;
+}
+
+
+string cut_path(string s) {
+ int pos = strrchr(s, '/', -1);
+ if (pos > 0) return strsub(s, 0, pos);
+ return "";
+}
+
+/*
+void check_UNC(string s) {
+ int unc = strstr(s, "//", 0); // windows beginnt UNC Namen mit zweimal Slash // bzw. Backslash \\
+ string last_unc = s;
+ if (unc == 0) {
+ SearchIs_UNC = 1;
+ do {
+ string akt_unc = cut_path(last_unc);
+ unc = check_files(akt_unc, "");
+ if (unc) last_unc = akt_unc;
+ } while (unc);
+ SearchRootfound += last_unc;
+ SearchRoot[SearchnRoot] = last_unc;
+ SearchnRoot++;
+ }
+ return;
+}
+*/
+
+/************************ die Suchschleife *******************************************************/
+// searchfile = die zu suchende Datei
+// root = der Start-Pfad ab dem gesucht werden soll, inkl. Laufwerkbuchstabe unter Windows
+// maxiteration = die Tiefe, Anzahl der Verzweigung (Unterordner) ab dem root Pfad.
+/*************************************************************************************************/
+string file_search(string searchfile, string root, int maxiteration, string debugnum) {
+ if (!root) {
+ if (debugnum == "init") {
+ dlgMessageBox("RUN ltspice.ulp with option Setup: "+searchfile, "CANCEL");
+ }
+ else {
+ if (dlgMessageBox(debugnum + "\nUnknown path of file : "+searchfile, "OK", "CANCEL") == 0) return "";
+ }
+ exit(-752);
+ }
+ int len = strlen(root);
+ if (root[len-1] != '/') root += "/"; // root muß mit Slash enden!
+ if (!check_files(root, "")) { // den Pfad prüfen
+ return "";
+ }
+ // *** Betriebsystem feststellen ***
+ // ******* Windows Laufwerke *******
+ if (root) {
+ SearchRoot[0] = root;
+ SearchnRoot = 1;
+ }
+ else {
+ check_windows_root(); // unter Windows die Laufwerke ermitteln
+ //if (SearchnRoot) {
+ // sprintf(SearchRootfound, "Betriebssystem WINDOWS");
+ // for (int d = 0; d < SearchnRoot; d++) {
+ // SearchRootfound += SearchRoot[d] + "\n";
+ // }
+ //}
+ //int pos;
+ // ************* Windows UNC-Pfad *****************
+ //pos = strstr(root, "//", 0); // windows hat bei UNC Namen zweimal Slash // am Anfang
+ //check_UNC(root);
+ //if (!SearchIs_UNC) if (project.board) project.board(B) check_UNC(B.name);
+ //if (!SearchIs_UNC) if (project.schematic) project.schematic(S) check_UNC(S.name);
+ //if (!SearchIs_UNC) if (library) library(L) check_UNC(L.name);
+
+ // ************* LINUX File system ****************
+ //if (!SearchRootfound) {
+ // pos = strstr(root, "/", 0);
+ // if (pos == 0) {
+ // sprintf(SearchRootfound, "Betriebsystem LINUX");
+ // if (check_files("/", "/")) {
+ // SearchRoot[SearchnRoot] = "/";
+ // SearchnRoot = 1;
+ // }
+ // }
+ //}
+ }
+
+ int n, r;
+ SearchStart = 0;
+ SearchEnd = SearchnRoot;
+ int iteration = 1;
+ int finish = 0;
+ int cntf;
+ string searchfoundfile[];
+
+ do {
+ // 1. die Root-Ordner nach der Datei durchsuchen
+ for (r = SearchStart; r < SearchEnd; r++) {
+ status(SearchRoot[r]); // Anzeige des aktuellen Verzeichnisnamen
+ n = check_files(SearchRoot[r], searchfile); // suche im Verzeichnis nach Datei
+ if (n) {
+ for (int f=0; f= 0) s[pos] = '\\';
+ } while(pos >= 0);
+ return s;
+}
+
+
+// change backslash in windows path names to Eagle slash
+string backslash2lash(string s) {
+ int pos;
+ do {
+ pos = strchr(s, '\\');
+ if (pos >= 0) s[pos] = '/';
+ } while(pos >= 0);
+ return s;
+}
+
+string checkapostroph(string s) { // da der ganze String in ' eingeschlossen wird,
+ // müssen die Apostrophen verdoppelt werden.
+ string t[];
+ int cnt;
+ cnt = strsplit(t, s, '\''); // check Apostroph
+ if (cnt > 1) {
+ s = "";
+ for (int i = 0; i < cnt; i++) {
+ if (i == 0) {
+ if (t[i]) s += t[i];
+ }
+ else if (i) s += "''" + t[i];
+ }
+ }
+ return s;
+}
+
+/********* export functions ***********/
+void looptest(string fname) {
+ string text;
+ int cnttext = fileread(text, fname);
+ if (showtest) {
+ dlgDialog("Export to LTspice : "+ fname) {
+ dlgLabel("Die Datei, siehe Kopfzeile, wurde aktuell gelesen.");
+ dlgLabel(fname);
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(500);
+ dlgTextEdit(text);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("Cancel") { dlgReject(); exit(-9); }
+ dlgPushButton("Dieses Menu nicht mehr anzeigen") { showtest = 0; dlgAccept(); }
+ dlgStretch(1);
+ }
+ };
+ }
+ return;
+}
+
+
+string ex_checkbackslash(string s) { // für die Anzeige des Windows-Pfad mit Slash statt Backslash
+ int pos;
+ do {
+ pos = strchr(s, '\\');
+ if (pos >= 0) s[pos] = '/';
+ } while(pos >= 0);
+ return s;
+}
+
+
+string ex_check_text(string text) { // Eagle gibt Backslash doppelt aus, also halbieren!
+ string t[];
+ int cnt = strsplit(t, text, '\n');
+ if (cnt == 1) return text;
+ string t2 = "";
+ for (int n = 0; n < cnt-1; n++) {
+ t2 += t[n] + "\\n";
+ }
+ t2 += t[n];
+ return t2;
+}
+
+
+string ex_checktextangle(int talign, int tangle, string name, int iangle) {
+ /* Wenn das Symbol gedreht ist, und der Text nicht, dann muß der Text vertikal ausgegeben werden.
+ Wenn der Text gedreht ist und das Symbo nicht, dann muß der Text auch vertikal ausgegeben werden,
+ in allen anderen Fällen horizontal.
+ */
+ string v = "";
+
+ if (iangle == 0 || iangle == 180) {
+ if ((tangle == 90 || tangle == 270 || iangle == 90 || iangle == 270)) v = "V";
+ }
+ else if (iangle == 90 || iangle == 270) {
+ if ((tangle == 0 || tangle == 180 || iangle == 0 || iangle == 180)) v = "V";
+ }
+ switch(talign) {
+ case ALIGN_BOTTOM_LEFT : return v+"Left";
+ break;
+ case ALIGN_BOTTOM_CENTER : return v+"Bottom";
+ break;
+ case ALIGN_BOTTOM_RIGHT : return v+"Right";
+ break;
+ case ALIGN_CENTER_LEFT : return v+"Left";
+ break;
+ case ALIGN_CENTER : return v+"Center";
+ break;
+ case ALIGN_CENTER_RIGHT : return v+"Right";
+ break;
+ case ALIGN_TOP_LEFT : return v+"Left";
+ break;
+ case ALIGN_TOP_CENTER : return v+"Top";
+ break;
+ case ALIGN_TOP_RIGHT : return v+"Right";
+ break;
+ default : return "Left";
+ }
+}
+
+
+real ex_spicegrid(real v) {
+ return v / 100 * 16;
+}
+
+
+string ex_spicetextcoord(UL_TEXT T, UL_INSTANCE I) {
+ string s;
+ int ang = I.angle;
+ real x;
+ real y;
+ switch(ang) {
+ case 0 : x = ex_spicegrid(u2mil(T.x - I.x));
+ y = ex_spicegrid(u2mil(T.y - I.y)*-1.0); // checked ok
+ break;
+ case 90 : if (I.mirror) {
+ y = ex_spicegrid(u2mil(T.x - I.x)*-1.0);
+ x = ex_spicegrid(u2mil(T.y - I.y)); // checked ok
+ }
+ else {
+ y = ex_spicegrid(u2mil(T.x - I.x));
+ x = ex_spicegrid(u2mil(T.y - I.y)); // checked ok
+ }
+ break;
+ case 180 : if (I.mirror) {
+ x = ex_spicegrid(u2mil(T.x - I.x));
+ y = ex_spicegrid(u2mil(T.y - I.y)); // checked ok
+ }
+ else {
+ x = ex_spicegrid(u2mil(I.x - T.x));
+ y = ex_spicegrid(u2mil(I.y - T.y)*-1.0); // checked ok
+ }
+ break;
+ case 270 : if (I.mirror) {
+ y = ex_spicegrid(u2mil(T.x - I.x));
+ x = ex_spicegrid(u2mil(T.y - I.y)*-1.0); // checked ok
+ }
+ else {
+ y = ex_spicegrid(u2mil(I.x - T.x));
+ x = ex_spicegrid(u2mil(I.y - T.y)); // checked ok
+ }
+ break;
+ }
+ sprintf(s, "%.0f %.0f", x, y);
+ return s;
+}
+
+
+void ex_draw_wire(UL_WIRE W) {
+ if (W.curve) {
+ /* ARC Normal 32 -32 0 0 27 -27 5 -27
+ die ersten vier Zahlen sind die umschließende Box,
+ die nächsten 2 die Start-Koordinate,
+ und die letzten beiden die End-Koordinate des ARC
+ */
+ printf("ARC Normal %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f\n",
+ ex_spicegrid(u2mil(W.arc.xc - W.arc.radius)), ex_spicegrid(u2mil(W.arc.yc + W.arc.radius)*-1.0),
+ ex_spicegrid(u2mil(W.arc.xc + W.arc.radius)), ex_spicegrid(u2mil(W.arc.yc - W.arc.radius)*-1.0),
+ ex_spicegrid(u2mil(W.arc.x1)), ex_spicegrid(u2mil(W.arc.y1)*-1.0),
+ ex_spicegrid(u2mil(W.arc.x2)), ex_spicegrid(u2mil(W.arc.y2)*-1.0)
+ );
+ }
+ else {
+ printf("LINE Normal %.0f %.0f %.0f %.0f\n",
+ ex_spicegrid(u2mil(W.x1)), ex_spicegrid(u2mil(W.y1)*-1.0),
+ ex_spicegrid(u2mil(W.x2)), ex_spicegrid(u2mil(W.y2)*-1.0)
+ );
+ }
+ return;
+}
+
+
+void ex_draw_rect(UL_RECTANGLE R) {
+ printf("LINE Normal %.0f %.0f %.0f %.0f\nLINE Normal %.0f %.0f %.0f %.0f\nLINE Normal %.0f %.0f %.0f %.0f\nLINE Normal %.0f %.0f %.0f %.0f\n",
+ ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y1)*-1.0),
+ ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y1)*-1.0),
+ ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y1)*-1.0),
+ ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y2)*-1.0),
+ ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y2)*-1.0),
+ ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y2)*-1.0),
+ ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y2)*-1.0),
+ ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y1)*-1.0)
+ );
+ return ;
+}
+
+
+void ex_draw_poly(UL_POLYGON P) {
+ P.contours(W) ex_draw_wire(W);
+ return;
+}
+
+
+void ex_draw_net_wire(UL_WIRE W) {
+ printf("WIRE %.0f %.0f %.0f %.0f\n",
+ ex_spicegrid(u2mil(W.x1)), ex_spicegrid(u2mil(W.y1)*-1.0),
+ ex_spicegrid(u2mil(W.x2)), ex_spicegrid(u2mil(W.y2)*-1.0)
+ );
+ return;
+}
+
+
+/* CIRCLE Normal 64 0 48 -16 */
+void ex_draw_circle(UL_CIRCLE C) {
+ printf("CIRCLE Normal %.0f %.0f %.0f %.0f\n", // 64 0 48 -16
+ ex_spicegrid(u2mil(C.x - C.radius)), ex_spicegrid(u2mil(C.y + C.radius)*-1.0),
+ ex_spicegrid(u2mil(C.x + C.radius)), ex_spicegrid(u2mil(C.y - C.radius)*-1.0)
+ );
+ return;
+}
+
+
+/* LTspice directiven beginnen mit ! */
+void ex_draw_text(UL_TEXT T, string option, string supply) {
+ string t = strupr(T.value);
+ real tx = ex_spicegrid(u2mil(T.x));
+ real ty = ex_spicegrid(u2mil(T.y)*-1.0);
+ switch(T.align) {
+ case ALIGN_BOTTOM_LEFT : if (T.angle == 0) {
+ ty -= ex_spicegrid(u2mil(T.size/2));
+ }
+ else if (T.angle == 90) {
+ tx += ex_spicegrid(u2mil(T.size/2));
+ }
+ break;
+ case ALIGN_BOTTOM_CENTER : ;
+ break;
+ case ALIGN_BOTTOM_RIGHT : ty -= ex_spicegrid(u2mil(T.size/2));
+ break;
+ case ALIGN_CENTER_LEFT : ty -= ex_spicegrid(u2mil(T.size/2));
+ break;
+ case ALIGN_CENTER : ty -= ex_spicegrid(u2mil(T.size/2));
+ break;
+ case ALIGN_CENTER_RIGHT : ty -= ex_spicegrid(u2mil(T.size/2));
+ break;
+ case ALIGN_TOP_LEFT : ;
+ break;
+ case ALIGN_TOP_CENTER : ;
+ break;
+ case ALIGN_TOP_RIGHT : ;
+ break;
+ }
+
+
+ // TEXT 0 0 Bottom 2 +3.3V : example of supply pin name
+ if (Ex_PinDirSup && supply) {
+ if (T.layer != Ex_LayerSpiceOrder) {
+ printf("TEXT %.0f %.0f %s 0 %s\n",
+ tx, ty,
+ ex_checktextangle(T.align, T.angle, "", 0),
+ ex_check_text(supply)
+ );
+ }
+ return;
+ }
+ if (t == ">NAME" || option == ">NAME") {
+ // WINDOW 0 36 40 Left 0 // Textplatzhalter für >NAME
+ if(option == ">NAME") printf("WINDOW 0 %.0f %.0f %s 0\n", tx, ty, ex_checktextangle(T.align, T.angle, "", 0));
+ return;
+ }
+ if (t == ">VALUE" || option == ">VALUE") {
+ // WINDOW 3 36 76 Left 0 // platzhalter für >VALUE
+ if (option == ">VALUE") printf("WINDOW 3 %.0f %.0f %s 0\n", tx, ty, ex_checktextangle(T.align, T.angle, "", 0));
+ return;
+ }
+// if (strstr(T.value, "SpiceOrder") == 0) return; // nur vorübergehender Text im Symbol zum überprüfen
+ if (option == "*") {
+ // TEXT 0 0 Center 0 LT
+ printf("TEXT %.0f %.0f %s 0 %s\n", tx, ty, ex_checktextangle(T.align, T.angle, "", 0), ex_check_text(T.value));
+ return;
+ }
+ t = T.value;
+ if (t[0] == '\\' && t[1] == '!') { // damit Eagle den Text nicht Überstreicht, muß ein Backslash vorangestellt werden.
+ t = strsub(t, 1); // schneide das Backslash (Escapezeichen) vor dem ! wieder ab.
+ }
+
+ printf("TEXT %.0f %.0f %s 0 %s\n",
+ tx, ty,
+ ex_checktextangle(T.align, T.angle, "", 0),
+ ex_check_text(t)
+ );
+
+ return;
+}
+
+
+void ex_collectordertext(UL_SYMBOL S) {
+ Ex_CntSymText = 0; // reinitialization
+ S.texts(T) {
+ if (T.layer == Ex_LayerSpiceOrder) {
+ string s[];
+ strsplit(s, T.value, ' ');
+ if (s[0] == Ex_SpiceOrder) {
+ Ex_PinX[Ex_CntSymText] = T.x;
+ Ex_PinY[Ex_CntSymText] = T.y;
+ Ex_SpiceOrderNum[Ex_CntSymText] = s[1];
+ Ex_CntSymText++;
+ }
+ }
+ }
+}
+
+
+string ex_getspiceorder(int x, int y) {
+ for (int n = 0; n < Ex_CntSymText; n++ ) {
+ if (x == Ex_PinX[n] && y == Ex_PinY[n]) return Ex_SpiceOrderNum[n];
+ }
+ return "";
+}
+
+
+string ex_checkinverted(string pinname) { // LTspice benutzt Underline als Einleitungszeichen für den Negierungsüberstrich,
+ if (pinname[0] == '!') pinname[0] = '_'; // Eagle beginnt mit Ausrufezeichen.
+ return pinname;
+}
+
+
+void ex_draw_pin(UL_PIN P, int pcnt) {
+ int pinlength;
+ int x2, y2;
+ if (P.direction == PIN_DIRECTION_SUP) Ex_PinDirSup = 1;
+ if (pcnt) { // draw line and pin it self
+ switch(P.length) { // Grid unit = mil
+ case (PIN_LENGTH_POINT) : pinlength = 0; // kein Wire
+ break;
+ case (PIN_LENGTH_SHORT) : pinlength = 100; // 0.1-Inch-Wire
+ break;
+ case (PIN_LENGTH_MIDDLE) : pinlength = 200; // 0.2-Inch-Wire
+ break;
+ case (PIN_LENGTH_LONG) : pinlength = 300; // 0.3-Inch-Wire
+ break;
+ }
+ int ang = P.angle;
+ switch(ang) {
+ case (0) : x2 = pinlength;
+ y2 = 0;
+ break;
+ case (90) : x2 = 0;
+ y2 = pinlength;
+ break;
+ case (180) : x2 = pinlength * -1;
+ y2 = 0;
+ break;
+ case (270) : x2 = 0;
+ y2 = pinlength * -1;
+ break;
+ }
+ if (pinlength) {
+ printf("LINE Normal %.0f %.0f %.0f %.0f\n", // Linie des PIN
+ ex_spicegrid(u2mil(P.x)), ex_spicegrid(u2mil(P.y)*-1.0), // Das Vorzeichen der Y-Achse ist bei LT-Spice vertauscht
+ ex_spicegrid(u2mil(P.x)+x2), ex_spicegrid((u2mil(P.y)+y2)*-1.0)
+ );
+ }
+
+
+ //if (!Ex_PinDirSup) {
+ printf("PIN %.0f %.0f NONE 0\n", ex_spicegrid(u2mil(P.x)), ex_spicegrid(u2mil(P.y)*-1.0 ));
+ printf("PINATTR PinName %s\n", ex_checkinverted(P.name));
+ printf("PINATTR SpiceOrder %s\n", ex_getspiceorder(P.x, P.y));
+ //}
+ //else {
+ /* ****************************************************************
+ if (Ex_PinDirSup) { // a supply symbol is generated
+ sprintf(acmd, "EDIT %s.DEV; ATTRIBUTE %s 'node.sub'; ATTRIBUT 'VALUE2' 'node';",
+ DEV.name, Ex_AttributeSPICEMODEL
+ );
+ exit(acmd);
+ }
+ * ****************************************************************/
+ //}
+ }
+ return;
+}
+
+
+void readconfig(void) { // read configuration file of ULP
+ SpiceDefaultSymLbr = cfgget("ULP:ltspice.SpiceDefaultSymLbr");
+ SpiceSimulationLbr = cfgget("ULP:ltspice.SpiceSimulationLbr");
+ EagleSpiceLbrDir = cfgget("ULP:ltspice.EagleSpiceLbrDir");
+ LTSpiceLibDir = cfgget("ULP:ltspice.LTSpiceLibDir");
+ ImpSpiceSchematicAsc = cfgget("ULP:ltspice.ImpSpiceSchematicAsc");
+ LTSpiceExecute = cfgget("ULP:ltspice.LTSpiceExecute");
+ SpiceSymbol = cfgget("ULP:ltspice.SpiceSymbol");
+ ExpSchematic2LTpice = cfgget("ULP:ltspice.ExpSchematic2LTpice");
+ SchName = cfgget("ULP:ltspice.SchName");
+ Import_All_Symbols = cfgget("ULP:ltspice.Import_All_Symbols");
+ ExternalSymbol = cfgget("ULP:ltspice.ExternalSymbol");
+ Imp_ConnectScriptDir = cfgget("ULP:ltspice.Imp_ConnectScriptDir");
+ ExpEagleSpiceSymDir = cfgget("ULP:ltspice.ExpEagleSpiceSymDir");
+ Ex_SpiceAscDir = cfgget("ULP:ltspice.SpiceAscDir");
+ return;
+}
+
+
+void saveconfig(void) {
+ cfgset("ULP:ltspice.SpiceDefaultSymLbr", SpiceDefaultSymLbr);
+ cfgset("ULP:ltspice.SpiceSimulationLbr", SpiceSimulationLbr);
+ cfgset("ULP:ltspice.EagleSpiceLbrDir", EagleSpiceLbrDir);
+ cfgset("ULP:ltspice.LTSpiceLibDir", LTSpiceLibDir);
+ cfgset("ULP:ltspice.ImpSpiceSchematicAsc", ImpSpiceSchematicAsc);
+ cfgset("ULP:ltspice.LTSpiceExecute", LTSpiceExecute);
+ cfgset("ULP:ltspice.SpiceSymbol", SpiceSymbol);
+ cfgset("ULP:ltspice.ExpSchematic2LTpice", ExpSchematic2LTpice);
+ cfgset("ULP:ltspice.SchName", SchName);
+ cfgset("ULP:ltspice.Import_All_Symbols", Import_All_Symbols);
+ cfgset("ULP:ltspice.ExternalSymbol", ExternalSymbol);
+ cfgset("ULP:ltspice.Imp_ConnectScriptDir", Imp_ConnectScriptDir);
+ cfgset("ULP:ltspice.ExpEagleSpiceSymDir", ExpEagleSpiceSymDir);
+ cfgset("ULP:ltspice.SpiceAscDir", Ex_SpiceAscDir);
+ return;
+}
+
+
+int ex_check_slash(string name) {
+ string s[];
+ return strsplit(s, name, '/') -1;
+}
+
+
+string ex_check_dev_name(string dev) { // wenn Package-Variante "leer" dann gib auch leeren string zurück
+ if (dev == "''") return "";
+ int pos;
+ do {
+ pos = strchr(dev, '/'); // Slash ist in Device-Namen (Packagevariant) verboten, da unter Linux sonst ein Unterordner angesprichen wird.
+ if (pos >= 0) dev[pos] = '_';
+ } while(pos >= 0);
+ return dev;
+}
+
+
+string ex_check_devset_name(string devset, string pac, string tech) { // * ist in Dateinamen Deviceset verboten,
+ if (pac == "''") pac = ""; // da es sich hier um ein Wildcard-Zeichen handelt
+ if (tech == "''") tech = ""; // wie auch das ? muß es durch Pacvariante und Technology ersetzt werden.
+ string s[];
+ int np = strsplit(s, devset, '*'); // Technologie
+ if (np > 1) {
+ if (tech == "''") tech = ""; // ein leeres Device wird intern mit '' angegeben, und muß "" (leer) werden!
+ devset = s[0]+tech+s[1];
+ }
+ else {
+ devset = s[0]+tech;
+ }
+ int nt = strsplit(s, devset, '?'); // Packagevariante
+ if (nt > 1) {
+ if (pac == "''") pac = ""; // ein leeres Device wird intern mit '' angegeben, und muß "" (leer) werden!
+ devset = s[0]+pac+s[1];
+ }
+ else {
+ devset = s[0]+pac;
+ }
+//if (dlgMessageBox(">"+devset+"<", "okpactech1189", "escpactech1189") != 0) exit(-1321);
+ return devset;
+}
+
+
+string check_dev_description(string descript) {
+ if(descript[0] == '<') return ""; // Description beginnt mit HTML-Tag, dann nur leeren String zurückgeben.
+ string s[];
+ int cnt = strsplit(s, descript, '\n'); // nur die Kopfzeile zurückgeben, da LTspice bei der Description
+ descript = s[0]; // keine mehrzeiligen Texte benutzen kann.
+ return descript;
+}
+
+
+string check_exist_asy(string symname, string sympath, string debugnum) { // müssen bestimmte symbole in bestimmten Pfaden abgelegt sein?
+ return file_search( symname, sympath, CntSubDir, debugnum);
+}
+
+
+int makedir(string root1, string subdir) { /*** generate DOS command MKDIR ***/
+ string DOScommand;
+ sprintf(DOScommand, "CMD.EXE /C MKDIR \"%s%s\"", lash2backslash(root1), lash2backslash(subdir));
+ system(DOScommand);
+ string f[];
+ int n = fileglob(f, root1 + subdir); // prüfe ob das Verzeichnis angelegt werden konnte.
+ return n;
+}
+
+
+void check_exist_directory(string fname) { // überprüfe die Existenz des Verzeichneis, und wenn nicht vorhanden, anlegen!
+ string fdir = filedir(fname);
+ string fd[];
+ int n = fileglob(fd, fdir);
+ int len =strlen(fdir);
+ if (fdir[len-1] == '/') fdir[len-1] = 0; // für MKDIR darf kein Backslash (Slash) am Ende sein.
+ if (!n) {
+ if (!makedir("", fdir)) { // Returnwert 0 wenn das Verzeichnis nicht angelegt werden konnte
+ dlgMessageBox("!Can't build:\n" + fdir, "ok", "esc");
+ exit(-1359);
+ }
+ }
+ return;
+}
+
+
+void ex_draw_device(UL_DEVICE D, UL_DEVICESET DEV) {
+ string error;
+ int cntgate = 0;
+ D.gates(G) {
+ cntgate++;
+ }
+ if (ex_check_slash(DEV.name)) {
+ dlgMessageBox("!Do not use character / in device name!\n"+ DEV.name + ".DEV\nPlease change to '_' !", "OK");
+ sprintf(error, "EDIT %s.DEV;", DEV.name);
+ exit(error);
+ }
+ // check attribute SPICEMODEL
+ string acmd = "";
+ int cntnoattspicemodel = 0;
+ int cntnoattspiceprefix = 0;
+ string devnoattmodel[];
+ string technoattmodel[];
+ string devnoattprefix[];
+ string technoattprefix[];
+ int cntde = 0;
+ DEV.devices(DE) {
+ cntde++;
+ string t[];
+ int nt = strsplit(t, DE.technologies, ' ');
+ int spicemodelexist = 0;
+ int spiceprefixexist = 0;
+//if (dlgMessageBox(DEV.name + DE.name, "ok", "esc") !=0) exit(-1392);
+ // prüfe erst die Existenz der Spicemodelle
+ for (int i = 0; i < nt; i++) {
+ spicemodelexist = 0;
+ spiceprefixexist = 0;
+ DE.attributes(A, t[i]) {
+ if (A.name == "SPICEMODEL") { spicemodelexist++; // 1 = Attribute existiert
+ if (A.value) spicemodelexist++; // 2 = Wert gesetzt
+ }
+ if (A.name == "SPICEPREFIX") { spiceprefixexist++; // 1 = Attribute existiert
+ if (A.value) spiceprefixexist++; // 2 = Wert gesetzt
+ }
+ }
+ if (DEV.prefix == "C" || DEV.prefix == "L" || DEV.prefix == "R") { // 2014-01-23
+ // C braucht kein Spicemodel
+ // L braucht kein Spicemodel
+ // R braucht kein Spicemodel
+ }
+ else {
+ if (spicemodelexist < 2) {
+ devnoattmodel[cntnoattspicemodel] = DE.name;
+ technoattmodel[cntnoattspicemodel] = t[i];
+ cntnoattspicemodel++;
+ }
+ }
+ if (spiceprefixexist < 2) { // 2012-11-30
+ devnoattprefix[cntnoattspiceprefix] = DE.name;
+ technoattprefix[cntnoattspiceprefix] = t[i];
+ cntnoattspiceprefix++;
+ }
+ }
+ }
+ // check all devices of this deviceset, of attribute SPICEMODEL
+ string attvalspicemodel;
+ string attvalspiceprefix;
+ if (cntnoattspicemodel || cntnoattspiceprefix) {
+ if (cntnoattspicemodel) { // 2012-12-05
+ int result = dlgDialog("Set Attributes") {
+ dlgHBoxLayout dlgSpacing(300);
+ if (cntnoattspicemodel) {
+ dlgLabel("" + DEV.name + ".DEV
MISSING SpiceModel Type in the name of spicemodel for this device!");
+ dlgStringEdit(attvalspicemodel);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") if (attvalspicemodel) dlgAccept();
+ else dlgMessageBox("First type in the name of spicemodel for this device!", "OK");
+ dlgPushButton("CANCEL") dlgReject();
+ }
+ };
+ if(!result) exit(-1441);
+ }
+
+ if (cntnoattspiceprefix) { // 2012-12-05
+ string prefixlist[];
+ for (int l = 0; LTspicePrefix[l]; l++) prefixlist[l] = LTspicePrefix[l] + "\t" + LTspicePrefixDescript[l];
+ int prefsel = -1;
+ int result = dlgDialog("Set Attributes") {
+ dlgHBoxLayout dlgSpacing(300);
+ if (cntnoattspiceprefix) {
+ dlgLabel("" + DEV.name + ".DEV
MISSING SpicePrefix Select a spiceprefix for this device!");
+ dlgListBox(prefixlist, prefsel) { attvalspiceprefix = LTspicePrefix[prefsel]; dlgAccept(); }
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") if (attvalspiceprefix) dlgAccept();
+ else {
+ if (prefsel >= 0) {
+ attvalspiceprefix = LTspicePrefix[prefsel];
+ dlgAccept();
+ }
+ else dlgMessageBox("First select a Spice prefix for this device.", "OK");
+ }
+ dlgPushButton("CANCEL") dlgReject();
+ }
+ };
+ if(!result) exit(-1466);
+ }
+ // if (!spicemodelexist) dlgMessageBox("Missing attribute SPICEMODEL of technology '"+ ex_check_dev_name(actualtechno) + "' of package variant " + D.name, "OK");
+ // else dlgMessageBox("Attribute SPICEMODEL of technologie '"+ ex_check_dev_name(actualtechno) + "' of package variante " + D.name + " has no value!", "OK");
+ string as;
+ int i;
+ for (i = 0; i < cntnoattspicemodel; i++) {
+ sprintf(as, "EDIT %s.DEV;\n", DEV.name);
+ acmd += as;
+ /*** in Device und Technologie darf kein Schrägstrich, oder Backslash vorkommen,
+ denn das gibt ein Proglem bei Pfad und Dateinamen in Linux/MAX-OS bzw. Windows!
+ Hier muß ein Unterstrich benutzt werden!
+ ***/
+ string chkdevname = ex_check_dev_name(devnoattmodel[i]);
+ if (devnoattmodel[i] != chkdevname && chkdevname) { // Supply-Devices haben kein Package, nicht mal ''
+ sprintf(as, "PACKAGE -%s %s;\n", devnoattmodel[i], chkdevname); // 2012-10-04 benenne die Packagevariante um, mit "_" als "/".
+ acmd += as;
+ }
+ // 2012-09-17 Attribute-Befehl zweimal aufrufen! Fehler in Dialog-Menu.
+ // Wenn kein Wert angegeben wird, wird es nicht als geändert erkannt, und das Attribute wird nicht angelegt!
+ sprintf(as, "PACkage '%s'; TECHNOLOGY %s; ATTRIBUTE %s '%s';\n",
+ checkapostroph(ex_check_dev_name(devnoattmodel[i])), technoattmodel[i], Ex_AttributeSPICEMODEL, attvalspicemodel // 2012-12-10
+ );
+ acmd += as; // if(dlgMessageBox(acmd, "acmd ok", "acmd esc") != 0) exit(-1489); ;
+ }
+ // 2012-11-30 setze den Wert für das Attribute SPICEPREFIX
+ for (i = 0; i < cntnoattspiceprefix; i++) {
+ sprintf(as, "EDIT %s.DEV;\n", DEV.name);
+ acmd += as;
+ /* ** in Device und Technologie darf kein Schrägstrich, oder Backslash vorkommen,
+ denn das gibt ein Proglem bei Pfad und Dateinamen in Linux/MAX-OS bzw. Windows!
+ Hier muß ein Unterstrich benutzt werden!
+ ** */
+ string chkdevname = ex_check_dev_name(devnoattprefix[i]);
+ if (devnoattprefix[i] != chkdevname && chkdevname) { // Supply-Devices haben kein Package, nicht mal ''
+ sprintf(as, "PACKAGE -%s %s;\n", devnoattprefix[i], chkdevname); // 2012-10-04 benenne die Packagevariante um, mit "_" als "/".
+ acmd += as;
+ }
+ // 2012-09-17 Attribute-Befehl zweimal aufrufen! Fehler in Dialog-Menu.
+ // Wenn kein Wert angegeben wird, wird es nicht als geändert erkannt, und das Attribute wird nicht angelegt!
+ sprintf(as, "PACkagE '%s'; TECHNOLOGY %s; ATTRIBUTE %s '%s';\n",
+ checkapostroph(ex_check_dev_name(devnoattprefix[i])), technoattprefix[i], Ex_AttributeSPICEPREFIX, attvalspiceprefix // 2012-12-10
+ );
+ acmd += as; // if(dlgMessageBox(acmd, "acmd ok", "acmd esc") != 0) exit(-1509); ;
+ }
+
+ if (acmd) {
+if (dlgMessageBox("ex_draw_device() : exit " + acmd , "ok", "esc") != 0) exit(-1513);
+ exit(acmd);
+ }
+ }
+//if (dlgMessageBox("ex_draw_device() : symbole ausgeben" , "ok", "esc") != 0) exit(-1517);
+
+ Ex_PinDirSup = 0;
+ DEV.gates(G) {
+ library(L) {
+ L.symbols(SYM) {
+ if (SYM.name == G.symbol.name) { // prüfe nur die zum Device gehörenden Symbole
+ if (ex_check_slash(SYM.name)) {
+ dlgMessageBox("!Do not use character / in symbol name!\n"+SYM.name+".SYM\nPlease change to '_' !", "OK");
+ sprintf(error, "EDIT %s.SYM;", SYM.name);
+ exit(error);
+ }
+ // check exist SpiceOrder
+ int cnttext = 0;
+ int cntpin = 0;
+ string h;
+ SYM.texts(T) {
+ if (T.layer == Ex_LayerSpiceOrder) {
+ if (strstr(T.value, "SpiceOrder") == 0) cnttext++;
+ }
+ }
+ SYM.pins(P) {
+ if (P.direction == PIN_DIRECTION_SUP) Ex_PinDirSup = 1; // ein Supply-Pin ist beteiligt, also ist es ein Supply-symbol
+ cntpin++;
+ }
+ if (!cnttext) {
+ sprintf(h, "!Symbol %s can not be exported, missing SpiceOder for PINs!", SYM.name);
+ dlgMessageBox(h, "OK");
+ sprintf(h, "EDIT %s.SYM;RUN spiceorder.ulp", SYM.name);
+ exit(h);
+ }
+ if (cnttext != cntpin) {
+ dlgMessageBox("!Different counts of SpiceOrder and PINs.", "OK");
+ sprintf(h, "EDIT %s.SYM;RUN spiceorder.ulp", SYM.name); // run spiceordr.ulp to define the missing spiceorder in device
+ exit(h);
+ }
+ ex_collectordertext(SYM);
+
+ string actgatename = G.name;
+ if (cntgate < 2) actgatename = ""; // wenn Deviceset nur aus 1 Gate besteht,
+ // dann den Gatenamen nicht benutzen!
+ // keine leere '' Package-Variante angeben
+ int ltspicelbr = strstr(L.name, "/ltspice/");
+ string tech[];
+ int n = strsplit(tech, D.technologies, ' ');
+ for (int i = 0; i < n; i++) {
+ if (ltspicelbr > 0) { // eine LTspice importierte LBR ist geladen
+ Ex_AsyName = LTSpiceLibDir + "sym/" + DEV.library + "/" + ex_check_devset_name(DEV.name, D.name, "") + actgatename + ".asy"; // keine leere '' Package-Variante angeben
+ }
+ // eine Eagle-Lbr ist geladen
+ else Ex_AsyName = ExpEagleSpiceSymDir + DEV.library + "/" + ex_check_devset_name(DEV.name, D.name, tech[i]) + actgatename + ".asy"; // 2012-12-10 Technologie
+ // für jede technologie ein symbol anlegen 2012-10-02
+ check_exist_directory(Ex_AsyName); // 2012-12-10 bevor das Symbol angelegt werden kann, muß das Verzeicnis existieren!
+ output(Ex_AsyName, "wt") {
+//if (dlgMessageBox(Ex_AsyName, "ok", "esc") != 0) exit(-1571);
+ CntOutput++;
+ printf("Version 4\n");
+ printf("SymbolType CELL\n");
+ int pcnt = 0;
+ SYM.wires(W) ex_draw_wire(W); // Symbollinien zeichnen.
+ SYM.polygons(POL) ex_draw_poly(POL); // Die Kontur des Polygon zeichen (werden nicht gefüllt).
+ SYM.rectangles(R) ex_draw_rect(R); // Rechteck als Linien zeichnen.
+ SYM.circles(C) ex_draw_circle(C);
+ SYM.texts(T) {
+ if (T.layer != Ex_LayerSpiceOrder && T.layer != 93) { // Spiceorder nicht als Text ausgeben! Zusätzliche Doku im Layer 93 Pins nicht ausgeben.
+ if (strupr(T.value) != ">NAME" && strupr(T.value) != ">VALUE") ex_draw_text(T, "*", SYM.name); // beliebiger Text
+ else if (strupr(T.value) == ">NAME") ex_draw_text(T, ">NAME", ""); // der Textplatzhalter >NAME
+ else if (strupr(T.value) == ">VALUE") ex_draw_text(T, ">VALUE", ""); // der Textplatzhalter >VALUE
+ }
+ }
+ /*
+ SYMATTR Value LT6231
+ SYMATTR Prefix X
+ */
+ printf("SYMATTR Value %s\n", DEV.name); // nicht der Device-Prefix, sondern der Device-Name
+
+ string t[];
+ int n = strsplit(t, D.technologies, ' ');
+ // check exist Spice Attribute for Spice Model
+ //int spicemodelexist = 0;
+ //int spiceprefixexist = 0;
+ string actualtechno = "";
+ /*
+ SYMATTR Value LT3518
+ SYMATTR Prefix X
+ SYMATTR SpiceModel LT3518.sub
+ SYMATTR Value2 LT3518
+ */
+
+ string aspiceprefix;
+ string aspicemodel;
+ string avalue2;
+ string aspiceline;
+ string aspiceline2;
+ string aspicetype;
+ DEV.devices(DE) {
+ if (DE.name == D.name) {
+ for (int i = 0; i < n; i++) {
+ D.attributes(A, t[i]) {
+ actualtechno = t[i];
+ if (A.name == "SPICEPREFIX") {
+ sprintf(aspiceprefix, "SYMATTR Prefix %s\n", A.value); //
+ }
+ else if (A.name == "SPICEMODEL") {
+ //spicemodelexist++; // 1 = Attribute existiert
+ if (A.value != "NONE") {
+ sprintf(aspicemodel, "SYMATTR SpiceModel %s\n", A.value);
+
+ }
+ else {
+ //if (dlgMessageBox(A.name + " : " + A.value, "NONE ok", "NONE esc") != 0) exit(-1627);
+ }
+ }
+ /* Der Value im LTspice-Symbol ist der Devicesetname
+ else if (A.name == "VALUE") {
+ sprintf(avalue, "SYMATTR Value %s\n", A.value);
+ }
+ */
+ else if (A.name == "VALUE2") {
+ sprintf(avalue2, "SYMATTR Value2 %s\n", A.value);
+ }
+ else if (A.name == "SPICELINE") {
+ sprintf(aspiceline, "SYMATTR Spiceline %s\n", A.value);
+ }
+ else if (A.name == "SPICELINE2") {
+ sprintf(aspiceline2, "SYMATTR Spiceline2 %s\n", A.value);
+ }
+ else if (A.name == "SPICETYPE") {
+ sprintf(aspicetype, "SYMATTR Type %s\n", A.value);
+ }
+ }
+ }
+ printf("%s", aspiceprefix);
+ printf("%s", aspicemodel);
+ if (avalue2) printf("%s", avalue2);
+ if (aspiceline) printf("%s", avalue2);
+ if (aspicetype) {
+ printf("%s", aspicetype);
+ }
+ }
+ }
+ printf("SYMATTR Description %s\n", check_dev_description(DEV.description));
+ SYM.pins(P) ex_draw_pin(P, 1); // die Linien der Pins plus die PINs selbst zeichnen.
+ /* export no description
+ string descript = DEV.description;
+ if (!descript) descript = DEV.prefix;
+ printf("SYMATTR Description : %s Export with %s\n", descript, argv[0]);
+ SYM.pins(P) ex_draw_pin(P, ++pcnt); // die Pinkontakte selbst
+ */
+ } // end output()
+ }
+ }
+ }
+ }
+ }
+ if (Test) looptest(Ex_AsyName);
+ return;
+}
+
+
+void ex_draw_label(UL_LABEL L) {
+ // ein Flag ist ein Supply-Symbol, wobei nur zwischen 0 == GND und COM == Common unterschieden wird.
+ return;
+}
+
+
+void ex_draw_line(UL_WIRE W) {
+ return;
+}
+
+
+void ex_draw_rectangle(UL_RECTANGLE R) {
+ // RECTANGLE Normal 352 336 288 304
+ printf("RECTANGLE Normal %.0f %.0f %.0f %.0f\n",
+ ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y1)*-1.0),
+ ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y2)*-1.0)
+ );
+ return;
+}
+
+
+string ex_check_gate_name(UL_PART P, string igatename) {
+ // wenn Device aus nur 1 Gate besteht, dann keine Gate-Namen verwenden
+ int gcnt = 0;
+ P.deviceset.gates(G) {
+ gcnt++;
+ }
+ //string h;
+ //sprintf(h, "%s (%s) has %d gates!", P.name, P.deviceset.name, gcnt);
+ if (gcnt == 1) return "";
+ return igatename;
+}
+
+
+void ex_draw_instance(UL_INSTANCE I, UL_PART P) {
+ int cnttext = 0;
+ int cntpin = 0;
+ string h;
+ string currentgatename = ex_check_gate_name(P, I.gate.name);
+ string libpath;
+
+ I.gate.symbol.texts(T) {
+ if (T.layer == Ex_LayerSpiceOrder) {
+ if (strstr(T.value, "SpiceOrder") == 0) cnttext++;
+ }
+ }
+ I.gate.symbol.pins(P) {
+ cntpin++;
+ }
+ if (cnttext != cntpin || !cnttext) {
+ if (!cnttext) {
+ sprintf(h, "!No SpiceOrder in symbol %s of Part %s,\nplease define the SpiceOder for PINs first!", I.gate.symbol.name, P.name);
+ }
+ if (cnttext != cntpin) {
+ sprintf(h, "!Different quantity of SpiceOrder and PINs in symbol %s of part %s (%s).\nPlease check symbol!",
+ I.gate.symbol.name, P.name, P.device.name
+ );
+ }
+ dlgMessageBox(h, "OK");
+ libpath = file_search(P.deviceset.library+".lbr", EAGLE_DIR, 4, "1733");
+ if (strstr(libpath, P.deviceset.library) < 0) {
+ dlgMessageBox("Library " + P.deviceset.library + ".lbr not found in path:\n"+ EAGLE_DIR, "OK");
+ if (dlgMessageBox("Export from schematic ?", "YES", "CANCEL") != 0) exit(-1739);
+ exit("RUN exp-project-lbr");
+ }
+ sprintf(h, "OPEN '%s';\nEDIT %s.DEV;RUN spiceorder.ulp", libpath, P.deviceset.name);
+ //if (dlgMessageBox(h, "ok", "esc1740") != 0) exit(-1743);
+ exit(h);
+ }
+ if (P.deviceset.library == "lt-supply") { // LTspice-Versorgungssymbole bzw. LABEL müssen in der lt-supply.lbr angelegt sein!
+ // FLAG(s) haben keine Rotation, sie werden anhand der Richtung des angelegten WIRE ausgerichtet!
+ if (P.device.name == "0") { // FLAG 144 -416 0
+ printf("FLAG %.0f %.0f 0\n", ex_spicegrid(u2mil(I.x)), ex_spicegrid(u2mil(I.y)*-1.0));
+ return;
+ }
+ else if (P.device.name =="COM") { // FLAG -128 288 COM
+ printf("FLAG %.0f %.0f COM\n", ex_spicegrid(u2mil(I.x)), ex_spicegrid(u2mil(I.y)*-1.0));
+ return;
+ }
+ else {
+ printf("FLAG %.0f %.0f %s\n", ex_spicegrid(u2mil(I.x)), ex_spicegrid(u2mil(I.y)*-1.0), P.device.name);
+ return;
+ }
+ }
+
+ string devicename = P.device.name;
+ if (P.deviceset.library == "lt-spice-simulation") { // Spezielle Behandlung von Bauteilen aus der Simulations-LBR
+ if (devicename == "RES_RLOAD") devicename = "res"; // Konvertiere einen LOAD-Resistor wieder zurück zu "res"
+ else if (devicename == "VOLTAGE");
+ else if (devicename == "CURRENT");
+ else if (devicename == "BV");
+ else if (devicename == "E");
+ else if (devicename == "LOAD"); // ein LOAD (veränderbarer Widerstand) als Last aus der lt-spice-simulation.lbr
+ else {
+ dlgMessageBox("Unknown simulation part " +P.name+ " (Device:"+ devicename + "), please check : " + P.deviceset.library + ".lbr", "OK");
+ exit(-1772);
+ }
+ }
+ // Prüfe das Vorhandensein des benötigten Symbol in der LTspice-Datenstruktur.
+ // Müssen bestimmte Symbole in bestimmten Verzeichissen abgelegt sein?
+ string asyfile;
+ if (P.deviceset.library == "lt-spice-simulation") {
+ asyfile = check_exist_asy(ex_check_dev_name(devicename+currentgatename+".asy"), LTSpiceLibDir, "init");
+ }
+ else if (P.deviceset.library == "lt-supply") {
+ if (dlgMessageBox(devicename+currentgatename+".asy" + ":" + LTSpiceLibDir , "ok1779", "esc1779") != 0) exit(-1782);
+ }
+ else {
+ asyfile = check_exist_asy(ex_check_dev_name(devicename+currentgatename+".asy"), LTSpiceLibDir, "1782"); // evtl. einen Ordner weiter unten beginnen, ExpEagleSpiceSymDir);
+ }
+ if (!asyfile) { // 2014-01-23
+ if (dlgMessageBox(LTSpiceLibDir + "\n" + devicename+currentgatename + ".asy\ndoes not exist as LTspice symbol.\nOpen library and deviceset, and export device (symbols).", "OK", "CANCEL") != 0) exit(-1788);
+ libpath = file_search(P.deviceset.library+".lbr", EAGLE_DIR, 4, "1786");
+ sprintf(h, "OPEN '%s';\nEDIT %s.DEV;", libpath, P.deviceset.name);
+ exit(h);
+ }
+
+ /* *** Lastwiderstände "Rload" benutzen das selbe Symbol wie R (res.asy) beim ****
+ **** importieren wird dem Devicenamen (Instance) der Zusatz "_RLOAD" vergeben. *** */
+ if (devicename == "RES_RLOAD") devicename = "res"; // hier ohne den expliziten Hinweis auf die Herkunft (LBR)
+
+ string rotation;
+ sprintf(rotation, "R%.0f", I.angle); // ok 2012-05-11
+ if (rotation == "R0" && I.mirror) rotation = "M0";
+ else if (rotation == "R180" && I.mirror) rotation = "M180";
+ else if (rotation == "R180") rotation = "R180";
+ else if (rotation == "R90" && I.mirror) rotation = "M270";
+ else if (rotation == "R90") rotation = "R270";
+ else if(rotation == "R270" && I.mirror) rotation = "M90";
+ else if(rotation == "R270") rotation = "R90";
+
+ printf("SYMBOL %s %.0f %.0f %s\n",
+ // Device- und Gate-Namen dürfen keine Slash enthalten, siehe LTspiceFormatInfo.
+ ex_check_dev_name(devicename+currentgatename), // aktueller Gatename, wenn Device aus mehr als 1 Gate besteht
+ /*** hier fehlt evtl. noch die Technologie ***/
+ ex_spicegrid(u2mil(I.x)),
+ ex_spicegrid(u2mil(I.y)*-1.0),
+ rotation
+ );
+ string iname = I.name;
+ if (strstr(iname, "RLOAD") == 0) {
+ // iname = "Rload"; Kleinschreibung muß nicht sein!
+ }
+ printf("SYMATTR InstName %s\n", iname);
+ printf("SYMATTR Value %s\n", I.value);
+ string SPICEMODEL = "", VALUE2 = "", SPICELINE = "", SPICELINE2 = "", SPICETYPE = "", NAME = "", VALUE = "";
+
+ /* nur in der LBR für das Symbol ausgeben
+ if (P.attribute["SPICEMODEL"]) {
+ SPICEMODEL = P.attribute["SPICEMODEL"];
+ } */
+ if (P.attribute["VALUE2"]) {
+ VALUE2 = P.attribute["VALUE2"];
+ if (VALUE2) printf("SYMATTR Value2 %s\n", VALUE2);
+ }
+ if (P.attribute["SPICELINE"]) {
+ SPICELINE = P.attribute["SPICELINE"];
+ if(SPICELINE) printf("SYMATTR SpiceLine %s\n", SPICELINE);
+ }
+ if (P.attribute["SPICELINE2"]) {
+ SPICELINE2 = P.attribute["SPICELINE2"];
+ if(SPICELINE2) printf("SYMATTR SpiceLine2 %s\n", SPICELINE2);
+ }
+ if (P.attribute["SPICETYPE"]) {
+ SPICETYPE = P.attribute["SPICETYPE"];
+ if (SPICETYPE) {
+ printf("SYMATTR Type %s\n", SPICETYPE);
+ }
+ }
+
+ I.gate.symbol.texts(T) {
+ if (strupr(T.value) == ">VALUE") VALUE = T.value;
+ }
+
+ I.texts(T) {
+ int windowattrib = -1;
+ int textoffset = 0;
+ if (I.name == T.value) windowattrib = 0;
+ else if (I.value == T.value) windowattrib = 3;
+ else if (SPICETYPE == T.value) windowattrib = 1;
+ else if (SPICEMODEL == T.value) windowattrib = 38;
+ else if (SPICELINE == T.value) windowattrib = 39;
+ else if (SPICELINE2 == T.value) windowattrib = 40;
+ else if (VALUE2 == T.value) windowattrib = 123;
+ if (windowattrib >=0) {
+ printf("WINDOW %d %s %s %.0f\n",
+ windowattrib,
+ ex_spicetextcoord(T, I),
+ ex_checktextangle(T.align, T.angle, P.name, I.angle),
+ u2mil(textoffset)
+ );
+ }
+ }
+
+ return;
+}
+
+
+/****************** Import functions *********************/
+void imp_Testview(string head) {
+ int sel = 0;
+ int srt = 0;
+ for (int n = 0; n < Imp_CntW; n++) {
+ sprintf(Imp_LineView[n], "%d\t%d\t%d\t%d\t%d\t%d\t%d", n, Imp_WireX1[n], Imp_WireY1[n], Imp_WireX2[n], Imp_WireY2[n], Imp_WireSeg[n], Imp_WireType[Imp_WireSeg[n]]);
+ }
+ dlgDialog(head) {
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(400);
+ dlgListView("Nr.\tx1\ty1\tx2\ty2\tSegnr\t1 BUS/2 NET", Imp_LineView, sel, srt);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-1890); }
+ dlgStretch(1);
+ }
+ };
+ return;
+}
+
+
+void imp_helpSimulationSymbols(void) {
+ dlgDialog("HELP import-LTspice") {
+ dlgHBoxLayout dlgSpacing(400);
+ dlgLabel(Imp_InfoExternalSymbol);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ return;
+}
+
+
+string imp_dirname(string name) { // ermittle den letzen Verzeichnisnamen
+ string s[];
+ int cntd = strsplit(s, name, '/');
+ if (cntd > 1) return s[cntd-2];
+ return s[0];
+}
+
+
+string imp_check_use(string lname) { // check exist lbr in library path
+ if (!lname) return "";
+
+ for (int n = 0; n < Imp_CntUsedLbrs; n++) { // check lbr in used list?
+ if (Imp_UsedLbrs[n] == lname) return ""; // LBR are in use
+ }
+ int nl = 0;
+ int exist = 0;
+ string lb[];
+ string dir = filedir(lname); // prüfe auf kompletten Pfad-Datei-Namen
+ if (dir) { // mit Pfad zur Lib
+ if (fileglob(lb, lname)) {
+ Imp_Cmd += "USE '" + lname + "'; #1933\n";
+ Imp_UsedLbrs[Imp_CntUsedLbrs] = lname; // set lbr on used list
+ Imp_CntUsedLbrs++;
+ return "@"+lname;
+ }
+ else {
+ do {
+ if (fileglob(lb, path_lbr[nl] + "/" + lname + "*.lbr")) {
+ Imp_Cmd += "USE '" + path_lbr[nl] + "/" + lname + ".lbr'; #1941\n";
+ Imp_UsedLbrs[Imp_CntUsedLbrs] = lname; // set lbr on used list
+ Imp_CntUsedLbrs++;
+ return "@"+path_lbr[nl] + "/" + lname + ".lbr";
+ }
+ nl++;
+ } while(path_lbr[nl]);
+
+ dlgMessageBox("!Library does not exist:\n\n\"" + lname + "\"\n\nULP aborted.", "OK");
+ //return "lbr not found";
+ exit(-1951);
+ }
+ }
+ else { // Ohne Pfad zur Lib, suche in allen Verzeichnissen die im Control-Panel angegeben sind.
+ do {
+ if (fileglob(lb, path_lbr[nl] + "/" + lname + "*.lbr")) {
+ Imp_Cmd += "USE '" + path_lbr[nl] + "/" + lname + ".lbr'; #1957\n";
+ Imp_UsedLbrs[Imp_CntUsedLbrs] = lname; // set lbr on used list
+ Imp_CntUsedLbrs++;
+ return "@"+path_lbr[nl] + "/" + lname + ".lbr";
+ }
+ nl++;
+ } while(path_lbr[nl]);
+ dlgMessageBox("!Library " + lname + ".lbr can't be found in path! Please check: Control Panel - Options - Directories - Libraries. Add path of : " + lname + ".lbr. " +
+ "Are you sure, you have imported this lbr from LTspice?", "OK");
+ exit(-3);
+ }
+}
+
+
+int check_exist_packname(string pacname) {
+ int len = strlen(pacname);
+ if (!len) {
+ dlgMessageBox("! No package name : Error 1674", "CANCEL"); exit(-1962);
+ }
+ if (pacname[len-1] == '\'') pacname[len-1] =0;
+ if (pacname[0] == '\'') pacname = strsub(pacname, 1);
+
+ library(L) L.packages(PAC) {
+ if (PAC.name == pacname) return 1;
+ }
+ return 0;
+}
+
+
+string get_pac_from_script(string scriptname) { // lade existierendes script und suche nach der Packagebezeichnung
+ string scrlines[];
+ int cntsline = fileread(scrlines, scriptname);
+ string s[];
+ int cnt;
+ int pacexist = 0;
+ int paccnt = 0;
+ string pacname = "";
+ for ( int n = 0; n < cntsline; n++) {
+ cnt = strsplit(s, scrlines[n], ' ');
+ if (s[0] == "Package") {
+ paccnt++;
+ if (check_exist_packname(s[1])) {
+ pacname = s[1];
+ pacexist++;
+ }
+ else {
+ dlgMessageBox("!Script:" + scriptname + "\nPackage " + s[1] + " not found in lbr.", "OK");
+ exit(-1992);
+ }
+ }
+ else if (s[1] == "Package") { // Die Zeile beginnt mit einem SPACE
+ paccnt++;
+ if (check_exist_packname(s[2])) {
+ pacname = s[2];
+ pacexist++;
+ }
+ else {
+ dlgMessageBox("!Script:\n" + scriptname + "\nPackage " + s[2] + " not found in lbr.", "OK");
+ exit(-2003);
+ }
+ }
+ }
+ if (paccnt == pacexist) return pacname; // das zuletzt gefundene Package wird zurückgegeben
+ return "";
+}
+
+
+string imp_checkpinname(string pname) {
+ /*
+ LTspice läßt gleichen Pin-Namen mehrfach zu,
+ in Eagle muß der Pinname eindeutig sein,
+ hier wird geprüft ob der Pinname einzigartig ist.
+ Wenn nein, dann wird "@n" hinzugefügt, wobei im SCH
+ das Zeichen @ und alle dahinter vorkommenden Zeichen
+ nicht angezeigt werden. n wird hochgezählt.
+ */
+ if (pname[0] == '_') pname[0] = '!'; // LTspice benutzt das Underlinezeichen als Einleitung des Negierungsüberstrich,
+ string name = pname; // Eagle benutzt das Ausrufezeichen, also tauschen.
+ int cnt = 0;
+ do {
+ int found = 0;
+ for(int n = 0; n < Imp_CntPinname; n++) {
+ if (name == Imp_SpicePinName[n]) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ Imp_SpicePinName[Imp_CntPinname] = name;
+ Imp_CntPinname++;
+ return name;
+ }
+ else {
+ sprintf(name, "%s@%d", pname, ++cnt);
+ }
+ } while(pname);
+}
+
+
+real imp_eagle_coordvalue(real v) { // calculate LT_SPice-16-Grid to Eagle-100-mil-Grid
+ return (v / 16) * 100;
+}
+
+
+void imp_add_wire(int x1, int y1, int x2, int y2) {
+ Imp_WireX1[Imp_CntW] = x1; // für die spätere Untersuchung wegen des BUS-Flags
+ Imp_WireY1[Imp_CntW] = y1;
+ Imp_WireX2[Imp_CntW] = x2;
+ Imp_WireY2[Imp_CntW] = y2;
+ Imp_CntW++;
+
+ // LT-Spice rotiert ein FLAG (Supplypin/Label) automatisch
+ // anhand der Ausrichtung des Wire, an dessen Ende das FLAG sitzt.
+ // Dazu muß man alle Wire sammeln, um dann später die Rotation
+ // des FLAG zu bestimmen.
+ // Hier wird die Tabelle aufgebaut, für die Funktion lookup().
+ sprintf(Imp_Coords[Imp_CntCo], "%d %d;%d %d", x1, y1, x2, y2); // erstellen der Tabelle für lookup()
+ Imp_CntCo++;
+ sprintf(Imp_Coords[Imp_CntCo], "%d %d;%d %d", x2, y2, x1, y1);
+ Imp_CntCo++;
+ return;
+}
+
+
+int imp_getflagrotate(string coord, string l) {
+ string xy2[];
+ strsplit(xy2, lookup(Imp_Coords, coord, 1, ';'), ' '); // prüfe auf übereinstimmung der Wire-Koordinaten
+ if (!xy2[0]) { // Rückgabewert ist leer, wenn keine Wire-Koordinate gefunden wurde.
+ strsplit(xy2, coord, ' ');
+ sprintf(h, "Import line: %s\nCould not find wire's coordinates in order to place a supply symbol.\n(%.4fmil %.4fmil)",
+ l,
+ imp_eagle_coordvalue(strtod(xy2[0])), // als Eagle-Koordinate anzeigen
+ imp_eagle_coordvalue(strtod(xy2[1]))*-1.0
+ );
+ if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-2079);
+ return 0;
+ }
+ real r;
+ string xy1[];
+ strsplit(xy1, coord, ' ' );
+ int x1 = strtol(xy1[0]);
+ int y1 = strtol(xy1[1]);
+ int x2 = strtol(xy2[0]);
+ int y2 = strtol(xy2[1]);
+ if (x1 == x2) { // vertical
+ if (y1 < y2) Imp_FlagRotate = 180.0; // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ else Imp_FlagRotate = 0.0;
+ }
+ else if (y1 == y2) { // horizontal
+ if (x1 < x2) Imp_FlagRotate = 270.0; // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ else Imp_FlagRotate = 90.0;
+ }
+ else Imp_FlagRotate = 0.0;
+ return 1;
+}
+
+
+void imp_get_net_segment(void) {
+ /*
+ LT-Spice zeichnet WIRE immer von rechts nach links, und von unten nach oben!
+ Ein BUS wird erst am Ende durch ein BUSTAP markiert.
+ In Eagle wird NET und BUS unterschieden, sowohl als Befehl als auch als Objekt.
+ Hier müssen zuerst die Segmente zugeordnet werden, und dann als NET oder BUS
+ gezeichnet werden.
+
+ WireSeg[]; // Da ein NET sehr verzweigt, und später mit einem BUSTAB zu einem BUS deklariert werden kann,
+ // werden die Wire, Segmenten zugeordnet.
+ WireType[]; // Der Index des WireType entspricht der Segmentnummer.
+ // Der Inhalt wird zunächst auf NET gesetzt, wird im Segment eine Koordinate eines BUSTAB
+ // gefunden, so wird das Segment auf BUS gesetzt.
+ CntSeg = 0; // Anzahl der Segmente
+
+ */
+ int found = 0;
+ Imp_CntSeg = 0;
+ int fx1 = Imp_WireX1[0];
+ int fy1 = Imp_WireY1[0];
+ int fx2 = Imp_WireX2[0];
+ int fy2 = Imp_WireY2[0];
+
+ for (int n = 0; n < Imp_CntW; n++) {
+ if (!Imp_WireSeg[n]) {
+ Imp_WireSeg[n] = ++Imp_CntSeg;
+ Imp_WireType[Imp_CntSeg] = NET; // setze Segment-Type NET als Default
+ }
+ fx1 = Imp_WireX1[n];
+ fy1 = Imp_WireY1[n];
+ fx2 = Imp_WireX2[n];
+ fy2 = Imp_WireY2[n];
+
+ do {
+ found = 0;
+ for(int i = n+1; i < Imp_CntW; i++) {
+ if (!Imp_WireSeg[i]) {
+ if ( Imp_WireX1[i] == fx1 && Imp_WireY1[i] == fy1 || Imp_WireX2[i] == fx2 && Imp_WireY2[i] == fy2 ||
+ Imp_WireX1[i] == fx2 && Imp_WireY1[i] == fy2 || Imp_WireX2[i] == fx1 && Imp_WireY2[i] == fy1 ) {
+ Imp_WireSeg[i] = Imp_CntSeg;
+ found = i;
+ fx1 = Imp_WireX1[i];
+ fy1 = Imp_WireY1[i];
+ fx2 = Imp_WireX2[i];
+ fy2 = Imp_WireY2[i];
+ }
+ }
+ }
+ } while (found > 0);
+ }
+ Imp_WireChecked = 1; // Segmente ermittelt
+ return;
+}
+
+
+void imp_check_bus(int x, int y) { // check Koordinate auf BUSTAB
+ for (int n = 0; n < Imp_CntW; n++) {
+ if ( Imp_WireX1[n] == x && Imp_WireY1[n] == y || Imp_WireX2[n] == x && Imp_WireY2[n] == y) {
+ Imp_WireType[Imp_WireSeg[n]] = BUS;
+ break;
+ }
+ }
+ return;
+}
+
+
+void imp_draw_net(void) { // zeichne alle NETze und BUSse
+ Imp_Cmd += "SET CONFIRM YES;\n";
+ string commandtype = "NET";
+ for (int n = 0; n < Imp_CntW; n++ ) {
+ commandtype = "NET";
+ if (Imp_WireType[Imp_WireSeg[n]] == BUS) {
+ sprintf(commandtype, "BUS 'B_$%d' ", Imp_WireSeg[n]);
+ }
+ sprintf(h, "%s (%.4f %.4f) (%.4f %.4f);\n",
+ commandtype,
+ imp_eagle_coordvalue(Imp_WireX1[n]),
+ imp_eagle_coordvalue(Imp_WireY1[n])*-1.0,
+ imp_eagle_coordvalue(Imp_WireX2[n]),
+ imp_eagle_coordvalue(Imp_WireY2[n])*-1.0
+ );
+ Imp_Cmd+= h;
+ }
+ Imp_Cmd += "SET CONFIRM OFF;\n";
+ Imp_DrawNetBus = 1; // Flag NET/BUS gezeichnet
+ return;
+}
+
+
+void imp_version(string l) {
+ // Version 4
+ string s[];
+ int n = strsplit(s, l, ' ');
+ int versionnumber = strtol(s[1]);
+ sprintf(h, "# Spice version %d\n", versionnumber);
+ Imp_Cmd += h;
+ return;
+}
+
+
+// calculate angle from a pair of coordinates
+real imp_wire_angle(int x1, int y1, int x2, int y2) {
+ real xe = imp_eagle_coordvalue(x1);
+ real ye = imp_eagle_coordvalue(y1);
+ real xa = imp_eagle_coordvalue(x2);
+ real ya = imp_eagle_coordvalue(y2);
+ real RADIUS = sqrt(((xa - xe) * (xa - xe)) + ((ya - ye) * (ya - ye)));
+
+ if ((xa > xe) && (ya >= ye)) { /* Quadrant 1 */
+ return acos((xa - xe) / RADIUS) * 57.29578;
+ }
+ if ((xa < xe) && (ya >= ye)) { /* Quadrant 2 */
+ return acos((xa - xe) / RADIUS) * 57.29578;
+ }
+ if ((xa < xe) && (ya < ye)) { /* Quadrant 3 */
+ return 360 - acos((xa - xe) / RADIUS) * 57.29578;
+ }
+ if ((xa > xe) && (ya < ye)) { /* Quadrant 4 */
+ return 360 - acos((xa - xe) / RADIUS) * 57.29578;
+ }
+ if ((xa == xe) && (ya == ye)) { /* Ursprung */
+ return (xa - xe);
+ }
+ if ((xa == xe) && (ya > ye)) { /* 90 */
+ return (xa - xe + 90);
+ }
+ if ((xa == xe) && (ya < ye)) { /* 270 */
+ return (xa - xe + 270);
+ }
+}
+
+
+/******************************************************
+ parse library lines
+******************************************************/
+void imp_symboltype(string l){
+ // SymbolType CELL
+ // SymbolType BLOCK
+ string s[];
+ int n = strsplit(s, l, ' ');
+ string symboltype = s[1];
+
+ if (symboltype == "CELL") {
+ }
+ else if (symboltype == "BLOCK") {
+ }
+ else {
+ dlgMessageBox("Unknown symbol type:\n" + l, "CANCEL");
+ exit(-2250);
+ }
+ sprintf(h, "# Symbol Type %s\n", symboltype);
+ Imp_Cmd += h;
+ sprintf(h, "CHAnge Align Left Center; # Symbol\n");
+ Imp_Cmd += h;
+ return;
+}
+
+
+void imp_line(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ if (s[1] == "Normal") {
+ Imp_Cmd+="CHANGE WIDTH 6 ;\n";
+ }
+ else if (s[1] == "Bold") {
+ Imp_Cmd+="CHANGE WIDTH 10;\n";
+ }
+ else {
+ string e;
+ sprintf(e, "Unknown LINE " + s[1]);
+ dlgMessageBox(e, "OK");
+ exit(-2273);
+ }
+ if (s[6]) {
+ if (s[6] == "0") {
+ Imp_Cmd += "CHANGE STYLE Continuous;\n";
+ }
+ else if (s[6] == "1") {
+ Imp_Cmd += "CHANGE STYLE LongDash;\n";
+ }
+ else if (s[6] == "2") {
+ Imp_Cmd += "CHANGE STYLE ShortDash;\n";
+ }
+ else if (s[6] == "3") {
+ Imp_Cmd += "CHANGE STYLE DashDot;\n";
+ }
+ else {
+ Imp_Cmd += "CHANGE STYLE Continuous;\n";
+ }
+ }
+ sprintf(h, "SET WIRE_BEND 2;\nLAYER 94;\nWIRE (%.4f %.4f) (%.4f %.4f);\n",
+ imp_eagle_coordvalue(strtod(s[2])),
+ imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[4])),
+ imp_eagle_coordvalue(strtod(s[5])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ );
+ Imp_Cmd+=h;
+ return;
+}
+
+
+void imp_rectangle(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ if (s[1] == "Normal") {
+ Imp_Cmd+="CHANGE WIDTH 6;\n";
+ }
+ else if (s[1] == "Bold") {
+ Imp_Cmd+="CHANGE WIDTH 10;\n";
+ }
+ sprintf(h, "SET WIRE_BEND 2;\nLAYER 94;\nWIRE (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n",
+ imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[4])), imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[4])), imp_eagle_coordvalue(strtod(s[5])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[5])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ );
+ Imp_Cmd+=h;
+ return;
+}
+
+
+void imp_circle(string l) {
+ /*
+ Definition eines CIRCLE:
+ Die ersten zwei Koordinaten definieren mit den zwei diagonalen Ecken ein umschliesendes
+ Rechteck um den Kreis. Innerhalb dieses Rechteck befindet sich der Kreis, also
+ ist Breite und Länge des Rechteck zugleich der Durchmesser.
+ */
+ string s[];
+ int n = strsplit(s, l, ' ');
+ if (s[1] == "Normal") {
+ Imp_Cmd+="CHANGE WIDTH 6 ;\n";
+ }
+ else if (s[1] == "Bold") {
+ Imp_Cmd+="CHANGE WIDTH 10;\n";
+ }
+ sprintf(h, "LAYER 94;\nCIRCLE (%.4f %.4f) (%.4f %.4f);\n",
+ (imp_eagle_coordvalue(strtod(s[2])) + imp_eagle_coordvalue(strtod(s[4]))) / 2,
+ (imp_eagle_coordvalue(strtod(s[3])*-1.0) + imp_eagle_coordvalue(strtod(s[5])*-1.0)) / 2, // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ (imp_eagle_coordvalue(strtod(s[2])) + imp_eagle_coordvalue(strtod(s[4]))) / 2,
+ imp_eagle_coordvalue(strtod(s[5])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ );
+ Imp_Cmd+=h;
+ return;
+}
+
+
+void imp_arc(string l) {
+ // ARC Normal -20 -124 4 -100 -20 -112 -8 -100
+ /*
+ Definition des ARC:
+ Die ersten zwei Koordinaten definieren die zwei diagonalen Ecken eines umschließenden
+ Rechteck um einen Kreis. Die Mitte dieses Rechteck ist der Mittelpunkt des Kreises,
+ und somit der Mittelpunkt des ARC.
+ Die 3. und 4. Koordinate ergibt vom Mittelpunkt des zuvor definierten Kreises
+ den Anfangswinkel und die 7. und 8. Koordinate den Endwinkel.
+ Die Genauigkeit der Zeichnungen bezüglich der Enden eines ARC in LT-Spice, ist beschränkt
+ durch die relativ geringe Auflösung von 16 (Einheiten), siehe ARC in Optokoppler PC817D.
+ 2011-10-12
+ */
+ string s[];
+ int n = strsplit(s, l, ' ');
+ if (s[1] == "Normal") {
+ Imp_Cmd+="CHANGE WIDTH 6 ;\n";
+ }
+ else if (s[1] == "Bold") {
+ Imp_Cmd+="CHANGE WIDTH 10;\n";
+ }
+
+ if (n > 10) {
+ sprintf(h, "# %d Parameter in line:\n# %s\n", n, l);
+ Imp_Cmd+=h;
+ }
+ int centerx = (strtod(s[2]) + strtod(s[4])) / 2;
+ int centery = (strtod(s[3])*-1.0 + strtod(s[5])*-1.0) / 2;
+ int aax = strtod(s[6]);
+ int aay = strtod(s[7]) * -1;
+ int aex = strtod(s[8]);
+ int aey = strtod(s[9]) * -1;
+ int radius = strtod(s[4])- centerx;
+ if (radius < 0) radius *= -1; // Radius darf nie negativ sein.
+ real startangle = imp_wire_angle(centerx, centery, strtod(s[6]), strtod(s[7])*-1.0);
+ real endangle = imp_wire_angle(centerx, centery, strtod(s[8]), strtod(s[9])*-1.0);
+
+ /* P Polar-Koordinaten (relativ zur Marke, x = Radius, y = Winkel in Grad, gegen den Uhrzeigersinn) */
+ sprintf(h, "LAYER 94;\nMARK (%.4f %.4f);\nARC CCW (P%.4f %.4f) (P%.4f %.4f) (P%.4f %.4f);\nMARK;\n",
+ imp_eagle_coordvalue(centerx), imp_eagle_coordvalue(centery), // setze Marke ins Zentrum des ARC
+ imp_eagle_coordvalue(radius), startangle,
+ imp_eagle_coordvalue(radius), startangle + 180.0,
+ imp_eagle_coordvalue(radius), endangle
+ );
+ Imp_Cmd+=h;
+ return;
+}
+
+
+void imp_print_text(real thigh, char leading, string text, real tx, real ty) { // damit Eagle Directiven-Texte nicht überstreicht,
+ // muss das Einleitende ! mit einem Escapezeichen markiert werden.
+ string t[];
+ int cnt;
+
+ cnt = strsplit(t, text, '\''); // check Apostroph
+ /*
+ Text '''' == '
+ Text '''''' == ''
+ Text '''''''' == '''
+ Text '''ein Apostroph am Anfang'
+ Text 'ein Apostroph am Ende'''
+ Text 'ein Apostroph '' in der Mitte'
+ Text ''' vier '' Apostrophen '' verteilt'''
+ Text '''\\'''
+ */
+ if (cnt > 1) {
+ text = "";
+ for (int i = 0; i < cnt; i++) {
+ // da der ganze String in ' eingeschlossen wird,
+ // müssen die Apostrophen verdoppelt werden.
+ if (i == 0) {
+ if (t[i]) text += t[i];
+ }
+ else if (i) text += "''" + t[i];
+ }
+ }
+ if (leading) sprintf(h, "CHANGE SIZE %.0f;\nTEXT '%c%s' %s (%.4f %.4f);\n", thigh, leading, text, TextAlignRotation, tx, ty);
+ else sprintf(h, "CHANGE SIZE %.0f;\nTEXT '%s' %s (%.4f %.4f);\n", thigh, text, TextAlignRotation, tx, ty);
+ Imp_Cmd+=h;
+ return;
+}
+
+
+string imp_secondstr(string line, string w) { // return the rest of string after word
+ int pos = strstr(line, w) + strlen(w)+1;
+ return strsub(line, pos);
+}
+
+
+void imp_text(string l) {
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ // berechne den wirklichen Anfang des "Textes"
+ // TEXT -16 512 Left 2 A A A A
+ int textbegin = strlen(s[0]) + strlen(s[1]) + strlen(s[2]) + strlen(s[3]) + strlen(s[4]) + 5; // 5 = 5 Spaces
+ string text = strsub(l, textbegin);
+
+ TextAlignRotation = "R0";
+ if (s[3] == "Center") {
+ sprintf(TextAlign, "change align Center;\n");
+ }
+ else if(s[3] == "Left") {
+ sprintf(TextAlign, "change align Center Left;\n");
+ }
+ else if(s[3] == "Right") {
+ sprintf(TextAlign, "change align Center Right;\n");
+ }
+ else if(s[3] == "Top") {
+ sprintf(TextAlign, "change align Center Top;\n");
+ }
+ else if(s[3] == "Bottom") {
+ sprintf(TextAlign, "change align Center Bottom;\n");
+ }
+ else if(s[3] == "VLeft") { // 90gedreht
+ sprintf(TextAlign, "change align Center Left;\n");
+ TextAlignRotation = "R90";
+ }
+ else if(s[3] == "VRight") { // 90gedreht
+ sprintf(TextAlign, "change align Center Right;\n");
+ TextAlignRotation = "R90";
+ }
+ else if (s[3] == "VCenter") { // 90gedreht
+ sprintf(TextAlign, "change align Center;\n");
+ TextAlignRotation = "R90";
+ }
+ else if(s[3] == "VTop") { // 90gedreht
+ sprintf(TextAlign, "change align Center Top;\n");
+ TextAlignRotation = "R90";
+ }
+ else if(s[3] == "VBottom") { // 90! gedreht
+ sprintf(TextAlign, "change align Center Bottom;\n");
+ TextAlignRotation = "R90";
+ }
+ else {
+ dlgMessageBox("Unknown Text justification:" + s[3] + "\n" + Imp_SymDevName + "\n" + l, "ok", "esc");
+ exit(-2485);
+ }
+ Imp_Cmd+=TextAlign;
+ real texthigh = LTTextSize;
+ real textoffsety = 0;
+ real textoffsetx = 0;
+ char leadingcharacter = 0;
+
+ if (text[0] == ';') {
+ Imp_Cmd += "CHanGe Layer 94;\n";
+ }
+ else if (text[0] == '!') { // check spice directive
+ Imp_Cmd += "CHanGE Layer 97;\n";
+ leadingcharacter = '\\'; // Einleitendes Ausrufezeichen als Sonderzeichen definieren, da Eagle sonst den Text überstreicht.
+ }
+
+ imp_print_text(texthigh, leadingcharacter, text, imp_eagle_coordvalue(strtod(s[1])), imp_eagle_coordvalue(strtod(s[2])*-1.0)); // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ return;
+}
+
+
+void imp_window_sym(string l, int line) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ int winattrib = strtod(s[1]);
+
+ string h = "";
+ switch(winattrib) {
+ case 0 : Imp_Winattrib[0] = "0"; // InstName // WINDOW 0 273 -48 Bottom 2
+ sprintf(h, "Change Layer 95;\nChange Size 70mil;\nTexT '>NAME' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0));
+ Imp_Cmd += h;
+ break;
+
+ case 1 : Imp_Winattrib[1] = "1"; // Type
+ sprintf(h, "Change Layer 97;\nChange Size 10mil;\nTexT 'win1' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0));
+ Imp_Cmd += h;
+ break;
+
+ case 2 : Imp_Winattrib[2] = "2";
+ sprintf(h, "Change Layer 97;\nChange Size 10mil;\nTexT 'win2' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0));
+ Imp_Cmd += h;
+ break;
+
+ case 3 : Imp_Winattrib[3] = "3"; // Value // WINDOW 3 0 151 Center 0
+ sprintf(h, "Change Layer 96;\nChange Size 70mil;\nTexT '>VALUE' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0));
+ Imp_Cmd += h;
+ break;
+
+ case 38 : Imp_Winattrib[38] = "38"; // SpiceModel // WINDOW 38 0 32 Center 0
+ Imp_SpiceModelSymX = imp_eagle_coordvalue(strtod(s[2]));
+ Imp_SpiceModelSymY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ Imp_SpiceModelSymAlign = s[4];
+ Imp_SpiceModelSymOffset = imp_eagle_coordvalue(strtod(s[5]));
+ if (Imp_SpiceModelSymAlign != "Center") if (dlgMessageBox(l + "\error 2246", "OK", "CANCEL") != 0) exit(-2538);
+ break;
+
+ case 39 : Imp_Winattrib[39] = "39"; // SpiceLine // WINDOW 39 273 154 Center 2
+ Imp_SpiceLineSymX = imp_eagle_coordvalue(strtod(s[2]));
+ Imp_SpiceLineSymY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ Imp_SpiceLineSymAlign = s[4];
+ Imp_SpiceLineSymOffset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ case 40 : Imp_Winattrib[40] = "40"; // SpiceLine2
+ Imp_SpiceLine2SymX = imp_eagle_coordvalue(strtod(s[2]));
+ Imp_SpiceLine2SymY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ Imp_SpiceLine2SymAlign = s[4];
+ Imp_SpiceLine2SymOffset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ case 123 : Imp_Winattrib[123] = "123"; // Value2
+ sprintf(h, "Change Layer 96;\nChange Size 70mil;\nTexT '>VALUE2' (%.4f %.4f);\n", // Attribute Platzhalter
+ imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0)
+ );
+ Imp_Cmd += h;
+ break;
+
+ default : sprintf(h, "File:%s\nUnknown window attribute \"%s\" in line :%d\n%s", Imp_SymDevName, s[1], line+1, l);
+ if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-2563);
+ }
+ return;
+}
+
+void attribute2script(string at, string symbolfile, string mode) {
+ output(filesetext(symbolfile, ".scr"), mode) {
+ printf("%s", at);
+ }
+ return;
+}
+
+string imp_symattr_sym(string l, int cnt, string source) {
+ /***3
+ Zu diesem Zeitpunk existiert noch kein Package, also kann man Attribute nur für das Packagelose
+ Device anlegen!
+ Das anlegen einer Package-Variante, löscht die Attribute, die keinem Package zugeordnet sind.
+ Die Attribute müssen in einem separaten SCRIPT eingetragen werden, daß dann zu gegebenen Zeitpunkt
+ nach dem erzeugen der Package-Variante gestartet wird.
+ ***3 ***/
+ string s[];
+ int n = strsplit(s, l, ' ');
+ string sy;
+ if (s[1] == "Prefix") {
+ Imp_Winattrib[0] = s[2];
+ sprintf(sy, "ATTRIBUTE SPICEPREFIX '%s';\n", Imp_Winattrib[0]); // 2012-10-04
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+
+ else if (s[1] == "Value") { // Value [3]
+ Imp_Winattrib[3] = s[2];
+ attribute2script("VALUE OFF;\n", source, FileAppend); // im Device ablegen ***3
+ return ""; // im Device ablegen
+ }
+
+ else if (s[1] == "SpiceModel") { // SpiceModel [38]
+ Imp_Winattrib[38] = s[2];
+ sprintf(sy, "ATTRIBUTE 'SPICEMODEL' '%s';\n", Imp_Winattrib[38]);
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+
+ else if (s[1] == "SpiceLine") { // SpiceLine Imp_Winattrib[39]
+ if (Imp_Winattrib[39]) {
+ sprintf(sy, "Change Layer %d;\nChange Size 70mil;\nCHanGE Align %s;\nTexT 'Spiceline>%s' (%.4f %.4f);\n",
+ LayerSpiceOrder,
+ Imp_SpiceLineSymAlign,
+ imp_secondstr(l, s[1]), // Spiceline : können mehrere Wörter durch Space getrennt sein
+ Imp_SpiceLineSymX, Imp_SpiceLineSymY
+ );
+ Imp_Cmd += sy; // im Symbol ablegen
+ return "";
+ }
+ else {
+ sprintf(sy, "ATTRIButE 'Spiceline' '%s';\n", // im Device als Attribute ablegen
+ imp_secondstr(l, s[1]) // Spiceline : können mehrere Wörter durch Space getrennt sein
+ );
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+ }
+
+ else if (s[1] == "SpiceLine2") { // SpiceLine2 Winattrib[40]
+ if (Imp_Winattrib[40]) {
+ sprintf(sy, "Change Layer %d;\nChange Size 70mil;\nTexT 'Spiceline2>%s' (%.4f %.4f);\n", // im Symbol ablegen
+ LayerSpiceOrder, imp_secondstr(l, s[1]), // Spiceline2 : können mehrere Wörter durch Space getrennt sein
+ Imp_SpiceLine2SymX, Imp_SpiceLine2SymY
+ );
+ Imp_Cmd+= sy;
+ return "";
+ }
+ else {
+ sprintf(sy, "ATTRIButE 'Spiceline2' '%s';\n", // im Device als Attribute ablegen
+ imp_secondstr(l, s[1]) // Spiceline2 : können mehrere Wörter durch Space getrennt sein
+ );
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+ }
+
+ else if (s[1] == "Value2") { // Value2 [123]
+ Imp_Winattrib[123] = imp_secondstr(l, s[1]);
+ sprintf(sy, "ATTRIBUTE 'VALUE2' '%s'; #2658\n", Imp_Winattrib[123]);
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+
+ else if (s[1] == "Description") {
+ string descript;
+ sprintf(descript, "DESCRIPTION '%s'\n", imp_secondstr(l, s[1]));
+ return descript; // im Device ablegen
+ }
+
+ else if (s[1] == "ModelFile") {
+ Imp_Winattrib[123] = s[2];
+ sprintf(sy, "ATTRIBUTE 'ModelFile' '%s'; #2671\n", Imp_Winattrib[123]);
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+ else if (s[1] == "DefSubstrate") {
+ sprintf(sy, "ATTRIBUTE 'DefSubstrate' '%s'; #2676\n", s[2]);
+ attribute2script(sy, source, FileAppend); // im Device ablegen ***3
+ return "";
+ }
+
+ sprintf(h, "%s:\nUnknown SYMATTR in line %d:\n%s", source, cnt+1, l);
+ if (dlgMessageBox(h, "OK", "ESC") != 0) exit(-2670);
+ return "";
+}
+
+
+string imp_pin(string l) {
+ string s[];
+ int n = strsplit(s, l, ' ');
+ string coord;
+
+ if (s[3] == "NONE") { // bedeutet der PIN hat keinen sichbaren Namen
+ sprintf(coord, "%.4f %.4f\t%.4f %.4f\t%s",
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1]) + strtod(s[4])), // plus offset
+ imp_eagle_coordvalue(strtod(s[2])*-1.0),
+ s[3]
+ );
+ }
+ else if (s[3] == "LEFT") { // bedeutet der PIN steht an der linken Seite und der Name des Pin verschieb sich nach rechts
+ sprintf(coord, " %.4f %.4f\t%.4f %.4f\t%s",
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1]) + strtod(s[4])), // plus offset
+ imp_eagle_coordvalue(strtod(s[2])*-1.0),
+ s[3]
+ );
+ }
+ else if (s[3] == "RIGHT") {// bedeutet der PIN steh an der rechten Seite und der Name des Pin verschieb sich nach links
+ sprintf(coord, "%.4f %.4f\t%.4f %.4f\t%s",
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1]) - strtod(s[4])), // minus offset
+ imp_eagle_coordvalue(strtod(s[2])*-1.0),
+ s[3]
+ );
+ }
+ else if (s[3] == "TOP") { // bedeutet der PIN steht an der oberen Seite und der Name des Pin verschieb sich nach unten
+ sprintf(coord, "%.4f %.4f\t%.4f %.4f)\t%s",
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue((strtod(s[2]) + strtod(s[4]))*-1.0), // plus offset
+ s[3]
+ );
+ }
+ else if (s[3] == "BOTTOM") { // bedeutet der PIN steht an der unteren Seite und der Name des Pin verschieb sich nach oben
+ sprintf(coord, "%.4f %.4f\t%.4f %.4f\t%s",
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue((strtod(s[2]) - strtod(s[4]))*-1.0), // minus offset
+ s[3]
+ );
+ }
+ else {
+ string e;
+ sprintf(e, "Unknown '%s' in %s\nerror 2436", s[3], l);
+ dlgMessageBox(e, "OK");
+ }
+ return coord;
+}
+
+
+void imp_pinattr(string l, string coordpin, string coordname, string orientation) {
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+
+ string k[];
+ int cntk = strsplit(k, coordname, ' ');
+ real kx = strtod(k[0]);
+ real ky = strtod(k[1]);
+
+ if (s[1] == "PinName") {
+ if (cnt > 3) { // Mehr als 3 Teilstrings bedeutet der Pin-Name besteht aus mehreren Teilstrings (Leerzeichen getrennt).
+ for (int n = 3; n < cnt; n++) { // LTspice läßt im Namen SPACE (Leerzeichen) zu, in Eagle sind SPACE verboten!
+ s[2] += "_" + s[n];
+ }
+ }
+ Imp_SymPinName = strupr(s[2]); // Pinnamen in Eagle nur in upper case
+ // Pin name of pin to use with CONNECT
+ // PINATTR PinName _RST der Unterstrich bedeutet das Negierungszeichen, in Eagle das !
+ if (Imp_SymPinName[0] == '_') Imp_SymPinName[0] = '!'; // ! das Negierungszeichen in EAGLE
+
+ Imp_SymPinName = imp_checkpinname(Imp_SymPinName); // doppelte Pin-Namen dürfen nicht vorkommen.
+ if (!orientation) {
+ Imp_Cmd += "CHANGE VISIBLE Off;\n"; // visible Off
+ sprintf(h, "PIN '%s' PAS NONE POINT (%s);\n", Imp_SymPinName, coordpin);
+ Imp_Cmd+=h;
+ }
+ else if (orientation == "NONE") {
+ Imp_Cmd += "CHANGE VISIBLE Off;\n"; // visible Off
+ sprintf(h, "PIN '%s' PAS NONE POINT (%s);\n", Imp_SymPinName, coordpin);
+ Imp_Cmd+=h;
+ }
+ else if (orientation == "LEFT") {
+ Imp_Cmd += "CHANGE VISIBLE Pin;\n"; // Visible Pin
+ sprintf(h, "PIN '%s' PAS NONE POINT R0 (%s);\n", Imp_SymPinName, coordpin);
+ Imp_Cmd+=h;
+ }
+ else if (orientation == "RIGHT") {
+ Imp_Cmd += "CHANGE VISIBLE Pin;\n"; // Visible Pin
+ sprintf(h, "PIN '%s' PAS NONE POINT R180 (%s);\n", Imp_SymPinName, coordpin);
+ Imp_Cmd+=h;
+ }
+ else if (orientation == "TOP") {
+ Imp_Cmd += "CHANGE VISIBLE Off;\n"; // Visible Off, der Pinnmaem wir waagerecht als Text erzeugt
+ sprintf(h, "PIN '%s' PAS NONE POINT R270 (%s);\n", Imp_SymPinName, coordpin);
+ Imp_Cmd+=h;
+ sprintf(h, "Change Layer 95;\nChange Align Top Center;\nCHANGE SIZE 60;\nTEXT '%s' R0 (%.4f %.4f);\n", Imp_SymPinName, kx, ky); // 50 ist der Eagle-Offset zum Pinnamen
+ Imp_Cmd+=h;
+ }
+ else if (orientation == "BOTTOM") {
+ Imp_Cmd += "CHANGE VISIBLE Off;\n"; // Visible Off, der Pinnmaem wir waagerecht als Text erzeugt
+ sprintf(h, "PIN '%s' PAS NONE POINT R90 (%s);\n", Imp_SymPinName, coordpin);
+ Imp_Cmd+=h;
+ sprintf(h, "CHange Layer 95;\nChAnge Align Bottom Center;\nCHANGE SIZE 60;\nTEXT '%s' R0 (%.4f %.4f);\n", Imp_SymPinName, kx , ky); // 50 ist der Eagle-Offset zum Pinnamen
+ Imp_Cmd+=h;
+ }
+ else {
+ if (dlgMessageBox("Unknown orientation: " + orientation + "\nin line:" + l,"OK", "CANCEL") != 0) exit(-2790);
+ }
+ }
+
+ else if (s[1] == "SpiceOrder") {
+ if (coordname) {
+ sprintf(h, "CHANGE Size 16;\nChange Layer %d;\n", LayerSpiceOrder);
+ Imp_Cmd+=h;
+ sprintf(h, "CHANGE Align Center; # SpiceOrder\n");
+ Imp_Cmd+=h;
+ sprintf(h, "TEXt '%s %s' (%s);\n", s[1], s[2], coordpin); // SpiceOrder number 2012-06-11
+ Imp_Cmd+=h;
+ }
+ }
+ return;
+}
+
+
+void imp_dataflag(string l) { // 2012-06-14
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ string datflag;
+ sprintf(datflag, "TEXT 'DATAFLAG:%s' (%.6f %.6f);\n",
+ s[3],
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ );
+ Imp_Cmd+=datflag;
+ return;
+}
+
+
+int imp_checkexist_sym(string name) {
+ if (library) {
+ library(L) {
+ L.symbols(S) {
+ if (S.name == name) return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int imp_checkexist_dev(string name) {
+ if (library) {
+ library(L) {
+ L.devicesets(DEV) {
+ if (DEV.name == name) return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int imp_checkexist_sch(string name) {
+ string f[];
+ int cnt = fileglob(f, name);
+ if (cnt) { dlgMessageBox("Schematic exist:\n" + name, "CANCEL"); exit(-2847); }
+ return 0;
+}
+
+
+/**************************************************
+ parse schematic lines
+***************************************************/
+void imp_sheet(string l) {
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ s[2] = strupr(s[2]);
+ sprintf(h, "EDIT .s%s;\nSET WIRE_BEND 0;\nCHANGE STYLE Continuous;\n;", s[1]);
+ Imp_Cmd+=h;
+ if (Test) { // nur im Testfall wird der Zeichnungsrahmen übernommen.
+ sprintf(h, "CHangE LAYER 94;\nWIRE 10 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n# frame\n",
+ 0.0, 0.0,
+ imp_eagle_coordvalue(strtod(s[2])),
+ imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ 0.0, 0.0
+ );
+ Imp_Cmd+=h;
+ }
+ return;
+}
+
+
+void imp_wire(string l) {
+ status("WIRE"); // ein Lebenszeichen
+ if (!Imp_SetWireStyle) {
+ Imp_Cmd += "CHANGE STYLE Continuous;\n";
+ Imp_SetWireStyle++;
+ }
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ imp_add_wire(strtod(s[1]), strtod(s[2]), strtod(s[3]), strtod(s[4]));
+ return;
+}
+
+
+void imp_flag(string l) { // NET-Name des Segment, zugleich Supply-Symbol und LABEL
+ // Die FLAGs 0 und COM werden besonders behandelt,
+ // hier zeichnet LT-Spice ein Dreieck (Supply) das nach unten zeigt.
+ // Bei COM (Common/Masse) zeichnet LT-spice eine Pfeilspitze nach unten.
+ // Alle weiteren FLAGs sind NETz-Namen / LABEL
+ status("FLAG"); // ein Lebenszeichen
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ CmdNameLabel+=RememberFlag;
+ RememberFlag = "";
+
+ string coordidirection;
+ sprintf(coordidirection, "%d %d", strtol(s[1]), strtol(s[2]) );
+ int flagr = imp_getflagrotate(coordidirection, l); // Supply-Symbole sind in der Nulllage vertical ausgerichtet.
+ if (!flagr) { // kein NET-Segment mit der gleichen Koordinate gefunden,
+ // dann platziere ein Supply-Symbol
+ if (s[3] == "+V") Imp_FlagRotate = 0; // + Symbole nach oben 90
+ else if (s[3] == "-V") Imp_FlagRotate = 180; // - Symbole nach unten 270
+ string ltsupplylbr = imp_check_use("lt-supply");
+ sprintf(h, "Add '%s%s' R%.0f (%.4f %.4f);\n",
+ s[3], ltsupplylbr,
+ Imp_FlagRotate,
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0)
+ );
+ Imp_Cmd+=h;
+ return;
+ }
+
+ sprintf(h, "Ein FLAG an Netz %s\n(%.4f %.4f)\nRotation : %.1f ",
+ s[3],
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0),
+ Imp_FlagRotate);
+//if (dlgMessageBox(h, "ok", "esc") != 0) exit(-2921);
+
+ if (s[3] == "0") {
+ string ltsupplylbr = imp_check_use("lt-supply");
+ sprintf(h, "aDd '%s%s' R%.0f (%.4f %.4f);\n",
+ s[3], ltsupplylbr,
+ Imp_FlagRotate,
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0)
+ );
+ Imp_Cmd+=h;
+ }
+ else if (s[3] == "COM") {
+ string ltsupplylbr = imp_check_use("lt-supply");
+ sprintf(h, "adD '%s%s' R%.0f (%.4f %.4f);\n",
+ s[3], ltsupplylbr,
+ Imp_FlagRotate,
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0)
+ );
+ Imp_Cmd+=h;
+ }
+ // Eagle kann kein LABEL ohne NET setzen,
+
+ else {
+ // Imp_FlagRotate wird in der Funktion imp_getflagrotate() behandelt! 2012-11-05
+ // Da LTspice die Rotation der FLAGS anahand des letzen Wiresegement berstimmt,
+ // hier muss die Nullage des Symbol entsptrechend korrigiert werden.
+ // Typischerweise werden die Spannungen (Pfeile) bei plus nach oben und bei
+ // minus nach unten angelegt. Dazu muß es für jedes Symbole eine Nulagenkorrektur geben.
+ // OUT ist nach rechts zeigend angelegt.
+ if (s[3] == "+V") Imp_FlagRotate -= 180.0;
+ else if (s[3] == "-V") Imp_FlagRotate -= 180.0;
+ else if (s[3] == "OUT") Imp_FlagRotate -= 90.0;
+ string ltsupplylbr = imp_check_use("lt-supply"); // alle benötigten Supply-Symbole müssen in dieser LBR erstellt sein
+ sprintf(h, "Add '%s%s' R%.0f (%.4f %.4f);\n",
+ s[3], ltsupplylbr,
+ Imp_FlagRotate,
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0)
+ );
+ Imp_Cmd+=h;
+
+ /* 2012-11-05
+ sprintf(h, "#2582\nSET CONFIRM YES;\nNAME '%s' (%.4f %.4f) ;\n# FLAG\nSET CONFIRM OFF;\n",
+ s[3],
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ );
+ RememberFlag += h;
+ string xrefoption = "OFF";
+ sprintf(h, "Change size 70;\nCHANGE XREF %s;\nLABEL R%.1f (%.4f %.4f) (%.4f %.4f);\n",
+ xrefoption,
+ Imp_FlagRotate - 90.0, // Label sind in der Nulllage horizontal nach rechts ausgerichtet
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0)
+ );
+ RememberFlag += h;
+ */
+ }
+ return;
+}
+
+
+
+void imp_iopin(string l) {
+ /*
+ FLAG 1248 176 BI_Port
+ IOPIN 1248 176 BiDir
+ FLAG 1248 144 Input_Port
+ IOPIN 1248 144 In
+ FLAG 1248 112 Output_Port
+ IOPIN 1248 112 Out
+ */ string s[];
+ int n = strsplit(s, l, ' ');
+ // der IOPIN kommt immer nach dem FLAG, also immer die gleiche Kordinate
+ sprintf(h, "CHANGE XREF ON;\nLABEL (%.4f %.4f) (%.4f %.4f);\n",
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0)
+ );
+ CmdNameLabel += h;
+ RememberFlag = "";
+ return;
+}
+
+
+string imp_checktextalign(string align) {
+ TextAlignRotation = "R0";
+ string textalign = "Left"; // default
+ if (align == "Center") {
+ sprintf(textalign, " align Center");
+ }
+ else if(align == "Left") {
+ sprintf(textalign, " align Center Left");
+ }
+ else if(align == "Right") {
+ sprintf(textalign, " align Center Right");
+ }
+ else if(align == "Top") {
+ sprintf(textalign, " align Center Top");
+ }
+ else if(align == "Bottom") {
+ sprintf(textalign, " align Center Bottom");
+ }
+ else if(align == "VLeft") { // 90gedreht
+ sprintf(textalign, " align Center Left");
+ TextAlignRotation = "R90";
+ }
+ else if(align == "VRight") { // 90gedreht
+ sprintf(textalign, " align Center Right");
+ TextAlignRotation = "R90";
+ }
+ else if (align == "VCenter") { // 90gedreht
+ sprintf(textalign, " align Center");
+ TextAlignRotation = "R90";
+ }
+ else if(align == "VTop") { // 90gedreht
+ sprintf(textalign, " align Center Top");
+ TextAlignRotation = "R90";
+ }
+ else if(align == "VBottom") { // 90! gedreht
+ sprintf(textalign, " align Center Bottom");
+ TextAlignRotation = "R90";
+ }
+ return textalign;
+}
+
+
+string imp_checkempty(string s) {
+ if (s == "\"\"") return "";
+ return s;
+}
+
+
+void imp_symbol_sch(string l) { // place a symbol in schematic
+ /* ******* Ein Lastwiderstand zum simulieren ******
+ SYMBOL res 864 128 R0
+ SYMATTR InstName Rload1 *** Rload macht aus einem normalen Widerstand einen Lastwiderstand zum simulieren.
+ SYMATTR Value .5
+ SYMBOL eagle\\PNP_LABOR\\BST62 160 176 R0
+ ************************************************* */
+ Imp_InstanceName = ""; // Reset Instance name
+ Imp_Cmd += "CHanGe Align Left Center;\n"; // default für Textanordnung von Name/Value
+ // es kann, aber es muss nicht ein
+ // WINDOW 0 .... oder WINDOW 3 ... folgen.
+
+ Imp_CmdValueV = ""; // Reset Value
+ Imp_Winattrib[0] = ""; // Reset window attribute
+ Imp_Winattrib[1] = "";
+ Imp_Winattrib[3] = "";
+ Imp_Winattrib[38] = "";
+ Imp_Winattrib[39] = "";
+ Imp_Winattrib[40] = "";
+ Imp_Winattrib[123] = "";
+ string s[];
+ int cnt = strsplit(s, l, ' ');
+ AddPart = s[1];
+ status(AddPart); // ein Lebenszeichen
+
+ Imp_InstCoordX = imp_eagle_coordvalue(strtod(s[2]));
+ Imp_InstCoordY = imp_eagle_coordvalue(strtod(s[3])*-1.0); // in LT-Spice ist die Y-Achse auf den Kopf gestellt
+ AddPartOrientation = s[4];
+ string libpart[];
+ cnt = strsplit(libpart, s[1], '\\'); // == "eagle\\PNP_LABOR\\BST62"
+ if (cnt > 1) { // Wenn ein doppelter Backslash vor kommt, dann ist der LBR-Name angegeben.
+ AddPart = libpart[cnt-1]; // Library-name ist mit backslash vom part-name getrennt,
+ AddPartLib = ""; // es können auch mehr als ein backslash vorkommen,
+ for (int n = 0; n < cnt-1; n++) { // dann ist der Partname der letzte Teilstring.
+ if (libpart[n]) AddPartLib = libpart[n]; // 2014-04-03 setze den Pfad auf den vorletzen Teilstring
+ }
+ }
+ else { // dann ist es vermutlich ein Simulations-Symbol
+ AddPart = libpart[cnt-1];
+ AddPartLib = "";
+ }
+ return;
+}
+
+
+void imp_window_sch(string l, int cnt) {
+ /* Attribute Window *
+ InstName 0 -
+ Type 1 -
+ SpiceModel 38 +SYMATTR
+ Value 3 -
+ Value2 123 -
+ SpiceLine 39 -
+ SpiceLine2 40 -
+
+ Rotated symbols get windows for parameters relative to the
+ anchor point of the symbol
+ */
+ string h = "";
+ string s[];
+ int n = strsplit(s, l, ' ');
+ int winattrib = strtod(s[1]);
+
+ switch(winattrib) {
+ case 0 : Imp_Winattrib[0] = "0";
+ Imp_InstNameSmashX = imp_eagle_coordvalue(strtod(s[2])); // InstName 0 -
+ Imp_InstNameSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ TextAlignName = s[4];
+ Imp_InstNameOffset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ case 1 : Imp_Winattrib[1] = "1"; // Type
+ dlgMessageBox("WINDOW 1 : Type found", "CANCEL");
+ exit(-3129);
+ break;
+
+ case 3 : Imp_Winattrib[3] = "3";
+ Imp_InstValueSmashX = imp_eagle_coordvalue(strtod(s[2])); // Value 3 -
+ Imp_InstValueSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ TextAlignValue = s[4];
+ Imp_InstValueOffset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ case 38 : Imp_Winattrib[38] = "38";
+ Imp_SpiceModelSmashX = imp_eagle_coordvalue(strtod(s[2])); // SpiceModel 38 +SYMATTR
+ Imp_SpiceModelSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ break;
+
+ case 39 : Imp_Winattrib[39] = "39"; // WINDOW 39 273 154 Center 2
+ Imp_SpiceLineSmashX = imp_eagle_coordvalue(strtod(s[2])); // SpiceLine 39 -
+ Imp_SpiceLineSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ TextAlignSpiceLine = s[4];
+ Imp_SpiceLineSymOffset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ case 40 : Imp_Winattrib[40] = "40";
+ Imp_SpiceLine2SmashX = imp_eagle_coordvalue(strtod(s[2])); // SpiceLine2 40 -
+ Imp_SpiceLine2SmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ TextAlignSpiceLine2 = s[4];
+ Imp_SpiceLine2SymOffset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ case 123 : Imp_Winattrib[123] = "123"; // WINDOW 123 24 146 Left 0
+ Imp_InstValue2SmashX = imp_eagle_coordvalue(strtod(s[2])); // Value2 123 -
+ Imp_InstValue2SmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0);
+ TextAlignValue2 = s[4];
+ Imp_InstValue2Offset = imp_eagle_coordvalue(strtod(s[5]));
+ break;
+
+ default : dlgMessageBox("!Unknown window attribute:\n"+ l, "OK");
+ }
+
+
+ //
+ if (s[5] != "0") {
+ sprintf(h, "# %s:\n\# %s in Line %d:%s\n", ImpSpiceSchematicAsc, s[5] , cnt+1, l );
+ Imp_Cmd+=h;
+ }
+ return;
+}
+
+string imp_getTextOrientation( string instancename, string textholder, string textalign, string addpartorientation, real instcoordX, real instcoordY, real insttextsmashX, real insttextsmashY ) {
+ string os;
+
+ real nameposx, nameposy;
+ if (addpartorientation == "R0") {
+ nameposx = instcoordX + insttextsmashX;
+ nameposy = instcoordY + insttextsmashY;
+ }
+ else if (addpartorientation == "R90") {
+ nameposx = instcoordX + insttextsmashY; // wegen der 90Grad
+ nameposy = instcoordY - insttextsmashX; // muß der für den Offset X und Y getauscht werden
+ }
+ else if (addpartorientation == "R180") {
+ nameposx = instcoordX - insttextsmashX;
+ nameposy = instcoordY - insttextsmashY;
+ }
+ else if (addpartorientation == "R270") {
+ nameposx = instcoordX - insttextsmashY; // wegen der 270 Grad-Drehung muß der Offset X und Y getauscht werden
+ nameposy = instcoordY + insttextsmashX;
+ }
+ // mirrored
+ else if (addpartorientation == "M0") {
+ nameposx = instcoordX - insttextsmashX;
+ nameposy = instcoordY + insttextsmashY;
+ }
+ else if (addpartorientation == "M90") {
+ nameposx = instcoordX - insttextsmashY; // wegen der 90Grad
+ nameposy = instcoordY - insttextsmashX; // muß der für den Offset X und Y getauscht werden
+ }
+ else if (addpartorientation == "M180") {
+ nameposx = instcoordX + insttextsmashX;
+ nameposy = instcoordY - insttextsmashY;
+ }
+ else if (addpartorientation == "M270") {
+ nameposx = instcoordX + insttextsmashY; // wegen der 270 Grad
+ nameposy = instcoordY + insttextsmashX; // muß der für den Offset X und Y getauscht werden
+ }
+ sprintf(h, ";\nMOVe %s>%s (%.4f %.4f); #3229\n",
+ strupr(instancename), textholder, nameposx, nameposy
+ );
+ os += h;
+
+ string alignorientation;
+ // text align kann bisher nur mit Hilfe der Koordinaten erfolgen
+ if (textalign == "Center") {
+ sprintf(alignorientation, "Center");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Center\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Center\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Center\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Center\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Center\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Center\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Center\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Center\n
+ }
+ os += h;
+ }
+
+ else if(textalign == "Left") {
+ sprintf(alignorientation, "Bottom Left"); // 2012-07-09 Center Left
+ if (addpartorientation == "R0") {
+ sprintf(h, "rOTATe =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Left\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Left\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Left\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Left\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Left\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =MR270 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Left\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "roTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Left\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Left\n
+ }
+ os += h;
+ }
+
+ else if(textalign == "Right") {
+ sprintf(alignorientation, "Center Right");
+ if (addpartorientation == "R0") {
+ sprintf(h, "RoTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Right\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Right\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Right\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Right\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Right\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =MR270 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Right\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "RotATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Right\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Right\n
+ }
+ os += h;
+ }
+
+ else if(textalign == "Top") {
+ sprintf(alignorientation, "Center Top");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROtATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Top\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Top\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Top\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Top\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROtaTE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Top\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Top\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Top\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Top\n
+ }
+ os += h;
+ }
+
+ else if(textalign == "Bottom") {
+ sprintf(alignorientation, "Center Bottom");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTaTE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Bottom\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Bottom\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Bottom\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Bottom\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTatE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Bottom\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Bottom\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Bottom\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Bottom\n
+ }
+ os += h;
+
+ }
+
+ else if(textalign == "VLeft") { // 90gedreht
+ sprintf(alignorientation, "Center Left");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VLeft\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTAtE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VLeft\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VLeft\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VLeft\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VLeft\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VLeft\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VLeft\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTAte =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VLeft\n
+ }
+ os += h;
+ }
+
+ else if(textalign == "VRight") { // 90gedreht
+ sprintf(alignorientation, "Center Right");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VRight\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "rOtATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VRight\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VRight\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VRight\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =MR90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VRight\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VRight\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VRight\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VRight\n
+ }
+ os += h;
+ }
+
+ else if (textalign == "VCenter") { // 90gedreht
+ sprintf(alignorientation, "Center");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VCenter\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VCenter\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VCenter\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VCenter\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VCenter\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VCenter\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VCenter\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VCenter\n
+ }
+ os += h;
+ }
+
+ else if(textalign == "VTop") { // 90gedreht
+ sprintf(alignorientation, "Center Top");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VTop\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VTop\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VTop\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VTop\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =MR90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VTop\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VTop\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VTop\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VTop\n
+ }
+ os += h;
+ }
+ else if(textalign == "VBottom") { // 90 gedreht
+ sprintf(alignorientation, "Center Bottom");
+ if (addpartorientation == "R0") {
+ sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VBottom\n
+ }
+ else if (addpartorientation == "R90") {
+ sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VBottom\n
+ }
+ else if (addpartorientation == "R180") {
+ sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VBottom\n
+ }
+ else if (addpartorientation == "R270") {
+ sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VBottom\n
+ }
+ if (addpartorientation == "M0") {
+ sprintf(h, "ROTATE =MR90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VBottom\n
+ }
+ else if (addpartorientation == "M90") {
+ sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VBottom\n
+ }
+ else if (addpartorientation == "M180") {
+ sprintf(h, "ROTATE =MR270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VBottom\n
+ }
+ else if (addpartorientation == "M270") {
+ sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VBottom\n
+ }
+ os += h;
+ }
+
+ sprintf(h, "Change Align %s (%.4f %.4f);\n", alignorientation, nameposx, nameposy) ; // # Name\n
+ os += h;
+ return os;
+}
+
+
+void imp_symattr_sch(string l, int cnt) {
+ /* Attribute Window *
+ InstName 0 -
+ Type 1 -
+ SpiceModel 38 +SYMATTR
+ Value 3 -
+ Value2 123 -
+ SpiceLine 39 -
+ SpiceLine2 40 -
+
+ Rotated symbols get windows for parameters relative to the
+ anchor point of the symbol
+ */
+ string s[];
+ int sn = strsplit(s, l, ' ');
+ string addpartorient;
+
+ if (s[1] == "InstName") { // Imp_Winattrib[0]
+ Imp_InstanceName = s[2];
+ int rload = strstr(Imp_InstanceName, "Rload");
+ if (!rload) { // hier nur ein Simulations-Symbol laden
+ AddPart += Imp_RloadExtention; // "_RLOAD";
+ //AddPartLib = SpiceSimulationLbr; /**** ACHTUNG: die LBR darf nicht in der USE-Liste aufgeführt sein! ****/
+ if (Test) if (dlgMessageBox("Ein Simulationswiderstand wird geladen.\n" + l + "\n" + Imp_InstanceName + ":" + SpiceSimulationLbr, "ok", "esc") != 0) exit(-3540);
+ }
+ else {
+ int Vsym = strstr(Imp_InstanceName, "V");
+ /* Hier gibt es ein Missverständnis wegen dem Prefix V
+ eine BATTRY wird in LT SPice auch mit V bezeichnet! */
+ // *** es wird nicht immer die LBR angegeben siehe LTC4000 *** if (!AddPartLib) AddPartLib = "sym"; // set library on USE-list
+ }
+ /* *** Im ADD-Menu muss das Flag SMD aktiv sein, sonst findet das Script die Devices nicht! *** */
+ AddPartLib = imp_check_use(AddPartLib);
+ if(AddPartOrientation == "R0") addpartorient = "R0";
+ else if(AddPartOrientation == "R90") addpartorient = "R270";
+ else if(AddPartOrientation == "R180") addpartorient = "R180";
+ else if(AddPartOrientation == "R270") addpartorient = "R90";
+ else if(AddPartOrientation == "M0") addpartorient = "MR0";
+ else if(AddPartOrientation == "M90" ) addpartorient = "MR270";
+ else if(AddPartOrientation == "M180") addpartorient = "MR180";
+ else if(AddPartOrientation == "M270" ) addpartorient = "MR90";
+
+ sprintf(h, "AdD '%s%s' '%s' %s (%.4f %.4f) ;\n", // wegen der Package-Varianten ist es evtl. besser wenn man mit Joker * sucht?!
+ AddPart, AddPartLib, // Leider nein, da es CAP & CAP[METER], RES & RES[2], IND & IND[2] und
+ strupr(Imp_InstanceName), // sontige gleichlautende Symbole gibt!
+ addpartorient,
+ Imp_InstCoordX,
+ Imp_InstCoordY
+ );
+ Imp_Cmd += h;
+
+ sprintf(h, "SMASH %s;\n", strupr(Imp_InstanceName)); // Smash kann jetzt schon mit >Name erfolgen.
+ Imp_Cmd += h;
+ if (Imp_CmdPartValue) {
+ sprintf(h, "VALUE '%s' '%s'; #3586\n", strupr(Imp_InstanceName), Imp_CmdPartValue);
+ Imp_Cmd += h;
+ Imp_CmdPartValue = ""; // wieder leeren, damit der Value nicht mehrfach zugewiesen wird.
+ }
+
+ if (Imp_Winattrib[0]) { // WINDOW 0 == InstName
+ Imp_Cmd += imp_getTextOrientation( Imp_InstanceName, "NAME", TextAlignName, AddPartOrientation, Imp_InstCoordX, Imp_InstCoordY, Imp_InstNameSmashX, Imp_InstNameSmashY);
+
+ /**** LTSpice weist den InstancNamen mal vor, mal nach dem Value zu! ****/
+ if (Imp_CmdPartValue) {
+ sprintf(h, "VALUE '%s' '%s'; #3596\n", strupr(Imp_InstanceName), Imp_CmdPartValue);
+ Imp_Cmd += h;
+ Imp_CmdPartValue = "";
+ }
+ if (Imp_CmdValueV) { // Dadurch ergeben sich Probleme bei der Scriptausführung was
+ // die Zuweisung der Attribute (wie VALUE) betrifft.
+ // Trenne die Kommandos bei dem Zeichen '>' und füge die entsprechenden
+ // Instance-namen ein. ***###***
+ string vs[];
+ int vn = strsplit(vs, Imp_CmdValueV, '>');
+ Imp_CmdValueV = vs[0] + strupr(Imp_InstanceName) +">" + vs[1]; // Füge für das '>' den InstanceName ein!
+ int n = 2;
+ while (vs[n]) {
+ Imp_CmdValueV += strupr(Imp_InstanceName) + ">" + vs[n]; // Füge für das '>' den InstanceName plus '>' ein!
+ n++;
+ }
+ Imp_Cmd += Imp_CmdValueV; // In LTspice kann das Attribute Value vor der Zuweisung des Namen kommen,
+ // dann gibt es diverse Probleme bei der Zuordnung der Attribute über Koordinaten!
+ // Deshalb erst den Namen zuweisen, dann alle anderen Attribute!
+ Imp_CmdValueV = ""; // Reset Value-Attribute
+ }
+
+ string v[];
+ if (Imp_CmdValue2) { // [123] LTspice weist auch ein Attribute zu, bevor der Instancename bekannt ist!
+ strsplit(v, Imp_CmdValue2, '>');
+ string displayonoff = "OFF";
+ if (Imp_Winattrib[123]) displayonoff = "Value"; // 2012-12-17
+ sprintf(h, "ChAngE Display %s;\nATTRIBUTE '%s' %s%s>%s%s>%s\n", displayonoff, strupr(Imp_InstanceName), v[0], strupr(Imp_InstanceName), v[1], strupr(Imp_InstanceName), v[2]); // füge den jetzt bekannten Instanc Name ein
+ Imp_Cmd += h;
+ Imp_CmdValue2 = ""; // für das nächste Symbol/Instance wieder leeren!
+ }
+
+ if (Imp_MemSpiceline) { // [39] 2012-12-17
+ strsplit(v, Imp_MemSpiceline, '>');
+ string displayonoff = "OFF";
+ if (Imp_Winattrib[38]) displayonoff = "Value";
+ sprintf(h, "ChAngE Display %s;\nATTRIBUTE %s SPICELINE '%s';\nMOvE %s>SPICELINE %s;\nCHange Align %s %s;\n", // 2012-12-17 Display off
+ displayonoff,
+ strupr(Imp_InstanceName),
+ v[0],
+ strupr(Imp_InstanceName),
+ v[1],
+ v[2],
+ v[1]
+ ); // füge den jetzt bekannten Instance Namen ein
+ Imp_Cmd += h;
+ Imp_Cmd += "ChAngE Display Off; #3642\n"; // 2012-10-11
+ Imp_MemSpiceline = "";
+ }
+ if (Imp_MemSpiceline2) {
+ strsplit(v, Imp_MemSpiceline2, '>');
+ sprintf(h, "ChaNgE Display Value;\nATTRIBUTE %s SPICELINE2 '%s';\nMOVE %s>SPICELINE2 %s;\nCHange Align %s %s;\n",
+ strupr(Imp_InstanceName),
+ v[0],
+ strupr(Imp_InstanceName),
+ v[1],
+ v[2],
+ v[1]
+ ); // füge den jetzt bekannten Instance Namen ein
+ Imp_Cmd += h;
+ Imp_Cmd += "ChAngE Display Off; #3656\n"; // 2012-10-11
+ Imp_MemSpiceline2 = "";
+ }
+ return;
+ }
+ }
+
+ // SYMATTR Value 100%
+ else if (s[1] == "Value") {
+ if (Imp_InstanceName) { // LTSpice weist den Instance-Namen mal vor mal nach dem Value zu!
+ sprintf(h, "VALUE '%s' '%s';\n", strupr(Imp_InstanceName), imp_checkempty(imp_secondstr(l, s[1])));
+ Imp_Cmd += h;
+ }
+ else {
+ sprintf(Imp_CmdPartValue, "%s", imp_secondstr(l, s[1]));
+ }
+ if (Imp_Winattrib[3]) { // WINDOW 3 == Value
+ Imp_CmdValueV += imp_getTextOrientation( Imp_InstanceName, "VALUE", TextAlignValue, AddPartOrientation, Imp_InstCoordX, Imp_InstCoordY, Imp_InstValueSmashX, Imp_InstValueSmashY);
+ if (Imp_InstanceName) {
+ Imp_Cmd += Imp_CmdValueV;
+ Imp_CmdValueV = "";
+ }
+ }
+ return;
+ }
+
+ // SYMATTR Value2 X2
+ else if (s[1] == "Value2") { // [123] 2012-12-17
+ string displayonoff = "OFF";
+ if (Imp_Winattrib[123]) displayonoff = "Value";
+ if (Imp_InstanceName) {
+ sprintf(h, "Change Display %s;\nATTRIBUTE '%s' 'VALUE2' '%s';\n#3557\n", displayonoff, strupr(Imp_InstanceName), imp_secondstr(l, s[1]));
+ Imp_Cmd += h;
+ }
+ else {
+ // da noch kein InstanceName definiert ist, das Attribute zwischenmerken!
+ sprintf(Imp_CmdValue2, " 'VALUE2' '%s';\n#3562\n", imp_secondstr(l, s[1]));
+ }
+
+ Imp_CmdValue2 += imp_getTextOrientation( Imp_InstanceName, strupr(s[1]), TextAlignValue2, AddPartOrientation, Imp_InstCoordX, Imp_InstCoordY, Imp_InstValue2SmashX, Imp_InstValue2SmashY);
+ /********************************************/
+ if (Imp_InstanceName) {
+ Imp_Cmd += Imp_CmdValue2; // Ist der Name noch nicht zugewiesen, dann erfolgt die Zuweisung des Value
+ Imp_CmdValue2 = ""; // mit dem Namen. Die Befehlssequenz wird entsprechend nachbearbeitet. ******
+ }
+ return;
+ }
+
+ else if(s[1] == "SpiceLine") { // [39]
+ if (Imp_Winattrib[39]) { // wenn es eine Koordinate für das Attribute gibt, dann anzeigen, sonst nur ein Attribute definieren
+ real spicelineposx, spicelineposy;
+ if (AddPartOrientation == "R0") {
+ spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashX;
+ spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashY;
+ }
+ else if (AddPartOrientation == "R90") {
+ spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashY; // wegen der der 90Drehung muß X und Y getauscht werden
+ spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashX;
+ }
+ else if (AddPartOrientation == "R180") {
+ spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashX;
+ spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashY;
+ }
+ else if (AddPartOrientation == "R270") { // Verkehrtes Vorzeichen der Y-Achse
+ spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashY; // wegen der 270 Grad-Drehung muß der Offset X und Y getauscht werden
+ spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashX;
+ }
+ else if (AddPartOrientation == "M0") {
+ spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashX;
+ spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashY;
+ }
+ else if (AddPartOrientation == "M90") {
+ spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashY;
+ spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashX;
+ }
+ else if (AddPartOrientation == "M180") {
+ spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashX;
+ spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashY;
+ }
+ else if (AddPartOrientation == "M270") {
+ spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashY;
+ spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashX;
+ }
+
+ // den Wert des Attribute mit Textplatzhalter anzeigen
+ sprintf(Imp_MemSpiceline, "%s> (%.4f %.4f)>%s",
+ imp_secondstr(l, s[1]), // der Value für Spiceline kannen mehrere Wörter durch Space getrennt enthalten
+ spicelineposx, spicelineposy,
+ TextAlignSpiceLine
+ );
+ }
+ else {
+ sprintf(h, "ATTRIBUTE %s %s '%s';\n", strupr(Imp_InstanceName), s[1], imp_secondstr(l, s[1]));
+ Imp_Cmd += h;
+ }
+ return;
+ }
+
+ else if(s[1] == "SpiceLine2") { // [40]
+ if (Imp_Winattrib[40]) { // wenn es eine Koordinate für das Atrribute gibt, dann anzeigen, sonst nur ein Attribute definieren
+ real spiceline2posx, spiceline2posy;
+ if (AddPartOrientation == "R0") {
+ spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashX;
+ spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashY;
+ }
+ else if (AddPartOrientation == "R90") {
+ spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashY; // wegen der der 90Drehung muß X und Y getauscht werden
+ spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashX;
+ }
+ else if (AddPartOrientation == "R180") {
+ spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashX;
+ spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashY;
+ }
+ else if (AddPartOrientation == "R270") { // Verkehrtes Vorzeichen der Y-Achse
+ spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashY; // wegen der 270 Grad-Drehung muß der Offset X und Y getauscht werden
+ spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashX;
+ }
+ else if (AddPartOrientation == "M0") {
+ spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashX;
+ spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashY;
+ }
+ else if (AddPartOrientation == "M90") {
+ spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashY;
+ spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashX;
+ }
+ else if (AddPartOrientation == "M180") {
+ spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashX;
+ spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashY;
+ }
+ else if (AddPartOrientation == "M270") {
+ spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashY;
+ spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashX;
+ }
+
+ // den Wert des Attribute mit Textplatzhalter anzeigen
+ sprintf(Imp_MemSpiceline2, "%s> (%.4f %.4f)>%s",
+ imp_secondstr(l, s[1]), // Der Value von Spiceline kann mehrere Wörter durch Space getrennt enthalten
+ spiceline2posx, spiceline2posy,
+ TextAlignSpiceLine2
+ );
+ }
+ else {
+ sprintf(h, "CHANGE Display Off;\nATTRIBUTE %s %s '%s';\n", strupr(Imp_InstanceName), s[1], imp_secondstr(l, s[1]));
+ Imp_Cmd += h;
+ }
+ return;
+ }
+
+ // SYMATTR Description Capacitor
+ else if(s[1] == "Description") { // kein WINDOW für SYMATTR Description - deshalb die Description im Schaltplan als Attribute anlegen
+ if (!Imp_InstanceName) {
+ sprintf(h, "CHANGE Display OFF;\nATTRIBUTE (%.4f %.4f) 'SPICE_DESCRIPTION' '%s';\n", Imp_InstCoordX, Imp_InstCoordY, s[2]); // 2012-12-17
+ }
+ else sprintf(h, "CHANGE Display OFF;\nATTRIBUTE '%s' 'SPICE_DESCRIPTION' '%s';\n", strupr(Imp_InstanceName), s[2]);
+ Imp_Cmd += h;
+ return;
+ }
+
+ // SYMATTR Type cap
+ else if(s[1] == "Type") {
+ if (!Imp_InstanceName) {
+ sprintf(h, "ATTRIBUTE (%.4f %.4f) 'SpiceType' '%s';\n", Imp_InstCoordX, Imp_InstCoordY, s[2]);
+ }
+ else sprintf(h, "ATTRIBUTE '%s' 'SpiceType' '%s';\n", strupr(Imp_InstanceName), s[2]);
+ Imp_Cmd += h;
+ return;
+ }
+ return;
+}
+
+
+void imp_bustap(string l) {
+ if (!Imp_WireChecked) {
+ imp_get_net_segment(); // nachdem alle Wire gesammelt wurden, müssen die Segmente ermittelt werden
+ }
+ // BUSTAP 864 208 880 208
+ string s[];
+ int n = strsplit(s, l, ' ');
+
+ imp_check_bus(strtod(s[1]), strtod(s[2])); // Die erste Koordinate ist der Anschluss an den BUS,
+ // die zweite Koordinate an das Netz.
+
+ sprintf(h, "NET (%.4f %.4f)(%.4f %.4f);\n", // zeichne das fehlende NET-Stück.
+ imp_eagle_coordvalue(strtod(s[1])),
+ imp_eagle_coordvalue(strtod(s[2])*-1.0),
+ imp_eagle_coordvalue(strtod(s[3])),
+ imp_eagle_coordvalue(strtod(s[4])*-1.0)
+ );
+ Imp_Cmd += h;
+ return;
+}
+
+
+void call_system(string exportfile) { // DOS comand execute
+ string syscommand;
+ // Das executable und der Dateiname müssen in " " eingeschlossen werden, wegen Spaces im Pfad-Dateinamen!
+ sprintf(syscommand, "\"%s\" \"%s\"", lash2backslash(LTSpiceExecute), lash2backslash(exportfile));
+ system(syscommand); // externes Programm starten
+ return;
+}
+
+
+/****** IMPORT SETUP MENU ******/
+void imp_setupmenu(void) {
+ int editspicesym = 0;
+ int editspicesch = 0;
+ int fImport_All_Symbols = strtol(Import_All_Symbols);
+ int fExternalSymbol = strtol(ExternalSymbol);
+
+ dlgDialog("LT-Spice import") {
+ dlgHBoxLayout dlgSpacing(600);
+
+ if (library) { /*** SYMBOL ***/
+ //library(L) NewLbrName = L.name;
+ if (!SpiceSymbol) {
+ SpiceSymbol = LTSpiceLibDir + "*.asy";
+ }
+ FileSpiceSym[0] = SpiceSymbol;
+
+ dlgGridLayout {
+ dlgCell( 1, 1) dlgLabel("Directory of Eagle connect scrips");
+ dlgCell( 1, 2) dlgStringEdit(Imp_ConnectScriptDir);
+
+ dlgCell( 2, 1) dlgLabel("LTspice symbol:");
+ dlgCell( 2, 2) dlgStringEdit(SpiceSymbol);
+ dlgCell( 2, 3) dlgPushButton("&Browse") {
+ string mFileSpiceSym = backslash2lash(dlgFileOpen("Select a LTspice symbol", SpiceSymbol, "*.asy"));
+ if (mFileSpiceSym) {
+ EagleSpiceLbrDir = filedir(mFileSpiceSym);
+ SpiceSymbol = mFileSpiceSym;
+ FileSpiceSym[0] = mFileSpiceSym;
+ CntFileSpiceSym = 1;
+ editspicesym = 1;
+ string f[];
+ int cntf = strsplit(f, FileSpiceSym[0], '/');
+ if (cntf > 2) LbrName = f[cntf-2] + ".lbr"; // Bibliotheksname = Verzeichnisname
+ else LbrName = filesetext(FileSpiceSym[0], ".lbr");
+ if (Import_All_Symbols) NewLbrName = filedir(NewLbrName) + imp_dirname(SpiceSymbol) + ".lbr";
+ else NewLbrName = ""; // filedir(NewLbrName) + filesetext(filename(SpiceSymbol), ".lbr");
+ }
+ }
+
+ dlgCell( 3, 1) ;
+ dlgCell( 3, 2) dlgCheckBox("Import &all symbols from directory", fImport_All_Symbols) {
+ if (fImport_All_Symbols) {
+ NewLbrName = filedir(NewLbrName) + imp_dirname(SpiceSymbol) + ".lbr";
+ Import_All_Symbols = "1";
+ }
+ else {
+ NewLbrName = ""; // filedir(NewLbrName) + filesetext(filename(SpiceSymbol), ".lbr");
+ Import_All_Symbols = "";
+ }
+ }
+ dlgCell( 3, 3) ;
+
+ dlgCell( 4, 1) ;
+ dlgCell( 4, 2) dlgCheckBox("Import as simulation &part ( generate ATTRIBUTE _EXTERNAL_ )", fExternalSymbol) imp_helpSimulationSymbols();
+ dlgCell( 4, 3) ;
+
+ dlgCell( 7, 1) dlgLabel("&New EAGLE library name ");
+ dlgCell( 7, 2) dlgStringEdit(NewLbrName);
+ dlgCell( 7, 3) dlgPushButton("Br&owse") {
+ string mNewLbrName = backslash2lash(dlgFileSave("Select a Spice symbol", NewLbrName, "*.lbr"));
+ if (mNewLbrName) NewLbrName = mNewLbrName;
+ };
+ dlgCell( 8, 2) dlgLabel("(let this line empty to import symbol at current lbr.)");
+ }
+ }
+
+ else if (schematic) { /*** SHEMATIC ***/
+ string schname;
+ schematic(SCH) schname = SCH.name;
+ dlgGridLayout {
+ dlgCell( 0, 1) dlgLabel(" ");
+ dlgCell( 0, 2) dlgSpacing(300);
+ dlgCell( 0, 3) dlgLabel(" ");
+
+ /*********************************************************************************
+ Für LT-Spice gibt es Standard-Symbole (default) die nicht als Datei angelegt sind,
+ für diese Symbole muß es in Eagle eine entsprechende Bibliothek geben, die exakt
+ dem Aussehen in LT-Spice entsprechen.
+ Hier wird der Pfad und Dateiname dieser Bibliothek eingetragen.
+ **********************************************************************************/
+ dlgCell( 1 , 1 ) dlgLabel("Spice default symbols");
+ dlgCell( 1 , 2 ) dlgLabel(SpiceDefaultSymLbr, 1); // = lt-spice-simulation.lbr
+ //dlgCell( 1 , 3 ) dlgPushButton("B&rowse") {
+ // string mSpiceDefaultSymLbr = backslash2lash(dlgFileOpen("Select a spice default symbol library", SpiceDefaultSymLbr));
+ // if (mSpiceDefaultSymLbr) SpiceDefaultSymLbr = mSpiceDefaultSymLbr;
+ //}
+
+ // Die Symbol-LBR für Generatorn, Messgeräte, Lastwiderstände etc.
+ /*****************************************************************************
+ Symbole die für die Simulation von Bedeutung sind, müssen in einer Bibliothek
+ angelegt werden, und mit dem ATTRIBUTE "_EXTERNAL_" versehen sein.
+ Hier wird der Pfad und Dateiname dieser Bibliothek eingetragen.
+ ******************************************************************************/
+ dlgCell( 2 , 1 ) dlgLabel("Spice simulation library");
+ dlgCell( 2 , 2 ) dlgLabel(SpiceSimulationLbr, 1);
+ //dlgCell( 2 , 3 ) dlgPushButton("&Browse") {
+ // string mSpiceSimulationLbr = backslash2lash(dlgFileOpen("Select Simuation-Symbol-LBR", SpiceSimulationLbr , "*.lbr"));
+ // if (mSpiceSimulationLbr) {
+ // SpiceSimulationLbr = mSpiceSimulationLbr;
+ // }
+ //}
+
+ dlgCell( 4 , 1 ) dlgLabel("");
+ dlgCell( 4 , 2 ) dlgLabel("");
+ dlgCell( 4 , 3 ) dlgLabel("");
+
+ dlgCell( 6 , 1 ) dlgLabel("Spice schematic");
+ dlgCell( 6 , 2 ) dlgStringEdit(ImpSpiceSchematicAsc);
+ dlgCell( 6 , 3 ) dlgPushButton("&Browse") {
+ string mImpSpiceSchematicAsc = backslash2lash(dlgFileOpen("Select a spice schematic", ImpSpiceSchematicAsc , "*.asc"));
+ if (mImpSpiceSchematicAsc) {
+ ImpSpiceSchematicAsc = mImpSpiceSchematicAsc;
+ SchName = filedir(schname) + filesetext(filename(mImpSpiceSchematicAsc), ".sch");
+ string f[];
+ int exist = fileglob(f, SchName);
+ if (exist) {
+ dlgMessageBox("!Schematic '" + SchName + "' exist.", "CANCEL"); exit(-3960);
+ }
+ }
+ }
+
+
+ dlgCell( 7 , 1 ) dlgLabel("Eagle schematic ");
+ dlgCell( 7 , 2 ) dlgStringEdit(SchName);
+ dlgCell( 7 , 3 ) dlgPushButton("&Browse") {
+ string mSchName = backslash2lash(dlgFileOpen("Select eagle schematic", SpiceSimulationLbr , "*.sch"));
+ if (mSchName) {
+ SchName = mSchName;
+ }
+ }
+ }
+ }
+
+ else {
+ dlgMessageBox("!Start this ULP in a schematic or library.", "OK");
+ exit(-4);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") {
+ if (fileext(ImpSpiceSchematicAsc) == ".asc" || fileext(FileSpiceSym[0]) == ".asy") {
+ if (schematic) {
+ if (!SchName) SchName = filename(filesetext(ImpSpiceSchematicAsc, ".sch"));
+ ScriptFile = filesetext(SchName, Imp_ScriptExt);
+ dlgAccept();
+ }
+ else if (library) {
+ CntFileSpiceSym = fileglob(FileSpiceSym, SpiceSymbol);
+ dlgAccept();
+ }
+ }
+ else {
+ if (schematic) dlgMessageBox("Select a LTC schematic file (*.asc) first!", "OK");
+ else if (library) {
+ if (fileext(FileSpiceSym[0]) != ".asy" ) dlgMessageBox("Select a LTC symbol file (*.asy) first!", "OK");
+ }
+ }
+ }
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-5); }
+ dlgStretch(1);
+ dlgLabel(ULP_Version);
+ dlgPushButton("&Save config") saveconfig();
+ }
+ };
+ return;
+}
+
+/***** EXPORT menu *****/
+void ex_setupmenu(void) {
+ string schexportname;
+ dlgDialog("Eagle-LTspice Setup") {
+ dlgHBoxLayout dlgSpacing(200);
+ dlgLabel("spice.asy = "+ LTSpiceLibDir);
+ dlgLabel("eagle.asy = "+ ExpEagleSpiceSymDir);
+
+ if (schematic) { /*** SCHEMATIC ***/ //2012-10-10 alf
+ schematic(SCH) schexportname = filesetext(SCH.name, ".asc");
+ dlgLabel("SCH = "+ schexportname);
+ }
+ else if (library) { /*** LIBRARY ***/
+ dlgGridLayout {
+ ExOnceLib = 1;
+ if (deviceset) {
+ dlgCell( 5 , 2 ) dlgGroup("Export") {
+ dlgRadioButton("Export &all devices", ExOnceLib);
+ dlgRadioButton("EXPORT &only this deviceset to LTspice symbol (*.asy)", ExOnceLib);
+ }
+ }
+ else {
+ dlgCell( 5 , 2 ) dlgLabel("EXPORT all devicesets to LTspice symbols (*.asy)");
+ }
+ }
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-CANCEL") { dlgReject(); exit(-2); }
+ dlgStretch(1);
+ dlgLabel(ULP_Version);
+ }
+ };
+ saveconfig();
+ return;
+}
+
+
+void dosfilecopy( string source, string target, string option) {
+ string DOScommand;
+ sprintf(DOScommand, "XCOPY \"%s\" \"%s\" %s", lash2backslash(source), lash2backslash(target), option);
+ /*
+ dlgDialog("DOS command") {
+ dlgHBoxLayout dlgSpacing(800);
+ dlgStringEdit(DOScommand);
+ dlgPushButton("ok") dlgAccept();
+ dlgPushButton("esc") { dlgReject(); exit(-4056); }
+ };
+ */
+ system(DOScommand);
+ return;
+}
+
+void autosetupinfo(string dlgheader, string cntscrsetup) {
+ dlgDialog(dlgheader) {
+ dlgGridLayout {
+ dlgCell( 0, 1) dlgLabel("Program:");
+ dlgCell( 0, 2) dlgLabel(EAGLE_SIGNATURE);
+ dlgCell( 1, 1) dlgLabel("System:");
+ dlgCell( 1, 2) dlgLabel(OS_SIGNATURE);
+ dlgCell( 2, 1) dlgLabel("Eagle Path:");
+ dlgCell( 2, 2) dlgLabel(EAGLE_PATH);
+ dlgCell( 3, 1) dlgLabel("Eagle Dir:");
+ dlgCell( 3, 2) dlgLabel(EAGLE_DIR);
+ dlgCell( 4, 1) dlgLabel("User Dir:");
+ dlgCell( 4, 2) dlgLabel(EAGLE_HOME);
+ dlgCell( 5, 1) dlgLabel("");
+ dlgCell( 5, 2) dlgLabel("");
+ dlgCell( 6, 1) dlgLabel("LTSpiceExecute");
+ dlgCell( 6, 2) dlgLabel(LTSpiceExecute);
+ dlgCell( 7, 1) dlgLabel("LTSpiceLibDir");
+ dlgCell( 7, 2) dlgLabel(LTSpiceLibDir);
+ dlgCell( 8, 1) dlgLabel("ExpEagleSpiceSymDir");
+ dlgCell( 8, 2) dlgLabel(ExpEagleSpiceSymDir);
+ dlgCell( 9, 1) dlgLabel("");
+ dlgCell( 9, 2) dlgLabel("");
+ dlgCell( 10, 1) dlgLabel("EagleExecute");
+ dlgCell( 10, 2) dlgLabel(EagleExecute);
+ dlgCell( 11, 1) dlgLabel("Imp_ConnectScriptDir");
+ dlgCell( 11, 2) dlgLabel(Imp_ConnectScriptDir);
+ dlgCell( 12, 2) dlgLabel(cntscrsetup);
+ dlgCell( 13, 1) dlgLabel("SpiceSimulationLbr");
+ dlgCell( 13, 2) dlgLabel(SpiceSimulationLbr);
+ dlgCell( 14, 1) dlgLabel("SpiceDefaultSymLbr");
+ dlgCell( 14, 2) dlgLabel(SpiceDefaultSymLbr);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ //dlgPushButton("-CANCEL") {dlgReject(); exit(-10); }
+ dlgStretch(1);
+ if (dlgheader == "Diagnose") {
+ dlgPushButton("Save") {
+ string rptfile = filesetext(argv[0], ".rpt");
+ output(rptfile, "wt") {
+ printf("Program:\t%s\n", EAGLE_SIGNATURE);
+ printf("System:\t%s\n", OS_SIGNATURE);
+ printf("Eagle Path:\t%s\n", EAGLE_PATH);
+ printf("Eagle Dir:\t%s\n", EAGLE_DIR);
+ printf("User Dir:\t%s\n", EAGLE_HOME);
+ printf("LTSpiceExecute:\t%s\n", LTSpiceExecute);
+ printf("LTSpiceLibDir:\t%s\n", LTSpiceLibDir);
+ printf("ExpEagleSpiceSymDir:\t%s\n", ExpEagleSpiceSymDir);
+ printf("EagleExecute:\t%s\n", EagleExecute);
+ printf("Imp_ConnectScriptDir:\t%s\n", Imp_ConnectScriptDir);
+ printf("%s\n", cntscrsetup);
+ printf("SpiceSimulationLbr:\t%s\n", SpiceSimulationLbr);
+ printf("SpiceDefaultSymLbr:\t%s\n", SpiceDefaultSymLbr);
+ }
+ dlgMessageBox("Saved to:"+rptfile, "OK");
+ }
+ }
+ }
+ };
+ return;
+}
+
+/* ***********************
+ ******** MAIN ***********
+ *********************** */
+readconfig();
+int CntScr = 0;
+if (!LTSpiceExecute || argv[2] == "/S") {
+ string rootpath[] = { "C:/Programme/", "C:/Program files (x86)/", "C:/Program files/", "D:/Program files (x86)/", "D:/Program files/" }; // 2012-10-11
+ int nroot = 0;
+ do {
+ LTSpiceExecute = file_search("LTspiceIV/scad3.exe", rootpath[nroot], 3, "4085"); // 2012-11-27 das LTspice executable, in Pfad LTspiceIV, das es ältere Versionen gibt, mit unterschiedlichen Pfadnamen!
+ nroot++;
+ } while (!LTSpiceExecute && rootpath[nroot]);
+
+ if (!LTSpiceExecute) {
+ dlgMessageBox("!LTspiceIV (scad3.exe) not found.", "OK");
+ exit(-4141);
+ }
+ else {
+ ExpEagleSpiceSymDir = filedir(LTSpiceExecute) + "lib/sym/eagle/"; // 2012-12-05
+ LTSpiceLibDir = filedir(LTSpiceExecute) + "lib/"; // 2012-11-27
+ }
+
+ int pos = strstr(EagleExecute, "bin/"); // 2012-11-27 nur den Hauptpfad zu den Unterordnern
+ string eagleroot = strsub(EagleExecute, 0, pos);
+
+ string cfgdirlbr = cfgget("EAGLE:Directories.Lbr"); // 2012-10-30 den Pfad unter Optionen Verzeichnisse zu den importierten LTspice-LBRs erweitern!
+ pos = strstr(cfgdirlbr, "lbr/ltspice");
+ if (pos <0) {
+ cfgdirlbr = eagleroot + "lbr/ltspice;" + cfgdirlbr;
+ cfgset("EAGLE:Directories.Lbr", cfgdirlbr);
+ }
+
+ // prüfe Verzeichnis für Scripte zum erzeugen der Devices von LT
+ Imp_ConnectScriptDir = file_search("misc/ltspice/scr", eagleroot, 4, "4109"); // Das Directory der Scripte von LT zum erzeugen der Devices CONNECT, PACKAGE, ATTRIBUTE...
+ if (!Imp_ConnectScriptDir) {
+ if (dlgMessageBox("!Directory of LT connect scripts not found:\n" + eagleroot + "scr/ltc", "MAKE DIR", "CANCEL") != 0) exit(-4161);
+ // makedir(eagleroot, "scr/ltc");
+ }
+ else {
+ string scr[];
+ CntScr = fileglob(scr, Imp_ConnectScriptDir + "*.scr");
+ if (!CntScr) {
+ sprintf(h, "!No scripts found in:\n%s\n\nCopy first LT connect scripts!", Imp_ConnectScriptDir);
+ dlgMessageBox(h, "CANCEL");
+ exit(-4170);
+ }
+ }
+ string copyeaglesym2spice = file_search( "eagle", LTSpiceLibDir, 3, "4123"); // prüfe ob Unterordner /eagle unter /sym besteht?
+ string copysource = eagleroot+"misc/ltspice/lib/*.*";
+ if (copyeaglesym2spice) {
+ dosfilecopy( copysource, LTSpiceLibDir, "/S /Y"); // 2012-11-27 XCOPY mit Unterordner und ohne Eingabe/Quittierung
+ }
+ else {
+ if (!makedir(LTSpiceLibDir, "/sym/eagle")) { // Returnwert 0 wenn das Verzeichnis nicht angelegt werden konnte.
+ dlgMessageBox("!Can't creat directory:\n" + LTSpiceLibDir + "eagle", "CANCEL");
+ exit(-4181);
+ }
+ // kopiere die Spice Symbole vom Eagle-Paket nach LTC lib/sym/eagle inkl. Unterordner
+ // 2012-11-27 neu ist der Ordner sub mit der Datei note.sub
+ dosfilecopy( copysource, LTSpiceLibDir, "/S /Y"); // 2012-11-27 XCOPY mit Unterordner und ohne Eingabe/Quittierung
+ }
+
+ SpiceSimulationLbr = file_search("ltspice/lt-spice-simulation.lbr", EAGLE_DIR, 4, "4138"); // die Symbole zum simulieren, Stimuli (V, I, F Generatoren)
+ if (!SpiceSimulationLbr) {
+ dlgMessageBox("!Default LTspice simulation library not found, please import first:" + EAGLE_DIR + "/lbr/ltspice/lt-spice-simulation.lbr", "CANCEL");
+ // 2013-10-01 Pfadtrenner nach EAGLE_DIR und lbr...
+ exit(-4192);
+ }
+dlgMessageBox("!Default LTspice simulation library found on:\n" + EAGLE_DIR + "/lbr/ltspice/lt-spice-simulation.lbr", "CANCEL");
+
+ SpiceDefaultSymLbr = file_search("ltspice/sym.lbr", EAGLE_DIR, 4, "4144"); // die Default-Lbr für R, L, C, D, Res...
+ if (!SpiceDefaultSymLbr) {
+ dlgMessageBox("!Default LTspice symbol library (R C L D ...) not found, please import first:" + EAGLE_DIR + "lbr/ltspice/sym.lbr", "CANCEL");
+ exit(-4199);
+ }
+ string cntscrsetup;
+ sprintf(cntscrsetup, "%d scripts", CntScr);
+ autosetupinfo("Auto Setup Info", cntscrsetup);
+ saveconfig();
+ // 2012-10-30 die LTspice LBRs (den gesamten Ordner) in die USE-Liste eintragen!
+ string uselbr;
+ sprintf(uselbr, "USE -*;\nUSE '%slbr/ltspice';\nUSE '%slbr/eagle-ltspice'; #4222\n", eagleroot, eagleroot);
+ // Pfade immer in ' einschließen, besonders bei Windows 7/8 64-Bit,
+ // da es den Ordner "Programm (x86)" gibt, und die Klammern () von Eagle als Koordinate ausgewertet werden!
+ // für die eagle-ltspice.lbr muß der absolute Pfad angegeben werden,
+ // da der Pfad für die "eagl-lbrs" jetzt an zweiter Stelle steht! 2012-10-30
+ exit(uselbr);
+}
+
+
+/* ******************************
+ ******** main Export ***********
+ ****************************** */
+if (strupr(argv[1]) == "/E") {
+ if (library) { /*** LIBRARY ***/
+ library(L) {
+ ex_setupmenu(); // runs always with setup menu
+ if (deviceset && ExOnceLib) {
+ deviceset(DEV) {
+ DEV.devices(D) ex_draw_device(D, DEV);
+ /* *****************************************************************************************
+ Kein Handshake, das ULP wartet auf die Beendigung des aufgerufenen Programm (DOS-BOX)
+ und kehrt dann zum aufrufenden Fenster zurück.
+ Vorteil, das Fenster (Schaltplan) hat den Fokus wieder!
+ ****************************************************************************************** */
+ //call_system(Ex_AsyName);
+ //exit("RUN ulpmessage 'DEVICESET " + DEV.name + ".dev exported to " + ExpEagleSpiceSymDir + filename(filesetext(L.name, "/")) + DEV.name + ".asy'");
+ string rmsg;
+ sprintf(rmsg, "RUN ulpmessage 'DEVICESET %s.dev (%d) exported to %s", DEV.name, CntOutput, filedir(Ex_AsyName));
+ exit(rmsg);
+ }
+ }
+ else {
+ int cnt = 0;
+ L.devicesets(DEV) DEV.devices(D) {
+ cnt++;
+ ex_draw_device(D, DEV);
+ }
+ //exit("RUN ulpmessage '" + L.name + " exported to " + ExpEagleSpiceSymDir + filename(filesetext(L.name, "/")) + "*.asy'");
+ exit("RUN ulpmessage '" + L.name + " exported to " + filedir(Ex_AsyName) + "*.asy");
+ }
+ }
+ }
+
+ else if (sheet) { /*** SHEET ***/
+ if (strupr(argv[2]) == "/G") ExportAll = 0; // export only selected group
+
+ schematic(SCH) {
+ if (!ExportAll) ExpSchematic2LTpice = filesetext(SCH.name, "_group.asc"); // 2012-06-22
+ else ExpSchematic2LTpice = filesetext(SCH.name, ".asc"); // 2012-05-10
+ }
+ if (strupr(argv[2]) == "/S") {
+ ex_setupmenu();
+ exit(0);
+ }
+
+ if (Test) if (dlgMessageBox("Export Schematic to:\n" + ExpSchematic2LTpice, "OK", "CANCEL") != 0) exit(-6);
+
+ output(ExpSchematic2LTpice, "wt") {
+ printf("Version 4\n");
+ sheet(S) {
+ printf("SHEET %d %.0f %.0f\n", S.number, ex_spicegrid(u2mil(S.area.x2)), ex_spicegrid(u2mil(S.area.y2)*-1.0)); // SHEET 1 1684 1612
+ S.nets(N) N.segments(SEG) SEG.wires(W) if (ingroup(W) || ExportAll) ex_draw_net_wire(W);
+ S.nets(N) N.segments(SEG) SEG.labels(LAB) if (ingroup(LAB) || ExportAll) ex_draw_label(LAB);
+ S.parts(P) P.instances(I) if (ingroup(I) || ExportAll) ex_draw_instance(I, P);
+ S.wires(W) if (ingroup(W) || ExportAll) ex_draw_wire(W);
+ S.rectangles(R) if (ingroup(R) || ExportAll) ex_draw_rectangle(R);
+ S.circles(C) if (ingroup(C) || ExportAll) ex_draw_circle(C);
+ S.texts(T) if (ingroup(T) || ExportAll) ex_draw_text(T, "SCH", ""); // 2012-05-11
+ }
+ }
+
+ //string ExportedFile = ExpSchematic2LTpice;
+ int ExportedFileTime = -1;
+ int newfiletim = -1;
+ string f[];
+ int cnt = fileglob(f, ExpSchematic2LTpice);
+ if (cnt) {
+ ExportedFileTime = filetime(ExpSchematic2LTpice);
+ }
+ else {
+ dlgMessageBox("Warning, file '"+ExpSchematic2LTpice+"' does not exist!", "Break");
+ exit(-7);
+ }
+ status(" Waiting for return of "+filename(LTSpiceExecute));
+ string syscommand;
+
+ // Handshake mit LT-Spice über eine Datei (momentan der LTspice-Schaltplan selber, über den Zeitstempel)
+ if (Ex_WaitOnHandShake) {
+ sprintf(syscommand, "cmd.exe /c \"%s\" \"%s\"", LTSpiceExecute, ExpSchematic2LTpice);
+ system(syscommand); // externes Programm starten
+
+ ExportedFileTime = filetime(ExpSchematic2LTpice);
+ newfiletim = filetime(ExpSchematic2LTpice);
+ status("Waiting for LTspice response");
+ do {
+ newfiletim = filetime(ExpSchematic2LTpice);
+ } while (newfiletim == ExportedFileTime);
+ exit ("RUN 'ltspice.ulp /I' '"+ ExpSchematic2LTpice + "' 'RELOAD'");
+ }
+ /******************************************************************************************
+ Kein Handshake, das ULP wartet auf die Beendigung des aufgerufenen Programm (DOS-BOX)
+ und kehrt dann zum aufrufenden Fenster zurück.
+ Vorteil, das Fenster (Schaltplan) hat den Fokus wieder!
+ *******************************************************************************************/
+ call_system(ExpSchematic2LTpice);
+
+ newfiletim = filetime(ExpSchematic2LTpice);
+ // Überprüfe den Timestamp der Datei, falls geändert, dann starte das ULP mit der Option RELOAD!
+ if (newfiletim == ExportedFileTime) exit(0); // nothing changed!
+ exit ("RUN 'ltspice.ulp' '/I' '"+ ExpSchematic2LTpice + "' 'RELOAD'");
+ }
+
+ else dlgMessageBox("Start this ULP in a library or schematic!", "OK");
+ exit(-4320);
+}
+
+/* *******************************
+ ******** main Imxport ***********
+ ******************************* */
+else if (strupr(argv[1]) == "/I") {
+ sprintf(h, "%d", argc);
+ readconfig();
+ if (argc == 4) {
+ if (fileext(argv[2]) == ".asc") { // work with schematic
+ Imp_CntFileSpiceAsc = 1;
+ ImpSpiceSchematicAsc = argv[2];
+ }
+ else if (fileext(argv[2]) == ".asy") { // work with symbol
+ CntFileSpiceSym = 1;
+ FileSpiceSym[0] = argv[2];
+ }
+ ScriptFile = filesetext(argv[2], "~spice2eagle.scr");
+ }
+
+ else {
+ // ### main menu SYMBOL/SCHEMATIC ###
+ imp_setupmenu();
+ saveconfig();
+ }
+ if (!FileSpiceSym[0] && !ImpSpiceSchematicAsc) exit(-8);
+
+
+ /**** Import a library ****/
+ if (CntFileSpiceSym) {
+ int t = time();
+ string fext = "*.asy";
+ string libsource;
+ if (Import_All_Symbols) {
+ CntFileSpiceSym = fileglob(FileSpiceSym, filedir(FileSpiceSym[0])+fext);
+ if (!LbrName) LbrName = imp_dirname(FileSpiceSym[0]);
+ libsource = filedir(FileSpiceSym[0]) + "*.asy";
+ }
+ else {
+ if (!LbrName) LbrName = filesetext(FileSpiceSym[0], ".lbr");
+ libsource = filesetext(FileSpiceSym[0], "*.asy");
+ }
+ ScriptFile = filesetext(FileSpiceSym[0], Imp_ScriptExt);
+
+ if (NewLbrName) sprintf(Imp_Cmd, "OPEN '%s';\n", NewLbrName);
+ sprintf(h, "DESCRIPTION 'LT-Spice library generated with : \\n%s \\nfrom: %s \\nat %s';\n",
+ filename(argv[0]), libsource, t2string(t)
+ );
+ Imp_Cmd+=h;
+ sprintf(h, "LAYER %d SpiceOrder;\n", LayerSpiceOrder);
+ Imp_Cmd+=h;
+ sprintf(h, "SET COLOR_LAYER %d %d;\n", LayerSpiceOrder, ColorViolett); // SET COLOR_LAYER layer color;
+ Imp_Cmd+=h;
+
+ int nf = 0;
+ if (ScriptFile && FileSpiceSym[nf]) {
+ for (nf = 0; nf < CntFileSpiceSym; nf++) {
+ attribute2script("#4232\n", FileSpiceSym[nf], FileNewTemp); // neues Script anlegen, um die Attribute die in den PAckage-Varianten
+ // angelegt werden müssen, zwischen zu speichern. Denn das anlegen einer
+ // Package-Variante löscht die ATTRIBUTE, die vorher angelegt wurden!
+ string cmd;
+ Imp_CntPinname = 0;
+ int len = strlen(FileSpiceSym[nf]);
+ if (FileSpiceSym[nf] && FileSpiceSym[nf][len-1] != '/') { // can not use directories, cut last character /
+ CntLines = fileread(Lines, FileSpiceSym[nf]);
+ status(FileSpiceSym[nf]); // ein Lebenszeichen
+ Imp_SymDevName = strupr(filesetext(filename(FileSpiceSym[nf]), ""));
+ if (imp_checkexist_dev(Imp_SymDevName)) {
+ if (dlgMessageBox("! Attention: " + Imp_SymDevName + ".DEV exist.
\nfrom: %s \nat: %s';\n",
+ filename(argv[0]), B.name, t2string(time())
+ );
+ Cmd += h;
+ }
+
+ if (!Group) {
+ dlgMessageBox("!First define a GROUP. Read HELP GROUP (enter)", "OK");
+ }
+ else {
+ dlgDialog("Return script") {
+ dlgHBoxLayout dlgSpacing(500);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(400);
+ dlgTextEdit(Cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("Run Script") { dlgAccept(); exit(Cmd); }
+ dlgPushButton("ESC") { dlgReject(); exit(-1); }
+ }
+ };
+ }
+}
+
+else dlgMessageBox("!Start this ULP in a board.", "OK");
\ No newline at end of file
diff --git a/trunk/ulp/make-long-pad-inner-layer.ulp b/trunk/ulp/make-long-pad-inner-layer.ulp
new file mode 100644
index 00000000..3f07ffb3
--- /dev/null
+++ b/trunk/ulp/make-long-pad-inner-layer.ulp
@@ -0,0 +1,180 @@
+#usage "en:This ULP generates for LONG and OFFSET pads in inner layers the same diameter and shape as it is in the outer layers.
"
+ "EAGLE basically uses for all pads in inner layers a round pad shape. "
+ "If you are using a LONG or OFFSET pad for a oblong soldering lug, and you defined a slotted hole with contours "
+ "drawn in layer 46, Milling, it is necessary to expand the pad in the inner layers with additional WIRE "
+ "segments. So the DRC is able to check possible conflicts with the slotted hole, and polygons with a different "
+ "signal name can be calculated properly. "
+ "However, there might occur a problem with thermals because the ULP can't recognize whether the pad is "
+ "connected to a polygon with thermals in the current layer. It can happen that the pad extension connects "
+ "fully with the copper plane. "
+ "If a (list of) Element_name(s) is given, the extended shape will be generated for the given element(s); "
+ "if there is no Element_name given, extended shapes are generated for all elements that have long pads.
"
+ "RUN make-long-pad-inner-layer [Element_name [Element_name] .. ] "
+ "The inner layers must be used.! There has to be at least one WIRE oder POLYGON "
+ "in the inner layer.
"
+ "In order to avoid DRC Overlap errors, you have to connect each pad. "
+ "The wires must have the correct signal name! Therefore connect each referring pin in the schematic with a NET. "
+ "The ERC reports 'Only one pin on net...' then, but this has to be approved. "
+ "
"
+ "Author: support@cadsoft.de"
+ ,
+ "de:Dieses ULP generiert für LONG- und OFFSET-Pads für die Innenlagen die gleiche Größe und Form wie in den Aussenlagen.
"
+ "EAGLE generiert grundsätzlich für Pads in Innenlagen eine runde Padform. "
+ "Wird für längliche Lötanschlüsse (Lötfahnen) ein LONG- oder OFFSET-Pad benutzt und die Bohrung zusätzlich "
+ "geschlitzt, wobei die Fräskontur für den Längsschlitz im Layer 46 (Milling) definiert wird, so muß "
+ "in den Innenlagen das Pad zusätzlich mit WIRE-Segmenten erweitert werden. Dadurch kann der DRC Konflikte "
+ "mit dem Längsschlitz überprüfen bzw. ein Polygon mit fremden Signalnamen entsprechend freirechnen. "
+ "Es gibt allerdings ein Problem bei Thermalstegen, da über das ULP nicht ohne weiteres erkannt werden kann, "
+ "ob das Pad in diesem Layer an eine Kupferfläche über Thermalstege angeschlossen ist. "
+ "Diese Pads werden durch die Paderweiterung teilweise vollflächig angebunden. "
+ "Bei Angabe eines (einer Liste von) Bauteilnamen werden nur für dieses (diese) Bauteil(e) die "
+ "Paderweiterung erzeugt. Ohne Angabe von Bauteilnamen wird bei allen Bauteilen, die LONG-Pads enthalten, die "
+ "Paderweiterung erzeugt.
"
+ "Die Innenlagen müssen benutzt sein! Es muß also mindestens ein WIRE oder ein POLYGON "
+ "in der Innenlage vorhanden sein.
"
+ "Um Overlap-Fehler im DRC zu vermeiden, muß jedes PAD angeschlossen sein; "
+ "somit haben die erzeugten WIREs auch den entsprechenden Signal-Namen. "
+ "Dazu verbinden Sie im Schaltplan die Pins mit einem NETz. "
+ "Dadurch bedingt, meldet der ERC 'Nur ein Pin an Net... Diese Meldung kann aber toleriert werden.'"
+ "
"
+ "Autor: support@cadsoft.de"
+
+#require 6.0400;
+
+string Version = "1.4"; // 1.0 2007-11-29 alf@cadsoft.de
+ // 1.1 2008-01-08 check if connect with signal
+ // generate error messages
+ // 1.2 2008-01-15 Option - Element-Name list
+ // check if schematic consistent
+ // 1.3 2011-11-14 also use unused Layer
+ // 1.4 2013-01-15 Version 6 has no more supply option ($) of inner layer
+ // more detail info about pad without signal name
+ // real values extended to new resolution .9f
+string s;
+string cmd = "GRID mm;\nSET WIRE_BEND 2;\n";
+string error = "";
+int usedLayer[];
+string nameLayer[];
+
+
+void err(string name, string padname, int x, int y) {
+ sprintf(s, "%s Pad %s (%.9f %.9f) mm : No signal connected\n",
+ name, padname, u2mm(x), u2mm(y) );
+ error += s;
+ return;
+}
+
+
+string checkname(string s) { // check signal name, if name add ' ' 2008.01.08 alf@cadsoft.de
+ if (s) sprintf(s, "'%s'", s);
+ return s;
+}
+
+
+int checkEname(string s) {
+ for (int n = 1; n < argc; n++ ) {
+ if (strupr(argv[n]) == s) return 1;
+ }
+ return 0;
+}
+
+
+if (board) {
+ int usedsum = 0;
+ if (dlgMessageBox(usage + "
Version " + Version, "OK", "Cancel") != 0) exit(-1);
+ board(B) {
+ B.layers(L) {
+ if (L.number < 16 & L.number > 1) {
+ if (L.used) {
+ usedLayer[L.number] = 1;
+ nameLayer[L.number] = L.name;
+ usedsum++;
+ }
+ }
+ }
+ B.elements(E) {
+ if (!argv[1] || checkEname(E.name) ) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ string p, m;
+ real l;
+ if (C.pad.shape[16] == PAD_SHAPE_LONG) {
+ l = u2mm(C.pad.diameter[1]) * C.pad.elongation * 0.005;
+ sprintf(m, "MARK (%.9f %.9f);\n", u2mm(C.x), u2mm(C.y));
+ sprintf(s, "WIRE %s %.9f (R0 0) (P%.9f %0.1f);\n", // 2013-01-15 more resolution
+ checkname(C.pad.signal),
+ u2mm(C.pad.diameter[1]),
+ l, C.pad.angle
+ );
+ p += s;
+ sprintf(s, "WIRE %s %.9f (R0 0) (P%.9f %.1f);\n", // 2013-01-15 more resolution
+ checkname(C.pad.signal),
+ u2mm(C.pad.diameter[1]),
+ l, C.pad.angle+180.0
+ );
+ p += s;
+ if (!C.pad.signal) err(E.name, C.pad.name, u2mm(C.x), u2mm(C.y) );
+ }
+ else if (C.pad.shape[16] == PAD_SHAPE_OFFSET) {
+ real l = u2mm(C.pad.diameter[1]) * C.pad.elongation * 0.01;
+ sprintf(m, "MARK (%.9f %.9f);\n", u2mm(C.x), u2mm(C.y));
+ sprintf(s, "WIRE %s %.9f (R0 0) (P%.9f %0.1f);\n", // 2013-01-15 more resolution
+ checkname(C.pad.signal),
+ u2mm(C.pad.diameter[1]),
+ l, C.pad.angle
+ );
+
+ p += s;
+ if (!C.pad.signal) err(E.name, C.pad.name, u2mm(C.x), u2mm(C.y) );
+ }
+ if (p) {
+ cmd += m;
+ for (int n = 2; n < 16; n++) {
+ if (usedLayer[n]) { // 2011-11-14
+ sprintf(s, "CHANGE LAYER %d;\n", n);
+ cmd += s;
+ cmd += p;
+ } // 2011-11-14
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!usedsum) {
+ dlgMessageBox("!Inner layer not used! No Wire or Polygon in inner layer!", "OK");
+ exit(-1);
+ }
+
+ if (error) { // check and view errors
+ string Message = "";
+ if (project.schematic) {
+ Message = "Consitent schematic is loaded! First conect unconected Pins/Pads in schematic, please cancel.";
+ }
+ dlgDialog("ERROR " + filename(argv[0])) {
+ dlgHBoxLayout dlgSpacing(400);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(400);
+ dlgTextView(error);
+ }
+ dlgLabel("Can not place Signal-Wires on Pads with Signal-Name. "+
+ "Please draw a NET on this PIN in Schematic to connect this PAD with an signal!"
+ );
+ dlgLabel(Message);
+
+ dlgHBoxLayout {
+ dlgPushButton("Ignore") dlgAccept();
+ dlgPushButton("Cancel") { dlgReject(); exit(-1); }
+ dlgStretch(1);
+ }
+ };
+ }
+ cmd += "MARK;\nGRID LAST;\nRATSNEST;";
+ // dlgMessageBox(cmd, "OK"); // show generated script
+ exit(cmd);
+}
+
+else dlgMessageBox("Start this ULP in Board", "OK");
diff --git a/trunk/ulp/make-package-consistent-brd-sch.ulp b/trunk/ulp/make-package-consistent-brd-sch.ulp
new file mode 100644
index 00000000..16f21fbd
--- /dev/null
+++ b/trunk/ulp/make-package-consistent-brd-sch.ulp
@@ -0,0 +1,139 @@
+#usage "Make schematic and board package consistent, use packages from board."
+ "
"
+ "Author: alf@cadsoft.de
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+string Version = "1.0.0"; // 2011-05-30 alf@cadsoft.de
+
+string Error = "";
+int NotConsist = 0;
+string ScrName;
+int CntChange = 0;
+
+// ### Functions ###
+// Replace character with string (to replace technologie "*" and Package-Variant "?" in Deviceset name)
+string ChrStrRep(string str, char a, string b) {
+ string s[];
+ strsplit(s, str, a);
+ if (a) {
+ if (b == "''") return s[0] + s[1];
+ return s[0] + b + s[1];
+ }
+ return str;
+}
+
+
+void change_pac(string ename, string epackagename, string elibraryname) {
+ string s;
+ project.schematic(SCH) {
+ SCH.parts(P) {
+ if (P.name == ename) {
+ if (P.deviceset.library == elibraryname) {
+ string DevNname;
+ string techno = P.device.technologies;
+ string tech[];
+ int cntt;
+ int found = 0;
+ int foundtech = 0;
+ P.deviceset.devices(D) {
+ if (D.package.name == epackagename) { // check exist technologie in nue package variant
+ DevNname = D.name;
+ cntt = strsplit(tech, D.technologies, ' ');
+ for (int n = 0; n < cntt; n++) {
+ if (techno == tech[n]) {
+ foundtech = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (foundtech) {
+ if (P.device.package.name != epackagename) { // different packages in sch and brd?
+ P.deviceset.devices(D) {
+ if (D.package.name == epackagename) {
+ string dev_name = ChrStrRep(P.deviceset.name, '*', techno); // replace first with technologie
+ dev_name = ChrStrRep(dev_name, '?', D.name); // replace second with package variant
+ P.instances(I) {
+ string cmd;
+ sprintf(s, "EDIT .S%d;\n", I.sheet);
+ cmd+= s;
+ sprintf(s, "CHANGE PACKAGE %s %s;\n", ename, dev_name);
+ cmd+= s;
+ printf(cmd);
+ NotConsist = 1;
+ found = 1;
+ CntChange++;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ sprintf(s, "%s : Package-Variant %s on Deviceset %s not found!\n",
+ ename, epackagename, P.deviceset.name);
+ Error += s;
+ }
+ break; // parts
+ }
+ }
+ else {
+ sprintf(s, "%s : Technologie %s in Package-Variant %s not exist! Check device in library %s.lbr\n",
+ ename, techno, DevNname, P.deviceset.library);
+ Error += s;
+ }
+ }
+ else {
+ sprintf(s, "%s : Different libraries BRD:%s.lbr SCH:%s.lbr\n",
+ ename, P.deviceset.library, elibraryname);
+ Error += s;
+ }
+ }
+ }
+ }
+ return;
+}
+
+
+// ### Main ###
+if (library) {
+ dlgMessageBox("Start this ULP in a consistent board or schematic.", "OK");
+ exit(0);
+}
+
+if (project.schematic && project.board) {
+ if (project.board) {
+ project.board(B){
+ ScrName = filesetext(B.name, "~pac~consistent~.scr"); // temporary script file
+ output(ScrName, "wtD") {
+ B.elements(E) {
+ int PACcontact = 0;
+ E.package.contacts(C) { // check only packages with contacts
+ change_pac(E.name, E.package.name, E.package.library);
+ break;
+ }
+ }
+ }
+ }
+ if (Error) {
+ dlgDialog("Make PAC consistent errors") {
+ dlgHBoxLayout dlgSpacing(600);
+ dlgTextView(Error);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("+OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ exit(-1);
+ }
+ else {
+ if (!NotConsist) {
+ dlgMessageBox("Schematic and Board are Package consistent!", "OK");
+ exit(0);
+ }
+ string cmd;
+ sprintf(cmd, "SCRIPT '%s'\nEDIT .BRD;\nRUN ulpmessage '%d packages changed.';\n\nRUN '%s'", ScrName, CntChange, argv[0]);
+ exit(cmd);
+ }
+ }
+}
+dlgMessageBox("!Board an Schematic are not consistent.\nCheck Element/Part - Value - Netlist!", "OK");
diff --git a/trunk/ulp/make-symbol-device-package-bsdl.ulp b/trunk/ulp/make-symbol-device-package-bsdl.ulp
new file mode 100644
index 00000000..fb558c83
--- /dev/null
+++ b/trunk/ulp/make-symbol-device-package-bsdl.ulp
@@ -0,0 +1,3833 @@
+#usage "Make Symbol, Device, Package or use Package in LBR\n"
+ "
"
+ "Generates Symbol and Device from a text file containing a list of pin names. "
+ "This version can use BSDL (Boundary Scan Description Language) files to create a Package for BGA "
+ "or use a set of parameters to generate a Package. "
+ "
"
+ "Author: ed@anuff.com / librarian@cadsoft.de
"
+
+#require 5.7001
+
+/*
+ * Copyright (c) 2004 Ed Anuff . All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+// Rev: 1 (Eagle 4.12r04) - 2004-08-13 alf@cadsoft.de
+// *****************************************************************
+// Rev: 2 (Eagle 4.13) - 2004-14-09
+// special sorting for Pad names with 2-Alpha-Character
+// *** Xilix BSM-Files without ";" in line *************************
+// Xilinx = "linkage bit_vector (" and ": inout bit -- "
+// BSDL = "linkage bit_vector; (" and ": inout bit; -- "
+// *****************************************************************
+// Rev: 3 (Eagle 4.13) - 2004-11-23
+// corrected parse line with "port"
+// *** Xilinx BSM-Files
+// "port (" - without spaces
+// *** Intel .bsdl-Files
+// " port (" - with spaces
+// corrected Function: [Replace] character string
+// *****************************************************************
+// Rev: 4 (Eagle 4.13) - 2005-01-10
+// port: trim left spaces from string
+// pars_map() corrected counter
+// *****************************************************************
+// Rev: 5 (Eagle 4.13) - 2005-01-27
+// AnalogDevice uses Tabulator not Space characters and
+// some times places no space before use direction
+// *****************************************************************
+// Rev: 6 (Eagle 4.13) - 2005-03-23
+// Device and Package description font bold/italic
+// *****************************************************************
+// Rev: 7 (Eagle 4.14) - 2005-06-06
+// Accept comment "--" in line
+// *****************************************************************
+// Rev: 8 (Eagle 4.15) - 2005-06-28
+// Corrected grid and Package outlines
+// allways set grid to 1.0 mm (default)
+// *****************************************************************
+// Rev: 9 (Eagle 4.15) - 2005-08-02
+// change TAB with SPACE "\t" --> " "
+// Improved search end of "port" list for Xilinx-BSDL-Files
+// *****************************************************************
+// Rev: 10 (Eagle 4.15) - 2005-08-19
+// Menu to generate quad and dual pin packages
+// correct port-end-parse with ");" and for AnalogDevice == "));"
+// *****************************************************************
+// Rev: 11 (Eagle 4.15) - 2005-10-18
+// new parse end of port, counts open-close Bracked
+// BSDL can use multiple packages, now can select one, if more than one defined
+// Also generate Symbol only
+// Generate Package variant
+// Scan "BSDL" in text to set BSDL-Parse-Option if any file extension
+// *****************************************************************
+// Rev: 12 (Eagle 4.15) - 2005-12-01
+// If !file use lbrname for path/script
+// Correct package_name handling
+// Change bit-map if select quad or dual package
+// Use also thrue hole PADs for Packages
+// *****************************************************************
+// Rev: 13 (Eagle 4.16r1) - 2006-06-01
+// round coordinates to 0.1 inch in symbol
+// Menu BGA: [] Accept copy local parameter to global parameter
+// *****************************************************************
+// Rev: 14 (Eagle 4.16r1) - 2006-06-09
+// Menu BGA: add Cream-Mask Parameter
+// *****************************************************************
+// Rev: 15 (Eagle 4.16r1) - 2006-07-06
+// more at 1 Pin-Pad definition in Xilinx-BSDL Files, at
+// constant CP56 : PIN_MAP_STRING :=
+// "TCK : K10, TDI : J10, TDO : A6, TMS : K9, " &
+// *****************************************************************
+// Rev: 16 (Eagle 14.16r1) - 2006-10-19
+// Plus menu entry: delete Pad-Prefix in BSDL-List
+// Example: Xilinx - xcs20_PQ208.bsd
+// Check if exist Pad names
+// *****************************************************************
+// Rev: 17 (Eagle 14.16r1) - 2006-11-09
+// Delete Lines with Textstring extendet to EXACT / INCLUDE
+// *****************************************************************
+// Rev: 18 (Eagle 14.16r1) - 2006-12-05
+// Pad-Names to upper case
+// on linkage, check by pin-name (VDD, VCC, VSS, VDD) if the pin really power-pin
+// Set direction on all pins of a group of pins in a text-block
+// Generate a new symbol!
+// If more es 160 pins used, placed the pins as stripes by max (64) pins.
+// This make no large symbol if too much pins in device.
+// *****************************************************************
+// Rev: 19 (Eagle 4.16r2) - 2007-01-10
+// Start argument "edit-no-description" to switch of red marker in desciption;
+// *****************************************************************
+// Rev: 20 (Eagle 4.16r2) - 2007-10-15
+// Button: SortPin (List)
+// *****************************************************************
+// Rev: 21 (Eagle 4.16r2) - 2008-04-02
+// Button: Delete Column in Text field
+// Button: Delete double pad number in pin-pad-direction list if copy
+// text from a document like pdf ...
+// *****************************************************************
+// Rev: 22 (Eagle 5.0) - 2008-05-20
+// [Save text as] [Load Text] in Text-Menu
+// Rev: 23 (Eagle 5.0) - 2008-06-16 Texas BSDL files are use UPPER-CASE for "PORT"
+// Rev: 24 (Eagle 5.0) - 2008-06-19 no check for PIN-coordinates if not symbol generated
+// Rev: 25 (Eagle 5.0) - 2008-07-03 numbering pins, set Pin-Direction
+// *****************************************************************
+// Rev: 26 (Eagle 5.3) - 2008-11-07 Text-Options [Rename PAD]
+// Check pin list with pad names if package generated with option Package
+// Generate Device-Descriptin also by Text-Option
+// New changeable parameter GRID for Package generation,
+// if measurements in data sheet in inch, mil, mm.
+// remember last bsdl-file path
+//
+// Rev: 27 (Eagle 5.3) - 2008-12-03
+// Option for Padname use as in list, or generate by counter
+// *****************************************************************
+// Rev: 28 (Eagle 5.4) - 2009-02-18
+// check if list sorted by pad name, to generate correct symbol
+// by ascending pad namnes.
+// - correct edit option delte x th. line
+// *****************************************************************
+// Rev: 29 (Eagle 5.4.3) - 2009-03-09
+// no pad sorting if used bsdl file to generate symbol
+//
+// Rev: 30 (Eagle 5.6.1) - 2009-10-12
+// check if exist package definition in bsdl file
+//
+// Rev: 31 (Eagle 5.6.1) - 2009-10-16
+// generate only BGAs without file
+//
+// Rev: 32 (Eagle 5.6.1) - 2009-11-12
+// change character ';' ',' to '_' in parse function
+//
+// Rev: 33 (Eagle 5.6.2) - 2009-11-24
+// Split text and merge 1. helf text-lines with 2nd half text-lines
+//
+// Rev: 34 (Eagle 5.7.2) - 2010-02-15
+// Change wire width 10 mil on symbol outline
+//
+// Rev: 35 (Eagle 5.9.3) - 2010-05-25
+// Change PIN legth SHORT
+// Check if text parsed for generate symbol
+//
+// Rev: 36 (Eagle 5.9.3) - 2010-12-02
+// Info Text-Optoins ** use word separator also for delete column
+//
+// Rev. 37 (Eagle 5.11.1) 2011-03-07
+// Option ganerate pad names for generate only package (not BGA)
+//
+// Rev. 38 (Eagle 5.11.1) 2011-04-01
+// shrink menus for smaler Display (MacBook Pro user) now 823 to 667 pixel
+// ULP Scripts Panel too large for MacBook Pro
+// Help is now a Dialog with textview
+// Check package name if generate a package
+// New Rename PIN in tab List Options
+// New help for list tab
+//
+// Rev. 39 (Eagle 5.11.1) 2011-05-23
+// Check continuous pad number in function check_pad_sorting()
+// change to uppercase in function
+//
+// Rev. 40 (Eagle 5.11.2) 2011-09-20
+// Check directions of eagle bevor create symbol
+// Save package config, save BGA config
+//
+// Rev. 41 (Eagle 5.90.0) 2011-09-20
+// Check on empty pin list used make symbol
+// Check on empty pad list used make package
+//
+// Rev. 42 (Eagle 5.11.2) 2011-11-03 alf@cadsoft.de
+// No symbol (name) check, if only generated package
+// Edit Package-Name also in Package Tab
+//
+// Rev. 43 (Eagle 6.0.1) 2011-12-15 alf@cadsoft.de
+// Corrected check max/min coordinate with INT_MAX to check
+// coordinates of pads and pins.
+//
+// Rev. 44 (Eagle 6.5.0) 2013-12-02 Button to open manual as pdf
+//
+
+string Revision = "Rev. 44";
+
+string HelpDE = "Dieses ULP unterstützt die Generierung von Symbolen, Devices und Packages. " +
+ "Eine BSDL-Datei (Boundary Scan Description Language .bsdl) wird automatisch geparsed.
" +
+ "Pin-Direction: "
+ "Der Bezeichner 'linkage' wird für No-Connects (NC), Power (VCC), oder Ground (GND) benutzt, wobei anhand der BSDL-Daten "
+ "nicht unterschieden werden kann ob es sich um einen NC oder PWR Pin handelt. "+
+ "In einigen Fällen kann es vorkommen, daß dadurch Signal-Pins die Direction PWR erhalten, die man manuell im Symbol-Editor ändern muß. "+
+ "Bei Text-Dateien wird über die Anzahl der Trennzeichen der word separator ermittelt und voreingestellt.
" +
+ "Um Text-Dateien (Tabellen) zu bearbeiten, gibt es folgende Möglichkeiten:" +
+ "
" +
+ "
Split with word separator: Damit wird im Text an der Stelle an der sich ein nicht druckbares Zeichen befindet ein NewLine eingefügt." +
+ "
Split with Character: An der Stelle im Text an der sich dieses druckbare Zeichen befindet, wird ein NewLine eingefügt." +
+ "
Merge: Es werden, entsprechend dem angegebenen Wert, so viele Zeilen zu einer Zeile zusammengefügt." +
+ "
Merge 1/2 Text: Die Zeilen der zweiten Texthälfte wird an die Zeilen der ertsen Texthälfte angefügt." +
+ "Als Trennzeichen zwischen den Wörtern wird der gewählte word separator benutzt." +
+ "
Replace character string .. with .. : Zeichenketten im Text, die exakt der angegebenen Definition entsprechen, werden ausgetauscht." +
+ "
Delete lines with text: Zeilen die exakt dem angegebenen Text entsprechen, wenn das Flag Exact gesetzt ist, "
+ "oder Zeilen die den angegebenen Text enthalten, wenn das Flag Include gesetzt ist, werden entfernt." +
+ "
Delete every x th line [x], Start at line [n] - Löscht jede X-te Zeile ab der n-ten Zeile im Text." +
+ "
Delete empty lines: Zeilen, die leer sind bzw. nur nicht druckbare Zeichen enthalten, werden entfernt."+
+ "
<<-- Copy kopiert die Tabelle wieder in den Text(-Editor)." +
+ "
Sort Pad sortiert die Liste nach Pad-Namen." +
+ "
Sort Pin sortiert die Liste nach Pin-Namen." +
+ "
Parse -->> übersetzt den Text (Tabelle) in die Pin-Pad-Direction-Tabelle." +
+ " Als Trennzeichen zwischen den Wörtern wird der gewählte word separator benutzt." +
+ "
" +
+ "Durch Anwenden der einzelnen Möglichkeiten kann ein beliebiger Text zu einer brauchbaren Tabelle umgestaltet werden. " +
+ "Es ist auch möglich einen Text aus der Zwischenablage (Clipboard) einzufügen (Ctrg+V)." +
+ "
" +
+ "Bei Text-Dateien kann ein Package aus der vorhandenen Use-Liste der geladenen LBR gewählt, oder über Package automatisch generiert werden. " +
+ "Bei BSDL-Dateien (.bsdl) kann ebenfalls ein Package automatisch generiert werden. " +
+ "Es wird überprüft ob im benutzten Package genügend Pads vorhanden sind um jeden Symbol-Pin zu verbinden." +
+ "
" +
+ "BGA-Package generieren (BSDL): Es wird davon ausgegangen, daß das Gehäuse symmetrisch aufgebaut ist. " +
+ " - Package Width: Die Gehäuseaussenmaße (Kunststoffkörper). " +
+ " - PAD Grid: Der Abstand zwischen den SMD-Pads. " +
+ " - PAD Diameter: Der Durchmesser der SMD-Pads. " +
+ " - Stop Mask: Ein positiver Wert erzeugt eine Stopmaske um den angegebenen Wert größer als das Pad, ein negativer Wert erzeugt " +
+ "eine Maske um den Betrag kleiner als das Pad. " +
+ "Package generieren: Durch Angabe der Parameter in der Karte Package können zweireihige oder vierseitige Packages generiert werden. " +
+ "Der Start-Parameter edit-no-description verhindert daß in der Description des Device der Hinweis " +
+ " edit this description eingetragen wird.
" +
+ "Author: librarian@cadsoft.de";
+ "
";
+
+string HelpEN = "This ULP supports the generation of Symbols, Devices, and Packages. " +
+ "A BSDL (Boundary Scan Description Language) file will be parsed automatically " +
+ "PIN-Direction: In addition to in, out, and inout, a pin can be identified as type linkage. "+
+ "This is used for no-connects (NC), power (VCC), or ground (GND). "+
+ "The number of separators in the text file determins and presets the word separator.
" +
+ "There are the following possibilities to edit text files (spreadsheets):" +
+ "
" +
+ "
Split with word separator: Insert NewLine at the position of a non-printable character." +
+ "
Split with Character: Insert NewLine in the text at the position of the given printable character." +
+ "
Merge: Joins the given number of lines to one common line. " +
+ "The given word separator is used as separator between words." +
+ "
Replace character string with: For replacing the given string." +
+ "
Delete lines with text: For deleting lines that contain exactly the given text." +
+ "
Delete every x th line [x], Start at line [n]: Deletes every x th line, beginning with line number n." +
+ "
Delete empty lines: For deleting lines that do not contain characters or contain non-printable characters only." +
+ "
<<-- Copy: Copies the spreadsheet into the text editor again. The given word separator will be used between words." +
+ "
Sort Pad The list will be sorted by pad names." +
+ "
Sort Pin The list will be sorted by pin names." +
+ "
Parse -->>: Transfers the text (spreadsheet) into the Pin-Pad-Direction spreadsheet." +
+ "
" +
+ "These tools allow to make a usable spreadsheet from any text." +
+ "It is also possible to insert text from the operating sytem's clipboard. " +
+ "If you are working with text files you have to choose an already existing package from the currently loaded library or use Package. " +
+ "It is also possible to generate a new package from a BSDL file (*.bsdl). " +
+ "First the ULP will check if there are sufficient pads for the pins of the symbol." +
+ "
" +
+ "Generate a package (BSDL files only): The package is assumed to be designed symmetrically. " +
+ " - Package width: The dimension of the (plastic) case . " +
+ " - PAD grid: The distance between the smds. " +
+ " - PAD diameter: The diameter of the smds." +
+ "
Swap PIN-PAD: tauscht in der Liste die Pins-Pads-Spalte." +
+ "
Swap PAD-DIR: tauscht in der Liste die Pads-Direction-Spalte." +
+ "
Direction Change: Ändert die Direction der Liste nach Angaben." +
+ "
Direction Set: Setzt alle Direction-Einträge auf den gewählten Wert." +
+ "
Direction Delete: Löscht alle Diretion-Einträge in der Liste." +
+ "
Clear leading zeros in BGA-Pad: Löscht alle führenden Nullen die evtl. bei BGA-Pads aus der BSDL-Datei übernommen worden sind." +
+ "
Delete double pad number: Löscht alle doppelt vorkommenden Zeilen mit gleicher Padnummer. " +
+ "Das kann vorkommen, wenn aus Text, PDF oder sonstigen Seiten, Tabellen kopiert werden." +
+ "
Rename PIN: Alle Teile der Pinnamen in denen die Suchzeichenkette [Replace] character string aus der Karteikarte Text Options vorkommen, " +
+ "werden mit der Zeichenkette with ersetzt." +
+ "
Rename PAD: Alle Teile der Padnamen in denen die Suchzeichenkette [Replace] character string aus der Karteikarte Text Options vorkommen, " +
+ "werden mit der Zeichenkette with ersetzt." +
+ "
Numbering pads für pins: Die Spalte Pads wird neu durchnummeriert. " +
+ "
" +
+ "Author: librarian@cadsoft.de" +
+ "
";
+
+string HelpLiEN = "List Option
" +
+ "
" +
+ "
Swap Pin-Pad Exchanges the pin and pad coloumn." +
+ "
Swap Pin-Pad Exchanges the pad and direction coloumn." +
+ "
Direction Change: Cahnge Direction of list at your input." +
+ "
Direction Set: Setzt all Direction entry of selected value." +
+ "
Direction Delete: Delete all Diretion entry of list." +
+ "
Clear leading zeros in BGA-Pad: Delete all leading zeros of BGA-Pad names (possibly include from BSDL file." +
+ "
Delete double pad number: Löscht alle doppelt vorkommenden Zeilen mit gleicher Padnummer. " +
+ "Das kann vorkommen, wenn aus Text, PDF oder sonstigen Seiten, Tabellen kopiert werden." +
+ "
Rename PIN: Search character in pin name and replace [Replace] character string at with of register card \"Text Options\". " +
+ "
Rename PAD: Search character in pad name and replace [Replace] character string at with of register card \"Text Options\". " +
+ "
Numbering renumbering column Pads. " +
+ "
" +
+ "Author: librarian@cadsoft.de" +
+ "
";
+
+
+string Help;
+string HelpList;
+if (language() == "de") {
+ Help = HelpDE;
+ HelpList = HelpLiDE;
+}
+else {
+ Help = HelpEN;
+ HelpList = HelpLiEN;
+}
+
+
+int TextHigh = 220; // high of the text and list window
+int TextWidth = 450; // width of the text window
+int ListWidth = 250; // width of the list window (Pins Pads Direc.)
+int TextStatusHigh = 18; // distance of Text an Tap filed to display text status
+
+string editMode = " edit this description";
+string infile, Source_file = "DESCRIPTION '';\n";
+string symbol_file, symbol_name;
+string device_file, device_name;
+string packagefile;
+string package_name;
+string pac_variant_name = "";
+string packages[];
+int n_packages = 0;
+int package_selected = 0;
+real package_wire_width = 0.1016; // to create a new package from BSDL file
+real pac_width = 17.0; // to create a quad package from BSDL file
+real textsize = 1.27;
+real grid_val = 1.0; // for BallGridArea packages
+real SMD_diameter = 0.5; // for BallGridArea packages
+real MaskRestring = 0.0; // for BallGridArea packages
+real CreamDiameter = 0.0; // for BallGridArea packages 2006-06-09
+string genpac_grid = "MM"; // 2008-11-07 default grid to generate package, can change in menu to mil, inch, mic.
+
+int smd_pad = 0; // use SMD or PAD for generate Package 2005-12-01
+// PAD_SHAPE_SQUARE, PAD_SHAPE_ROUND, PAD_SHAPE_OCTAGON, PAD_SHAPE_LONG, PAD_SHAPE_OFFSET
+string PadShape[] = { "SQUARE", "ROUND", "OCTAGON" };
+int pad_shape = PAD_SHAPE_ROUND;
+string packinfomess = "";
+
+// new Menu Paramter to auto generate
+int pad_layout;
+int Pad_Count = 1; // the pads of package
+int cnt_side = 0; // calculated pads on one side of package
+real xA_pac = 14.0; // width of the metall pins
+real yA_pac = 14.0; // width of the metall pins for quad package
+real xD_pac = 12.0; // width of the plastic package in x
+real yD_pac = 12.0; // width of the plastic package in y
+real basic_pad_grid = 0.65; // the Basic grid Pad to Pad
+real pad_width = 0.35; // the width of solder pin
+real pad_stand_out = 0.5; // stand out the pad over the metall pin
+real ypad_length = 0.4; // the pad width
+real xpad_length = 0.9; // the pad length
+real mark_length = 0.6; // length of corner edge to mark pad 1
+real roundness_restring = 0; // the SMD roundness for QFP/LCC/DualInline
+string round_restring = "Roundness %";
+int packageparameter_accept; // if all parameter Ok for QFP/LCC/DualInline
+int BGAparameter_accept; // if BGA parameter accept for generate package
+string paccmd; // the script to generate qfp/lcc/Dual-Inline
+
+int pin_map_cnt = 0; // count the maps in the file
+string pin_map_name; // the name of actual pin map
+
+
+char w_separator[] = { ' ' , '\b', '\f',
+ '\n', '\r', '\t',
+ '\v', 0 };
+
+string separator[] = { "SPACE", "Backspace", "Form Feed",
+ "New Line", "Carriage Return", "Horizontal tab",
+ "Vertical tab", "" };
+
+int select_separ = 0;
+char Word_separator = w_separator[select_separ];
+string String_separator;
+
+string Vector_name[];
+int sVector[], eVector[];
+int cnt_vector;
+string up_down;
+
+string text;
+string lines[];
+int n_lines;
+
+numeric string pin_names[];
+int n_pin_names = 0;
+numeric string pad_names[];
+int n_pad_names = 0;
+int use_pad_names = 0;
+enum { useNONE, useBGA, usePACwithPrefix } // for use Padnames to generate Device
+string pad_prefix;
+string old_pad_prefix;
+string checkPadname = "";
+
+
+numeric string pins_pads_direc[];
+numeric string pins[];
+numeric string pads[];
+string Pin_Direc[];
+int suffix[];
+int suffix_cnt, suffix_point;
+int suffix_s, suffix_e;
+
+int n_pins = 0;
+int n_pads = 0;
+
+int maxPinCnt = 100;
+int maxStripeCnt = 64; // maximum of pins on a stripe in symbol
+string pinCntInfo = " "; // Info if more as maxPinCnt pins used in one Symbol 2006-12-05
+
+
+// extend this list to set pin direction on power by linkage 2006-12-05
+string PowerName[] = {
+ "GND",
+ "VCC",
+ "VDD",
+ "VSS",
+ "VEE",
+ "+5V",
+ "-5V",
+ "" // the last must be empty ""
+ } ;
+
+enum { k_single, k_dual, k_dual2, k_quad , k_stripe };
+int pin_layout = k_dual;
+
+
+int is_bsdl = 0;
+int pars_mode;
+
+int breacked_status = 0;
+enum { mode_null, mode_port, mode_map };
+
+string bsdl_map_pin; // the actual map pin name
+ // more as one pins can named as the same
+
+string bsdl_pin_name[];
+string bsdl_Pin_Dir[];
+int cnt_bsdl_port;
+string parsed_pins = " ";
+string bsdl_package_name;
+int make_Package; // generate Package by generated script
+
+
+char port_separator = ':';
+char PIN_MAP_separator = ':';
+
+string tinfo = " ";
+string MakePacInfo = " ";
+int select = 0;
+int sorting = 0; // view list
+
+int index[];
+string used_pad_number[]; // 2008-11-07
+enum { e_symbol, bga_pac, e_pac }; // editor type to check max value of grid
+
+string rememberBSDLpath; // 2008-11-07
+string rememberLastPathFile = "~remember-make-bsdl~.mem";
+
+ // 2009-10-16
+string bga_pad_name[] = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "T", "U", "V", "W", "Y", "" };
+int cntBGApadX = 44;
+int cntBGApadY = 44;
+int only_generate_bga = 0;
+int only_generate_pac = 0; // to generate only a qfp/plcc ... package
+
+string Pin_Dir[] = {
+ "NC",
+ "IN",
+ "OUT",
+ "IO", // 2011-09-20 V6 use IO
+ "OC",
+ "PWR",
+ "PAS",
+ "HIZ",
+ "SUP"
+ };
+
+string Existdir = "
" + // 2011-05-23
+ "
Existing
" +
+ "
Directions:
" +
+ "
NC
Not Connected (not used)
" +
+ "
IN
Input
" +
+ "
OUT
Output
" +
+ "
IO
In/Out programmable
" + // 2011-09-20 V6 use IO
+ "
OC
Open Collector
" +
+ "
HIZ
Tristate
" +
+ "
SUP
Supply pin (without package)
" +
+ "
PAS
Passive
" +
+ "
PWR
Power pin of device
"
+ "
";
+
+
+real m_pac_width = pac_width; // 2006-06-01 -- 2011-09-20
+real m_grid_val = grid_val;
+real m_SMD_diameter = SMD_diameter;
+real m_MaskRestring = MaskRestring;
+real m_CreamDiameter = CreamDiameter;
+
+string packinfo = "";
+
+
+string ExecutableAcrobatReader = cfgget("ULP:AcrobatReader_ulp");
+string PdfDocLink;
+
+/* ***************************************
+ ########## Functions ###########
+ *************************************** */
+// change Eagle slash in path names to backslash for windows
+string getDOSname(string s) {
+ string sx[];
+ int n = strsplit(sx, s, '/');
+ return strjoin(sx, '\\');
+}
+
+void getexecutable(void) {
+ string execute = dlgFileOpen("Wähle PDF-Anzeige-Programm", "", "*.exe");
+ if (execute) {
+ ExecutableAcrobatReader = execute;
+ cfgset("ULP:AcrobatReader_ulp", execute); // setze die Optiopn in der eaglerc.usr
+ return;
+ }
+ else exit(-1);
+}
+
+void system_call(string loadpdffile) { // 2013-12-02 DOS comand execute
+ if (!ExecutableAcrobatReader) getexecutable();
+ string syscommand;
+ // Das executable und der Dateiname müssen in " " eingeschlossen werden, wegen Spaces im Pfad-Dateinamen!
+ // "CMD.EXE /C START " ist nötig, da sonst auf das Beenden des Acrobat-Reader gewartet wird.
+ sprintf(syscommand, "CMD.EXE /C START \"%s\" \"%s\"", getDOSname(ExecutableAcrobatReader), getDOSname(loadpdffile));
+ system(syscommand); // externes Programm starten
+ return;
+}
+
+/* ************************************ */
+int check_pin_direction(string pindir) { // 2011-09-20
+ int pn = 0;
+ do {
+ if (pindir == Pin_Dir[pn]) return 0;
+ pn++;
+ } while (Pin_Dir[pn]);
+ return -1;
+}
+
+
+string check_pin_dir(void) { // 2011-09-20
+ for (int n = 0; n < n_pins; n++) {
+ if (!Pin_Direc[n]) return "empty pin direction!";
+ if (check_pin_direction(Pin_Direc[n])) return Pin_Direc[n];
+ }
+ return "";
+}
+
+
+// 2008-11-07 check if exist package, but do not generate
+int check_exist_pac(string pacname) {
+ int exist = 0;
+ library(L) {
+ L.packages(PAC) {
+ if (PAC.name == pacname) return 1;
+ }
+ }
+ return 0;
+}
+
+
+int check_Coordinate(string name, real x, real y, string grid_unit, int edit_type) { // 2008-11-07 new, grid unit, editor type
+ string s;
+ real maxminxy;
+ // 2008-11-07 check max x-y by used grid
+ if (grid_unit == "MM") maxminxy = u2mm(INT_MAX); // 2011-12-15 the internal maximum
+ else if (grid_unit == "INCH") maxminxy = u2inch(INT_MAX);
+ else if (grid_unit == "MIL") maxminxy = u2mil(INT_MAX);
+ else if (grid_unit == "MIC") maxminxy = u2mic(INT_MAX);
+ else {
+ if (edit_type == bga_pac) dlgMessageBox("Check grid parameter in BGA menu!", "OK");
+ else if (edit_type == e_pac) dlgMessageBox("Check grid parameter in Package menu!", "OK");
+ return -1;
+ }
+ if (x > maxminxy || x < -maxminxy ) {
+ sprintf(s, "Too much pins to generate symbol in X Coordinate (%.4f) %s out of range %.4f %s
", x, grid_unit, maxminxy, grid_unit);
+ }
+ if (y > maxminxy || y < -maxminxy) {
+ sprintf(s, "Too much pins to generate symbol in Y Coordinate (%.4f) %s out of range %.4f %s
", y, grid_unit, maxminxy, grid_unit);
+ }
+ if (s) {
+ if (edit_type == e_symbol) s += "Check Symbol Pin Layout: Single | Dual | Quad before exiting this ULP
";
+ else if (edit_type == bga_pac) s += "Check pad names in BSDL file " + infile + " and/or measures in BGA menu.";
+ else if (edit_type == e_pac) s += "Check pad names " + infile + " and/or measures in Packlage menu.";
+ dlgMessageBox(s, "Ok");
+ return -1;
+ }
+ return 0;
+}
+
+
+string replaceString(string source, string find, string replace) {
+ string result = source;
+ int i = strstr(source, find);
+ string head;
+ string tail;
+
+ if (i > -1) {
+ if(i == 0) {
+ head = "";
+ tail = strsub(source, i + strlen(find));
+ }
+ else {
+ head = strsub(source, 0, i);
+ tail = strsub(source, i + strlen(find));
+ }
+ result = head + replace + tail;
+ }
+ return result;
+}
+
+
+string replaceCharacter(string source, char find, char replace) {
+ string result = source;
+ int i = strchr(source, find);
+ string head;
+ string tail;
+
+ if (i > -1) {
+ if(i == 0) {
+ head = "";
+ tail = strsub(source, i + 1);
+ }
+ else {
+ head = strsub(source, 0, i);
+ tail = strsub(source, i + 1);
+ }
+ sprintf(result, "%s%c%s", head, replace, tail);
+ }
+ return result;
+}
+
+
+
+// cut spaces on left and on right of string 2005-10-05
+string trimString(string source) {
+ if(!source) return source;
+ string result;
+ int i, head = 0;
+ for (i = 0; source[i]; i++) {
+ if (!isspace(source[i])) {
+ head = i;
+ break;
+ }
+ }
+ int send = strlen(source);
+ int len = send;
+ if (len) {
+ for (i = len-1; i >= 0; i--) {
+ if (!isspace(source[i])) {
+ send = i+1;
+ break;
+ }
+ }
+ }
+ return strsub(source, head, send-head);
+}
+
+
+string cleanWhitespace(string line) {
+ string oldtext = "";
+ do {
+ oldtext = line;
+ line = replaceString(line, "\t", " ");
+ line = replaceString(line, " ", " ");
+ } while (line != oldtext);
+ return trimString(line);
+}
+
+
+string spaceCharacter(string l, char c) {
+ string oldtext = "";
+ do {
+ oldtext = l;
+ l = replaceCharacter(l, c, ' ');
+ } while (l != oldtext);
+ return l;
+}
+
+
+string clear_line(string l) {
+ if(!l) return l;
+
+ int comment = strstr(l, "--"); // comment
+ if (comment > 0) l = strsub(l, 0, comment); // strip comment 02.06.2005
+
+ for (int n = 0; n < strlen(l); n++) {
+ if (l[n] == '\"' || l[n] == '(' || l[n] == ')' || l[n] == '&' ) {
+ l[n] = ' ';
+ }
+ else if ( l[n] == ';') l[n] = ','; // *** replace ';' with ',' for last MAP_LINE
+ }
+ l = trimString(l);
+ return l;
+}
+
+
+string cleanName(string name) {
+ name = cleanWhitespace(name);
+ name = replaceString(name, " ", "_");
+ name = replaceString(name, ".", "_");
+ name = replaceString(name, "(", "_");
+ name = replaceString(name, ")", "_");
+ name = replaceString(name, "\\", "-");
+ // 2009-11-12 alf@cadsoft.de
+ name = replaceString(name, ",", "_");
+ name = replaceString(name, ";", "_");
+ return name;
+}
+
+
+void replaceWord(string search, string replace) {
+ string s;
+ tinfo = " ";
+ dlgRedisplay();
+ if (search == replace) {
+ dlgMessageBox("!Search string equal Replace string", "Cancel");
+ return;
+ }
+ int found, newfound;
+ int ct = 0;
+ do {
+ newfound = strstr(text, search, found);
+ if (newfound >= 0) {
+ sprintf(s, "(%d)", newfound);
+ status(s);
+ text = strsub(text, 0, newfound) + replace + strsub(text, newfound+strlen(search) );
+ found = newfound + strlen(replace);
+ ct++;
+ }
+ else break;
+ } while (text);
+
+ status(" ");
+ sprintf(tinfo, "%d words replaced", ct);
+ dlgRedisplay();
+ return;
+}
+
+
+void gen_viewlist(int cnt) {
+ status ("generate list"); // 2008-11-07 display working
+ for (int i = 0; i < cnt; i++) {
+ sprintf( pins_pads_direc[i], "%s\t%s\t%s", pin_names[i], pad_names[i], Pin_Direc[i]);
+ }
+ pins_pads_direc[i] = ""; // 2008-04-02
+ return;
+}
+
+
+string clear_textline(string line, char c) {
+ int pos;
+ do {
+ pos = strchr(line, c);
+ if (pos >= 0) line[pos] = '_'; // 2009-11-12
+ } while (pos >= 0);
+ return line;
+}
+
+
+void filter_pin_pad( int use_pad_names) {
+ for (int d = 0; d <= n_pins; d++) {
+ pins_pads_direc[d] = "";
+ pin_names[d] = "";
+ pad_names[d] = "";
+ pins[d] = "";
+ pads[d] = "";
+ Pin_Direc[d] = "";
+ suffix[d] = 0;
+ }
+ n_pins = 0;
+ for (int i = 0; i < n_lines; i++) {
+ lines[i] = clear_textline(lines[i], ';');
+ string pin_name = cleanName(lines[i]);
+ string pad_name = "";
+ int n;
+ string items[];
+ n = strsplit(items, lines[i], Word_separator);
+ if (n > 0) {
+ pin_name = cleanName(items[0]);
+ if (use_pad_names = useBGA) { // ## useNONE, useBGA, usePACwithPrefix, isePACwithoutPrefix ##
+ pad_name = cleanName(items[1]);
+ }
+
+ if (strlen(pin_name) > 0) {
+ pins[n_pins] = pin_name;
+ if (use_pad_names) pads[n_pads++] = pad_name;
+
+ if (n > 2) Pin_Direc[n_pins] = items[2]; // 2008-04-02
+ pin_names[n_pins] = pin_name;
+ pad_names[n_pins] = pad_name;
+ n_pins++;
+ }
+ }
+ }
+ pins[n_pins] = "";
+ pads[n_pins] = "";
+ pin_names[n_pins] = "";
+ pad_names[n_pins] = "";
+ pins_pads_direc[n_pins] = "";
+ Pin_Direc[n_pins] = "";
+ Pin_Direc[n_pins] = "";
+ suffix[n_pins] = 0;
+ gen_viewlist(n_pins);
+ return;
+}
+
+
+void filter_text( int use_pad_names) {
+ n_lines = strsplit(lines, text, '\n');
+ filter_pin_pad( use_pad_names);
+ sprintf( parsed_pins, "%d pins parsed", n_pins); // 2008-11-07
+ Pad_Count = n_pins; // set pin counter for package option on text
+ return;
+}
+
+
+// ** scratch line after position n **
+string scratch(string p, char c, int n) {
+ int pos = strchr(p, c, n);
+ if (pos > 0) return strsub(p, 0, pos);
+ else return p;
+}
+
+
+/* ******************************************************
+ Analog-Device use "linkage" also for signal pins!!
+ Example:
+ CLKIN: linkage bit;
+ XTAL: linkage bit;
+ VROUT: linkage bit_vector(0 to 1));
+ *******************************************************
+
+ http://www.actel.com/documents/BSDLformat.pdf
+ In addition to in, out, and inout, a pin can be identified as type linkage.
+ This is used for no-connects (NC), power (VCC), or ground (GND).
+ ******************************************************** */
+
+string Pin_Direction( string bsdldir) {
+ string pin_dir;
+ bsdldir = scratch( bsdldir, ' ', 1); // for Xilinx BSM-Files 14.09.2004
+ bsdldir = scratch( bsdldir, ';', 1);
+
+ if (bsdldir == "inout") pin_dir = "IO"; // 2011-09-20 V6 use IO
+ else if (bsdldir == "out") pin_dir = "OUT";
+ else if (bsdldir == "in") pin_dir = "IN";
+ else if (bsdldir == "linkage") pin_dir = "PWR";
+ else if (bsdldir == "buffer") pin_dir = "HIZ";
+ else {
+ bsdldir = scratch( bsdldir, '(', 0);
+ }
+ if (bsdldir == "linkage bit_vector") pin_dir = "PWR";
+ // ** 09.09.2004 place a ';' in Xilinx BSD-Files **
+ // ** to separate " linkage bit_vector" ! **
+ return pin_dir;
+}
+
+
+string get_dir( string name) { // ** direction of pin **
+ for (int i = 0; i < cnt_bsdl_port; i++) {
+ if (bsdl_pin_name[i] == name) {
+ return bsdl_Pin_Dir[i];
+ break;
+ }
+ }
+ return "";
+}
+
+
+string getVector(string v) { // ** count up or down **
+ string Vname, vs[];
+ int pos;
+ pos = strsplit(vs, v, ':');
+ pos = strsplit(vs, vs[0], ' ');
+ for (int n = pos; pos; n--) {
+ if (vs[n]) break;
+ }
+ if (vs[n][0] == '(') vs[n] = strsub(vs[n], 1);
+ return vs[n];
+}
+
+
+void parse_bit_vector(string l) {
+ /* EXAMPLE **************************************************
+ XILINX-BSM-File
+ VCCAUX: linkage bit_vector; (1 to 16);
+ VCCINT: linkage bit_vector; (1 to 16);
+
+ INTEL-BSDL-File
+ port (pci_ad : inout bit_vector(31 downto 0);
+ pci_cbe_n : inout bit_vector(3 downto 0);
+ ** ^ ^ **
+ ** counter direction up = to / down = downto. **
+ ********************************************************** */
+
+ int pos = strstr(l, "bit_vector", 0);
+ if (pos > 0) {
+ Vector_name[cnt_vector] = getVector(l);
+ status(Vector_name[cnt_vector]); // 2008-11-07 display working
+ string s, v, vs[];
+ s = strsub(l, pos);
+ int n = strsplit(vs, s, '(' ); // cut up to (
+ s = vs[1];
+ n = strsplit(vs, s, ')' ); // cut )
+ s = vs[0];
+ n = strsplit(vs, s, ' ' );
+ sVector[cnt_vector] = strtol(vs[0]);
+ eVector[cnt_vector] = strtol(vs[2]);
+ up_down = vs[1];
+ cnt_vector++;
+ }
+ return;
+}
+
+
+// search & count breackeds for parse end 05.10.2005
+void brackeds(string l) {
+ string br[];
+ int open_breacked = strsplit(br, l, '(');
+ int close_breacked = strsplit(br, l, ')');
+ breacked_status += (open_breacked - close_breacked);
+ return;
+}
+
+
+// ** BSDL parser **
+void pars_port(string l) {
+ status("parse port");
+ brackeds(l);
+ if (!breacked_status) { // end of port list 2005-10-05
+ pars_mode = mode_null;
+ }
+ string k[];
+ // if more as 1 port in line, it's a group of ports in line! 2006-12-05
+ int cntk = strsplit(k, l, ',');
+ for (int nk = 0; nk < cntk; nk++) {
+ string p[];
+ int n = strsplit(p, k[nk], port_separator); // ':'
+ if (n > 1) {
+ bsdl_pin_name[cnt_bsdl_port] = trimString(p[0]);
+ bsdl_Pin_Dir[cnt_bsdl_port] = Pin_Direction(trimString(p[1]));
+ if (bsdl_Pin_Dir[cnt_bsdl_port] == "PWR") { // check if realy a power pin by name 2006-12-05
+ int cntpwr = 0, np = 0;
+ do {
+ cntpwr += strstr(bsdl_pin_name[cnt_bsdl_port], PowerName[np])+1; // to check more names, extend the line PowerName[]...
+ if (cntpwr) break;
+ np++;
+ } while (PowerName[np]);
+ if (!cntpwr) bsdl_Pin_Dir[cnt_bsdl_port] = "PAS"; // no powerpin 2006-12-05
+ }
+ parse_bit_vector(l);
+ cnt_bsdl_port++;
+ }
+ }
+ return;
+}
+
+
+int get_suffix(string vector) {
+ int n;
+ for (n = cnt_vector; n >= 0; n--) {
+ if (vector == Vector_name[n]) break;
+ }
+ return n;
+}
+
+
+void pars_map(string l) {
+ status("parse maping");
+
+ if (strstr(l, ";") >= 0 ) { // semikolon marks end of map list
+ pars_mode = mode_null; // set parse mode
+ }
+ l = clear_line(l); // replace '"' and '(' and ')' with space, and replace ';' with ','
+ l = cleanWhitespace(l);
+
+ string lq[];
+ int nlq = strsplit(lq, l, ','); // 2006-07-06 more as 1 Pin-Pad-Definition in Xilinx-BSDL files
+ // Example : xc2c32a_cp56.bsd
+ // constant CP56 : PIN_MAP_STRING :=
+ // "TCK : K10, TDI : J10, TDO : A6, TMS : K9, " &
+ for (int nq = 0; nq <= nlq; nq++) {
+ l = lq[nq];
+ string p[];
+ string pad_map;
+ int n = strsplit(p, l, PIN_MAP_separator); // ':'
+
+ if (n > 1) { // pin name
+ string ps[];
+ int nn = strsplit(ps, trimString(p[0]), ' ');
+ bsdl_map_pin = ps[0]; // a new pin name
+ pad_map = p[1]; // pad name(s)
+ status(pad_map); // 2008-11-07 display working
+ suffix_point = get_suffix(bsdl_map_pin);
+ if (suffix_point < 0) {
+ suffix_cnt = -1; // set counter negativ -1
+ }
+ else {
+ suffix_s = sVector[suffix_point];
+ suffix_e = eVector[suffix_point];
+ suffix_cnt = suffix_s;
+ }
+ }
+ else { // only pad names
+ pad_map = p[0];
+ }
+ pad_map = spaceCharacter(pad_map, ',');
+ pad_map = cleanWhitespace(pad_map);
+ n = strsplit(p, pad_map, ' ');
+ for (int i = 0; i <= n; i++) {
+ if (p[i]) { // ** 2005-01-10
+ // line can start with ", ..."
+ // line can end with ...,"
+ pins[n_pins] = bsdl_map_pin;
+ pads[n_pins] = strupr(trimString(p[i])); // upper case ** 2006-12-05
+ suffix[n_pins] = suffix_cnt;
+ if (suffix_cnt >= 0) {
+ if (up_down == "to") suffix_cnt++;
+ else if (up_down == "downto") suffix_cnt--;
+ }
+ n_pins++;
+ }
+ }
+ pins[n_pins] = ""; // clear +1
+ pads[n_pins] = "";
+ pin_names[n_pins] = "";
+ pad_names[n_pins] = "";
+ suffix[n_pins] = 0;
+ }
+ return;
+}
+
+
+string get_devName(string l) {
+ l = cleanWhitespace(l);
+ string s[];
+ int n = strsplit(s, l, ' ');
+ if (n > 1) return strupr(s[1]);
+ return "--";
+}
+
+
+string get_pacName(string l) {
+ string s[];
+ int n = strsplit(s, l, '"');
+ if (n > 1) return strupr(s[1]);
+ return "";
+}
+
+
+string get_pin_map_name(string l) {
+ l = cleanWhitespace(l);
+ string s[];
+ int n = strsplit(s, l, ' ');
+ n = strsplit(s, s[1], ':');
+ return s[0];
+}
+
+
+/* EXAMPLE ************************************************
+entity IXP4XX is
+ generic(PHYSICAL_PIN_MAP : string:= "BGA");
+ port (pci_ad : inout bit_vector(31 downto 0);
+ pci_cbe_n : inout bit_vector(3 downto 0);
+ pci_par : inout bit;
+ pci_frame_n : inout bit;
+ ....
+ ...
+ ..
+ constant BGA:PIN_MAP_STRING :=
+ "pci_ad : (D3, C2, J6, B1, A1, C1, D1, G3,"&
+ " E1, J4, G1, F1, K5, H2, K3, H1,"&
+ " N5, P2, P3, P5, N1, R1, R3, U1,"&
+ " U4, T1, V1, R5, V3, T4, W1, U3),"&
+ "pci_cbe_n : (H4, K1, M1, P1),"&
+ "pci_par : M2,"&
+******************************************************** */
+void filter_bsdl(void) {
+ n_lines = strsplit(lines, text, '\n');
+ int n;
+ /** counter and strings reset **/
+ suffix_cnt = 0;
+ pars_mode = mode_null;
+ cnt_bsdl_port = 0;
+ pin_map_cnt = 0; // use multiple PIN_MAP_STRING: in BSDL
+ n_pins = 0;
+ package_name = "";
+ package_selected = 0;
+
+
+ for ( n = 0; n < n_lines; n++) {
+ string line = lines[n];
+
+ if (strstr(line, "--") == 0); // comment
+
+ else {
+ switch(pars_mode) {
+ case mode_port: /*** parse port lines pin-names and function ***/
+ pars_port(trimString(line)); // 2005-01-10 trim spaces on left side of string
+ break;
+
+ case mode_map: /*** parse pad-name ***/
+ pars_map(line);
+ break;
+
+ default : int pos = strstr(strlwr(line), "port"); // 2008-06-16 Texas BSDL files are UPPER-CASE for "PORT"
+ if (pos >= 0) {
+ brackeds(line);
+ pars_mode = mode_port;
+ pos = strstr(line, "(", pos);
+ string p = strsub(line, pos+1);
+ pars_port(trimString(p));
+ }
+
+ else if (strstr(line, "constant") >= 0 && strstr(line, "PIN_MAP_STRING") > 8) {
+ if (!pin_map_cnt) {
+ package_name = strupr(get_pin_map_name(line));
+ pin_map_cnt++;
+ pars_mode = mode_map;
+ package_selected = 0;
+ }
+ else {
+ string next_pin_map = get_pin_map_name(line);
+ pin_map_cnt++;
+ if (dlgMessageBox("found next MAP list " + next_pin_map + " (Package), last Map list " + package_name + " (Package)
Use MAP?
", next_pin_map, package_name) != 0) ;
+ else {
+ package_name = strupr(next_pin_map);
+ pars_mode = mode_map;
+ suffix_cnt = 0; // reset counter an arrays 06.10.2005
+ n_pins = 0; // reset pin list counter
+ }
+ }
+ }
+
+ if (strstr(line, "entity") == 0) {
+ device_name = get_devName(line); // 23.11.2004
+ }
+
+ if (strstr(line, "generic") >= 0) {
+ package_name = strupr(get_pacName(line)); // 23.11.2004
+ package_selected = 0;
+ }
+ break;
+ }
+ }
+ }
+ status ("generate direction"); // 2008-11-07 display working
+ for ( n = 0; n < n_pins; n++) {
+ Pin_Direc[n] = get_dir( pins[n]);
+ if (suffix[n] >= 0) {
+ if (Pin_Direc[n] == "PWR") {
+ sprintf( pin_names[n], "%s@%d", pins[n], suffix[n]);
+ }
+ else {
+ sprintf( pin_names[n], "%s%d", pins[n], suffix[n]);
+ }
+ pins[n] = pin_names[n];
+ }
+ else pin_names[n] = pins[n];
+ pad_names[n] = pads[n];
+ }
+ // ** in a text block, only the last line define the direction **
+ // ** fill down the pindirection in list 2006-12-05 **
+ for ( n = n_pins - 1; n; n--) {
+ if (!Pin_Direc[n-1] && Pin_Direc[n]) Pin_Direc[n-1] = Pin_Direc[n];
+ }
+ pins_pads_direc[n_pins] = ""; // make shure the last in the list is empty!
+ pin_names[n_pins] = "";
+ pad_names[n_pins] = "";
+ Pad_Count = n_pins; // 2008-11-07 set pad counter
+ sprintf( parsed_pins, "%d pins parsed", n_pins);
+ dlgRedisplay();
+ if (n_pins > 160) { // 2008-11-07
+ sprintf(pinCntInfo, "Too many pins for a small symbol. Tip: Generate symbol with stripes of max pins in line."); // 2006-12-05
+ pin_layout = k_stripe;
+ }
+ else if (n_pins > maxPinCnt) {
+ sprintf(pinCntInfo, "Too many pins for a small symbol. Generate symbol with four sides.");
+ pin_layout = k_quad; // 2008-11-07
+ }
+ sprintf( bsdl_package_name, "Used package in BSDL file: %s", package_name );
+ gen_viewlist(n_pins);
+ return;
+}
+
+
+void check_separator(void) {
+ string tx[];
+ int scnt = 0;
+ int n = -1;
+ do {
+ n++;
+ int i = strsplit(tx, text, w_separator[n]);
+ if (scnt < i) {
+ scnt = i;
+ select_separ = n;
+ Word_separator = w_separator[select_separ];
+ sprintf(String_separator, "%c", Word_separator);
+ }
+ } while(w_separator[n]);
+ return;
+}
+
+
+// is in Text "BSDL" then mark Text as BSDL 2005-10-18
+int scan_isbsdl(void) {
+ int bsdl = 0;
+ bsdl = strstr(text, "BSDL");
+ if (bsdl > 0) return 1;
+ return 0;
+}
+
+
+void readText( string file) {
+ string base_file = filename(file);
+ string base_name = cleanName(strsub(filename(file), 0, strrchr(base_file, '.')));
+ symbol_name = base_name;
+ device_name = base_name;
+
+ // reset all counters
+ for (int d = 0; d <= n_pins; d++) {
+ pins_pads_direc[d] = "";
+ pin_names[d] = "";
+ pad_names[d] = "";
+ pins[d] = "";
+ pads[d] = "";
+ Pin_Direc[d] = "";
+ suffix[d] = 0;
+ }
+ n_pins = 0;
+ n_pads = 0;
+ n_pin_names = 0;
+ n_pad_names = 0;
+ package_name = "";
+
+ int n = fileread(text, file);
+ status("parse ..."); // 2008-11-07 display, im working
+ is_bsdl = scan_isbsdl();
+ string f = strlwr(fileext(file));
+ if (f == ".bsm" || f == ".bsd" || f == ".bsdl" || is_bsdl) {
+ // ** clear tabulator in text **
+ tinfo = "Parsing BSDL file, please wait!";
+ parsed_pins = "Please wait!";
+ dlgRedisplay();
+ int i;
+ do {
+ i = strchr(text, '\t');
+ if(i > 0) {
+ text[i] = ' ';
+ }
+ } while (i > 0);
+
+ use_pad_names = useBGA;
+ pad_prefix = "";
+ filter_bsdl(); // file parse
+ is_bsdl = 1;
+ }
+ if (!is_bsdl) check_separator();
+ sprintf(tinfo, "[text length %d character]", strlen(text) );
+ dlgRedisplay();
+ return;
+}
+
+
+string split_row_column(string p, int type) {
+ int n;
+ for (n = 0; n < strlen(p); n++) {
+ if (p[n] > '@');
+ else break;
+ }
+ if (type) return strsub(p, n);
+ return strsub(p, 0, n);
+}
+
+string merge_half_text_lines(string t) { // 2009-11-24
+/*
+Example:
+1
+2
+3
+4
+5
+6
+1DIR
+1B1
+1B2
+GND
+1B3
+1B4
+
+--- merge to ---
+
+1 1DIR
+2 1B1
+3 1B2
+4 GND
+5 1B3
+6 1B4
+*/
+ string newtext;
+ string l[];
+ int cnt = strsplit(l, t, '\n');
+ if (cnt & 1) {
+ string m;
+ sprintf(m, "Count of lines are odd number (%d), only a even number of lines can merge.", cnt);
+ dlgMessageBox(m, "OK");
+ return t;
+ }
+ cnt = cnt / 2;
+ if (cnt >= 1) {
+ for (int n = 0; n < cnt; n++) {
+ newtext += l[n] + String_separator + l[cnt+n] + "\n";
+ }
+ sprintf(tinfo, "Text to %d lines merged.", cnt);
+ }
+ else {
+ dlgMessageBox("Less than two lines.", "OK");
+ return t;
+ }
+ return newtext;
+}
+
+
+// *** BGAs can use 2 Alpha-Character for Pad-Name ***
+void padsort(void) {
+ int n;
+ for (n = 0; n < n_pins; n++) {
+ if(isalpha(pad_names[n][1])) {
+ pad_names[n] = "~" + pad_names[n];
+ }
+ }
+ sort(n_pins, index, pad_names);
+ for (n = 0; n < n_pins; n++) {
+ if(pad_names[n][0] == '~') {
+ pad_names[n] = strsub(pad_names[n], 1);
+ }
+ }
+}
+
+
+void makePackage(string file) {
+ real maxcolumn;
+ packagefile = filesetext(file, "~package.scr");
+ output(packagefile, "wtD") {
+ if(packageparameter_accept) printf("%s", paccmd); /** generate QFP/LCC/DUAL-Line **/
+ else if (BGAparameter_accept) { /** generate BGA **/
+ printf("EDIT %s.PAC;\n", package_name);
+ printf("GRID %s %.4f ON;\n", genpac_grid, grid_val/2); // 2008-11-07 set actual grid to generate package
+ printf("SET WIRE_BEND 2;\n");
+ printf("CHANGE ROUNDNESS 100;\n");
+ printf("CHANGE LAYER 1;\n");
+ printf("CHANGE SMD %.4f %.4f;\n", SMD_diameter, SMD_diameter);
+ padsort();
+ int cntrow, column, cntcolumn; // Zeile/Spalte
+ string row_name, last_name;
+
+ for (int n = n_pins-1; n >= 0; n--) {
+ row_name = split_row_column(pad_names[index[n]], 0);
+ column = strtol(split_row_column(pad_names[index[n]], 1));
+ if(maxcolumn < column) maxcolumn = column;
+ if (last_name != row_name) {
+ cntrow++;
+ last_name = row_name;
+ }
+ if (check_Coordinate(pad_names[index[n]], grid_val*column, grid_val*cntrow, genpac_grid, bga_pac)) exit(0); // 2008-11-07 grid from bga
+ printf("CHANGE LAYER 1;\n");
+ printf("SMD NOSTOP NOCREAM '%s' (%.4f %.4f);\n", pad_names[index[n]], grid_val*column, grid_val*cntrow );
+ printf("CHANGE LAYER 29;\n"); // tStop
+ printf("CIRCLE 0 (%.4f %.4f) (%.4f %.4f);\n", grid_val*column, grid_val*cntrow, grid_val*column + SMD_diameter/2+MaskRestring, grid_val*cntrow);
+ if (CreamDiameter) {
+ printf("CHANGE LAYER 31;\n"); // tCream
+ printf("CIRCLE 0 (%.4f %.4f) (%.4f %.4f);\n", grid_val*column, grid_val*cntrow, grid_val*column + CreamDiameter/2, grid_val*cntrow);
+ }
+ }
+ printf("GROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (>%.4f %.4f);\n",
+ -1.0 * grid_val, -1.0 * grid_val,
+ grid_val * (maxcolumn+1), -1.0 * grid_val,
+ grid_val * (maxcolumn+1), grid_val * (cntrow+1),
+ -1.0 * grid_val, grid_val * (cntrow+1),
+ -1.0 * grid_val, -1.0 * grid_val );
+
+ real centerx, centery;
+ centerx = (grid_val * (maxcolumn+1)) / 2;
+ centery = (grid_val * (cntrow+1)) / 2;
+ printf("MOVE (>%.4f %.4f) (0 0);\n", centerx, centery);
+
+ printf("SET WIRE_BEND 0;\n");
+ printf("CHANGE LAYER 21;\n");
+ printf("WIRE .2032 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n",
+ -pac_width /2 + package_wire_width, -pac_width /2 + package_wire_width,
+ pac_width /2 - package_wire_width, pac_width /2 - package_wire_width,
+ -pac_width /2 + package_wire_width, -pac_width /2 + package_wire_width);
+ // *** mark edge on pin 1 ***
+ printf("SET WIRE_BEND 2;\n");
+ printf("WIRE .2032 (%.4f %.4f) (%.4f %.4f);\n",
+ -pac_width /2 + package_wire_width, pac_width /2 - grid_val,
+ -pac_width /2 + grid_val, pac_width /2 - package_wire_width);
+
+ printf("CHANGE SIZE %.2f;\n", textsize);
+ printf("CHANGE LAYER 25;\n");
+ printf("TEXT >NAME (%.4f %.4f);\n",
+ -pac_width/2, pac_width/2 + textsize*0.5);
+
+ printf("CHANGE LAYER 27;\n");
+ printf("TEXT >VALUE (%.4f %.4f);\n",
+ -pac_width/2, -pac_width/2 - textsize*1.5);
+ printf("%s\n", Source_file);
+ }
+ }
+ return;
+}
+
+
+int device_exist(string dev_name) {
+ library(L) {
+ L.devicesets(DEV) {
+ if (DEV.name == dev_name) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+string makeSymbol_Device(string Libfile, int pin_layout, string pac_name, int use_pad_names, string pad_prefix) {
+ symbol_file = filesetext(Libfile, "~symbol.scr");
+ device_file = filesetext(Libfile, "~device.scr");
+ string partlib = "EDIT " + symbol_name + ".sym;\nGRID INCH 0.1 1;\n";
+ partlib += "CHANGE LENGTH SHORT;\n"; // 2010-05-25 new PIN legth
+ partlib += "CHANGE DIRECTION PAS;\n"; // ** default direction
+
+ string devicelib = "EDIT " + device_name + ".dev;\n";
+ devicelib += "GRID INCH 0.1 1 ON;\n";
+ devicelib += "PACKAGE " + pac_name + " '" + pac_variant_name + "';\n";
+ devicelib += "Technology '';\n";
+ if (device_exist(device_name)) return "Device " + device_name + "exist!\nPlease use a different name for tis device."; // 2008-11-07 check existing devices and return error
+ else {
+ // 2008-11-07 generate always description
+ sprintf(Source_file, "DESCRIPTION '%s%s
\\n\\\nAuto generated by %s %s \\n\\\nSource: %s';\n",
+ filesetext(filename(infile), ""), editMode, filename(argv[0]), Revision, filename(infile) );
+ devicelib += Source_file;
+ devicelib += "Prefix 'IC';\n";
+ devicelib += "Value Off;\n";
+ devicelib += "ADD " + symbol_name + " 'G$1' 0 NEXT (0 0);\n";
+ }
+ int i;
+ int index[];
+ string last_pin;
+ suffix_cnt = 0;
+ sort( n_pins, index, pins);
+ for (i = 0; i < n_pins; i++) {
+ if (last_pin != pins[index[i]]) {
+ last_pin = pins[index[i]];
+ suffix_cnt = 0;
+ }
+ else {
+ suffix_cnt++;
+ }
+ suffix[index[i]] = suffix_cnt;
+ }
+ real x = 0;
+ real y = 0;
+ real dx = 0;
+ real dy = -.1;
+ int terminal_i = 1;
+ int s2 = 0;
+ int s3 = 0;
+ int s4 = 0;
+ int rot = 0;
+ real spacer = .8;
+
+ if (pin_layout == k_stripe) {
+ s2 = (n_pins / maxStripeCnt) / 2;
+ s3 = maxStripeCnt / 2;
+ x = -1.0 * s2 + -0.2;
+ y = 0.1 * s3;
+ dx = 0.0;
+ dy = -0.1;
+ }
+ else if (pin_layout == k_quad) {
+ y = (.1 * n_pins / 4) + spacer;
+ s2 = (n_pins / 4) + 1;
+ s3 = (2 * n_pins / 4) + 1;
+ s4 = (3 * n_pins / 4) + 1;
+ }
+ else if (pin_layout == k_dual) {
+ y = .1 * n_pins / 2;
+ s2 = (n_pins / 2) + 1;
+ }
+ else if (pin_layout == k_dual2) {
+ y = .1 * n_pins / 2;
+ }
+ else {
+ y = .1 * n_pins;
+ }
+
+ for (i = 0; i < n_pins; i++) {
+ int pin_num = i + 1;
+ if (suffix[i]) {
+ sprintf( pin_names[i], "%s@%d", pins[i], suffix[i]);
+ pins[i] = pin_names[i];
+ }
+ string pin_name = pin_names[i];
+ string pad_name = "";
+
+ if (use_pad_names) {
+ if (use_pad_names == useBGA) pad_name = pad_names[i]; // use Padname as is for BGA
+ else if (use_pad_names == usePACwithPrefix) pad_name = pad_names[i]; // use Padname for existing Package with Prefix
+ devicelib += "CONNECT 'G$1." + pin_name + "' '" + pad_name + "';\n";
+ }
+ else {
+ string pin_num_str;
+ sprintf(pin_num_str, "%u", pin_num); // genberate padname by number
+ devicelib += "CONNECT 'G$1." + pin_name + "' '" + pad_prefix + pin_num_str + "';\n";
+ }
+
+ if (check_Coordinate(pin_name, x, y, "INCH", e_symbol)) {
+ string ck;
+ sprintf(ck, "Pin %s, coordinate out of range (%.4f %.4f)", pin_name, x, y);
+ return ck;
+ }
+
+ string x_str;
+ string y_str;
+ sprintf(x_str, "%.4f", round(x * 10) / 10); // set to 0.1 Inch Grid 2006-06-01
+ sprintf(y_str, "%.4f", round(y * 10) / 10);
+
+ partlib += "PIN '" + pin_name + "' " + Pin_Direc[i] + " (" + x_str + " " + y_str + ");\n";
+ if (rot > 0) partlib += "ROTATE (" + x_str + " " + y_str + ");\n";
+ if (rot > 1) partlib += "ROTATE (" + x_str + " " + y_str + ");\n";
+ if (rot > 2) partlib += "ROTATE (" + x_str + " " + y_str + ");\n";
+
+ x += dx;
+ y += dy;
+ terminal_i ++;
+
+ if (pin_layout == k_stripe) {
+ if (terminal_i > maxStripeCnt) { // 2008-12-03 correct counts
+ terminal_i = 1;
+ s2--;
+ x = -1.0 * s2 + -0.1; // PIN leght SHORT 2010-05-25, -0.2 for legth MIDDLE
+ y = 0.1 * s3;
+ }
+ }
+ else if (pin_layout == k_quad) {
+ if (terminal_i == s2) {
+ dy = 0;
+ dx = .1;
+ x = spacer + .1;
+ y = 0;
+ rot = 1;
+ }
+ else if (terminal_i == s3) {
+ dy = .1;
+ dx = 0;
+ x += spacer;
+ y = spacer + .1;
+ rot = 2;
+ }
+ else if (terminal_i == s4) {
+ dy = 0;
+ dx = -.1;
+ y += spacer;
+ x -= spacer + .1;
+ rot = 3;
+ }
+ }
+ else if (pin_layout == k_dual) {
+ if (terminal_i == s2) {
+ dy = .1;
+ dx = 0;
+ x = spacer * 3;
+ y = .1;
+ rot = 2;
+ }
+ }
+ else if (pin_layout == k_dual2) {
+ int terminal_row = (terminal_i - 1) / 2;
+ y = (.1 * n_pins / 2) - .1 * terminal_row;
+ if ((terminal_i % 2) == 1) {
+ x = 0;
+ rot = 0;
+ }
+ else {
+ x = spacer * 3;
+ rot = 2;
+ }
+ }
+ }
+
+ real left = .1; // 0.2 for PIN legth MIDDLE 2010-05-25
+ real bottom = 0;
+ real top = (.1 * n_pins) + .1;
+ real right = spacer * 1.5;
+
+ if (pin_layout == k_stripe) {
+ ; // no frame for this symbol
+ }
+ else if (pin_layout == k_quad) {
+ left = 0.1; // 0.2 for PIN legth MIDDLE 2010-05-25
+ bottom = 0.1; // 0.2 for PIN legth MIDDLE
+ top = (spacer * 2) + (.1 * n_pins / 4) - 0.0; // -0.1 for Pin legth MIDDLE
+ right = (spacer * 2) + (.1 * n_pins / 4) - 0.0; // -0.1 for Pin legth MIDDLE
+ }
+ else if ((pin_layout == k_dual) || (pin_layout == k_dual2)) {
+ top = (.1 * n_pins / 2) + .1;
+ right = (spacer * 3) - .1; // 0.2 for PIN legth MIDDLE 2010-05-25
+ }
+
+ real cx = ((right - left) / 2) + left - .1; // 0.2 for PIN legth MIDDLE 2010-05-25
+ real cy = ((top - bottom) / 2) + bottom;
+
+ if (pin_layout == k_single) {
+ cx = right - .4;
+ }
+
+ string left_str;
+ string bottom_str;
+ string top_str;
+ string right_str;
+ string movexy05 = "";
+ string name_x;
+ string name_y;
+ string value_x;
+ string value_y;
+
+ if (pin_layout == k_stripe) { // place >NAME and >VALUE in stripe symbol
+ s2 = (n_pins / maxStripeCnt) / 2;
+ s3 = maxStripeCnt / 2;
+ x = -1.0 * s2;
+ y = 0.1 * s3;
+
+ sprintf(name_x, "%.4f", x - 0.2);
+ sprintf(name_y, "%.4f", y + .2);
+ sprintf(value_x, "%.4f", x - 0.2);
+ sprintf(value_y, "%.4f", y + .1);
+ }
+ else { // set to 0.1 Inch Grid 2006-06-01
+ sprintf(left_str, "%.4f", round(left * 10) / 10);
+ sprintf(bottom_str, "%.4f", round(bottom * 10) / 10);
+ sprintf(top_str, "%.4f", round(top * 10) / 10);
+ sprintf(right_str, "%.4f", round(right * 10) / 10);
+ // ** move Origin to center **
+ sprintf(movexy05, "GROUP (-29.9 -29.9) (29.9 -29.9) (29.9 29.9) (-29.9 29.9) (>-29.9 -29.9);\nMOVE (>%.4f %.4f) (0 0);\n",
+ round(((left + right) / 2) * 10) / 10,
+ round(((bottom + top) / 2) * 10) / 10);
+ sprintf(name_x, "%.4f", round(cx * 10) / 10);
+ sprintf(name_y, "%.4f", round(cy * 10) / 10 + .05);
+ sprintf(value_x, "%.4f", round(cx * 10) / 10);
+ sprintf(value_y, "%.4f", round(cy * 10) / 10 - .1);
+ // place no frame on stripe symbol
+ partlib += "LAYER 94;\n";
+ // change wire width 10mil 2010-02-15
+ partlib += "WIRE 10mil (" + left_str + " " + bottom_str + ") (" + right_str + " " + bottom_str + ") (" + right_str + " " + top_str + ") (" + left_str + " " + top_str + ") (" + left_str + " " + bottom_str + ");\n";
+ }
+ partlib += "CHANGE SIZE .07;\n";
+ partlib += "LAYER 95;\n";
+ partlib += "TEXT \'>NAME\' (" + name_x + " " + name_y + ");\n";
+ partlib += "LAYER 96;\n";
+ partlib += "TEXT \'>VALUE\' (" + value_x + " " + value_y + ");\n";
+ partlib += "LAYER 94;\n";
+ partlib += movexy05;
+ partlib += "WINDOW FIT;\n";
+
+ output(symbol_file, "wtD") {
+ printf("%s", partlib);
+ }
+
+ output(device_file, "wtD") {
+ printf("%s", devicelib);
+ }
+ return "";
+}
+
+
+string viewPadname(string t, string pacname) { // 2008-11-07 return 0 or error, Cancel = check padname
+ int sel;
+ if (t) {
+ dlgDialog("Make Device Package") {
+ dlgLabel("Pads not found in parsed list.");
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgLabel(pacname + ".PAC");
+ dlgTextView(t);
+ }
+ dlgVBoxLayout {
+ dlgLabel("Parsed from text");
+ dlgListView("Pads", pad_names, sel);
+ }
+ }
+ if (packageparameter_accept) {
+ dlgLabel(" Checke Pad-Name if Prefix used.");
+ dlgLabel(" Possibly delete PAD Prefix in BSDL-Pad Name.");
+ dlgLabel(" Use Text Options [Rename PAD] to rename.");
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") { dlgAccept(); if (t) t = "Check pad name(s) in package " + pacname; }
+ dlgPushButton("-Cancel") { dlgReject(); return "Check pad name(s) in package " + pacname; }
+ dlgSpacing(20);
+ dlgLabel(" Package is a BGA ");
+ dlgPushButton("Accept") { dlgAccept(); t = ""; }
+ dlgStretch(1);
+ }
+ };
+ }
+ return t;
+}
+
+
+string check_Padname(string name) {
+ for (int i = 0; i < n_pins; i++) {
+ if (name == pad_names[i]) {
+ name = "";
+ break;
+ }
+ }
+ if (name) name += "\n";
+ return name;
+}
+
+
+string getPackagePadCount(string pac_name) {
+ checkPadname = "";
+ int pcount = 0;
+ string s;
+ sprintf(s, " NOT found");
+ library(L) {
+ L.packages(PAC) {
+ if (PAC.name == pac_name) {
+ status("count pads " + pac_name);
+ PAC.contacts(C) {
+ checkPadname += check_Padname(C.name);
+ used_pad_number[pcount] = C.name; // 2008-11-07
+ pcount++;
+ }
+ sprintf(s, "%d Contacts", pcount);
+ break;
+ }
+ }
+ }
+ return s;
+}
+
+
+// 2008-11-07 if make package with bsdl.
+// Check used all pad-names in list with on generated Package.
+// Vergleiche padnamen des bsdl file mit generierten padnamen aus package.
+// Alle Pad-Namen in der Liste müssen im Package vorkommen.
+//
+string check_pin_pad_list(int n, int p) {
+ status("check pads in used package");
+ string ti = tinfo;
+ tinfo = "Please wait, check pad names!";
+ dlgRedisplay();
+ string tp;
+ int x = 0;
+ for (x = 0; x < n; x++) {
+ int notfound = 1;
+ for (int i = 0; i < p; i++) {
+ if (used_pad_number[i] == pad_names[x]) {
+ notfound = 0;
+ break;
+ }
+ }
+ if (notfound) tp += pad_names[x]+"\n";
+ }
+ tinfo = ti;
+ dlgRedisplay();
+ if (tp) return "Pads not found in Package\nCheck pad name in parsed list by 'Text Options'!\n"+tp;
+ return tp;
+}
+
+
+int check_exist_sym(string symname) {
+ int exist = 0;
+ library(L) {
+ L.symbols(SYM) {
+ if (SYM.name == symname) return 1;
+ }
+ }
+ return 0;
+}
+
+
+int getSymbolPinCount(string sym_name) {
+ int scount = -1;
+ library(L) {
+ L.symbols(SYM) {
+ if (SYM.name == sym_name) {
+ SYM.pins(P) scount++;
+ scount++;
+ break;
+ }
+ }
+ }
+ return scount;
+}
+
+
+string getPackagePadPrefix(string pac_name) {
+ library(L) {
+ L.packages(PAC) {
+ if (PAC.name == pac_name) {
+ PAC.contacts(C) {
+ string pad_name = C.name;
+ int i = strstr(pad_name, "1");
+ if (i != -1) {
+ string prefix = strsub(pad_name, 0, i);
+ return prefix;
+ }
+ }
+ }
+ }
+ }
+ return "P$";
+}
+
+
+// ** collect Packages **
+void coll_packages(void) {
+ packages[0] = " ";
+ n_packages = 1;
+ library(L) {
+ L.packages(PAC) {
+ packages[n_packages++] = PAC.name;
+ }
+ }
+ return;
+}
+
+
+// ***** change n.ts character to new character *****
+void change_char_text(char text_char, char to_char, int counter) {
+ int cc;
+ int cnt = 0;
+ for ( int n = 0; n < strlen(text); n ++) {
+ if (text[n] == text_char) {
+ if (cnt == counter) {
+ text[n] = to_char;
+ cc++;
+ cnt = 0;
+ }
+ else if (counter) cnt++;
+ }
+ }
+ sprintf(tinfo, "%d characters changed.", cc);
+ return;
+}
+
+
+string check_space(string s) {
+ int a;
+ for (int i = 0; i < strlen(s); i++) {
+ a = (isgraph(s[i]));
+ if (a) break;
+ }
+ if (a) return s;
+ else return "";
+}
+
+
+
+void delete_x_line(int start, int x) {
+ if (x < 2) {
+ dlgMessageBox("!The value of the counter must be greater 1", "Ok");
+ tinfo = "It is absurd to delete all lines! Check the value of x. line";
+ return;
+ }
+ if (start > 1) start--; // 2009-02-18 counts from zero
+ string xt[];
+ int cntst = strsplit(xt, text, '\n');
+ text = "";
+ int cdel = 0;
+ for (int s = start; s < cntst; s+=x) {
+ xt[s] = "";
+ }
+ for (int n = 0; n < cntst; n++) {
+ if (xt[n]) text += xt[n] + "\n";
+ else cdel++;
+ }
+ text[strlen(text)-1] = 0;
+ if (x > 2) sprintf(tinfo, "%d %d. lines deleted", cdel, x);
+ else sprintf(tinfo, "%d second lines deleted", cdel);
+ return;
+}
+
+
+void delete_empty_lines(void) {
+ if(!text) {
+ tinfo = "List is empty!";
+ return;
+ }
+ string st[];
+ int cntst = strsplit(st, text, '\n');
+ text = "";
+ int cc = 0;
+ for (int n = 0; n < cntst; n++) {
+ st[n] = check_space(st[n]);
+ if (st[n]) text += st[n] + "\n";
+ else cc++;
+ }
+ text[strlen(text)-1] = 0;
+ sprintf(tinfo, "%d empty lines deleted", cc);
+ return;
+}
+
+
+void delete_column(int del_column) { // 2008-04-02
+ int cntdelcol = 0;
+ if (!text) {
+ tinfo = "List is empty!";
+ return;
+ }
+ if (!del_column) {
+ tinfo = "First set the number of column to delete!";
+ return;
+ }
+ string lines[];
+ string columns[];
+ int cntl = strsplit(lines, text, '\n');
+ text = "";
+ for (int n = 0; n < cntl; n++) {
+ int cntc = strsplit(columns, lines[n], Word_separator);
+ if (cntc > del_column) cntdelcol++;
+ columns[del_column -1] = "";
+ lines[n] = "";
+ for (int c = 0; c < cntc; c++) {
+ lines[n] += columns[c];
+ if (c < cntc -1 && columns[c]) lines[n] += " ";
+ }
+ text += lines[n] += "\n";
+ }
+ tinfo = ""; // 2011-05-23
+ if (cntdelcol) {
+ sprintf(tinfo, "%d column deleted", cntdelcol);
+ }
+ return;
+}
+
+
+void sorting_pad(int cnt) {
+ numeric string sort_pad[], sort_pin[], sort_dir[];
+ int index[], i;
+ for (i = 0; i < cnt; i++) {
+ pins[i] = pads[i];
+ sort_pin[i] = pin_names[i];
+ sort_pad[i] = pad_names[i];
+ sort_dir[i] = Pin_Direc[i];
+ }
+ sort(cnt, index, sort_pad, sort_pin);
+ for (i = 0; i < cnt; i++) {
+ pin_names[i] = sort_pin[index[i]];
+ pad_names[i] = sort_pad[index[i]];
+ Pin_Direc[i] = sort_dir[index[i]];
+ pins[i] = pin_names[i];
+ pads[i] = pin_names[i];
+ }
+ return;
+}
+
+
+void sorting_pin(int cnt) {
+ numeric string sort_pad[], sort_pin[], sort_dir[];
+ int index[], i;
+ for (i = 0; i < cnt; i++) {
+ pins[i] = pads[i];
+ sort_pin[i] = pin_names[i];
+ sort_pad[i] = pad_names[i];
+ sort_dir[i] = Pin_Direc[i];
+ }
+ sort(cnt, index, sort_pin, sort_pad);
+ for (i = 0; i < cnt; i++) {
+ pin_names[i] = sort_pin[index[i]];
+ pad_names[i] = sort_pad[index[i]];
+ Pin_Direc[i] = sort_dir[index[i]];
+ pins[i] = pin_names[i];
+ pads[i] = pin_names[i];
+ }
+ return;
+}
+
+
+string check_pad_sorting(int cnt, int mkpac) { // 2009-02-18
+ int sortflagPAD = 0;
+ string RESULT = "";
+ if (!mkpac && use_pad_names == useBGA) sortflagPAD = 1; // option for use existing BGA 2009-03-09
+
+ else if (!mkpac && package_name) {
+ for (int n1 = 1; n1 <= cnt; n1++) {
+ int found = 0;
+ for (int n = 0; n < cnt; n++) {
+ if (strtol(pad_names[n]) == n1) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ sortflagPAD++;
+ string h;
+ sprintf(h, "Missing Pad number %d !", n1); // 2011-05-23
+ if (dlgMessageBox(h, "OK", "Cancel") != 0) return h;
+ }
+ }
+ if (sortflagPAD) {
+ dlgDialog("Make PAC/SYM/DEV") {
+ dlgLabel("To generate a correct symbol by count pad name, the list must sorted by pad number!");
+ dlgLabel("Check if Pin/Pad/Direction list sorted by PADs?");
+ dlgHBoxLayout {
+ dlgPushButton("Yes/Ignore") { dlgAccept(); RESULT = ""; }
+ dlgPushButton("Sort") {
+ sorting_pad(cnt);
+ gen_viewlist(cnt);
+ dlgAccept();
+ RESULT = "Check PAD list";
+ }
+ dlgPushButton("Cancel") { dlgReject(); RESULT = "CANCEL"; }
+ }
+ };
+ }
+ }
+ return RESULT;
+}
+
+
+string clear_z(string s) { // delete leading zero
+ parsed_pins = s;
+ if (isalpha(s[0]) && isalpha(s[1]) && s[2] == '0') s = strsub(s, 0, 2) + strsub(s, 3);
+ else if (isalpha(s[0]) && s[1] == '0') s = strsub(s, 0, 1) + strsub(s, 2);
+ else if (s[0] == '0') s = strsub(s, 1);
+ return s;
+}
+
+
+void clear_leading_z(int cnt) {
+ for (int i = 0; i < cnt; i++) {
+ pad_names[i] = clear_z(pad_names[i]);
+ }
+ gen_viewlist(cnt);
+ parsed_pins = "Finsh clear leading zeros";
+ return;
+}
+
+
+int del_double_pad(int cnt) { // 2008-04-02 delete double pad names if parsed from text
+ sorting_pad(cnt);
+ string npad = "";
+ string npin_names[];
+ string npad_names[];
+ string nPin_Direc[];
+
+ int newcnt = 0;
+ for (int i = 0; i < cnt; i++) {
+ if (npad == pad_names[i]) {
+ ; // is double
+ }
+ else {
+ npad = pad_names[i];
+ npin_names[newcnt] = pin_names[i];
+ npad_names[newcnt] = pad_names[i];
+ nPin_Direc[newcnt] = Pin_Direc[i];
+ newcnt++;
+ }
+ }
+ sprintf(parsed_pins, "Finsh delete double (%d) pad name, new count %d", cnt-newcnt, newcnt);
+ for (int n = 0; n < newcnt; n++) {
+ pin_names[n] = npin_names[n];
+ pad_names[n] = npad_names[n];
+ Pin_Direc[n] = nPin_Direc[n];
+ }
+ cnt = newcnt;
+ gen_viewlist(cnt);
+ return cnt;
+}
+
+
+// 2008-11-07 rename pad in parsed list
+void rename_pad(int cnt, string search, string replace) {
+ int cntrenamed = 0;
+ if (!search) {
+ dlgMessageBox("First define search string! See Text Option: [ Replace ] character string ..... with ....", "OK");
+ return;
+ }
+ if (search == replace) {
+ dlgMessageBox("Search string = Replace string, please change! See option: [ Replace ] character string .... with .....", "OK");
+ return;
+ }
+ for ( int n = 0; n < cnt; n++) {
+ int pos = strstr(pad_names[n], search);
+ if (pos >= 0) {
+ pad_names[n] = strsub(pad_names[n], 0, pos) + replace + strsub(pad_names[n], pos+strlen(search) );
+ cntrenamed++;
+ }
+ }
+ gen_viewlist(cnt);
+ sprintf(parsed_pins, "%d pads renamed", cntrenamed);
+ return;
+}
+
+
+// 2011-04-01 rename pin in parsed list
+void rename_pin(int cnt, string search, string replace) {
+ int cntrenamed = 0;
+ if (!search) {
+ dlgMessageBox("First define search string! See Text Option: [ Replace ] character string ..... with ....", "OK");
+ return;
+ }
+ if (search == replace) {
+ dlgMessageBox("Search string = Replace string, please change! See option: [ Replace ] character string .... with .....", "OK");
+ return;
+ }
+ for ( int n = 0; n < cnt; n++) {
+ int pos = strstr(pin_names[n], search);
+ if (pos >= 0) {
+ pin_names[n] = strsub(pin_names[n], 0, pos) + replace + strsub(pin_names[n], pos+strlen(search) );
+ cntrenamed++;
+ }
+ }
+ gen_viewlist(cnt);
+ sprintf(parsed_pins, "%d pins renamed", cntrenamed);
+ return;
+}
+
+
+// 2008-07-03
+void number_pads(int cnt) {
+ if (is_bsdl) { // 2011-04-01
+ dlgMessageBox("Do not numbering pads if used a BSDL file", "OK");
+ return;
+ }
+ for ( int n = 0; n < cnt; n++) {
+ sprintf(pad_names[n], "%d", n+1);
+ }
+ gen_viewlist(cnt);
+ return;
+}
+
+
+// 2008-07-03
+void set_Pin_Direction(int cnt) {
+ int setdir = 0;
+ dlgDialog("Set PIN-Directon") {
+ dlgHBoxLayout {
+ dlgGroup("Direction") {
+ dlgRadioButton("NC", setdir);
+ dlgRadioButton("IN", setdir);
+ dlgRadioButton("OUT", setdir);
+ dlgRadioButton("IO", setdir); // 2011-09-20 V6 use IO
+ dlgRadioButton("OC", setdir);
+ dlgRadioButton("PWR", setdir);
+ dlgRadioButton("PAS", setdir);
+ dlgRadioButton("HIZ", setdir);
+ dlgRadioButton("SUP", setdir);
+ }
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgPushButton("-Cancel") { dlgReject(); return; }
+ dlgStretch(1);
+ }
+ };
+ for ( int n = 0; n < cnt; n++) {
+ sprintf(Pin_Direc[n], "%s", Pin_Dir[setdir]);
+ }
+ gen_viewlist(cnt);
+ return;
+}
+
+
+string ch_dir(string dir) {
+ string s[];
+ strsplit(s, dir, '\t');
+ if (!s[1]) s[1] = s[0];
+ int psel = -1;
+ dlgDialog("New Direction") {
+ dlgHBoxLayout {
+ dlgLabel(s[0]);
+ dlgLabel(" &new ");
+ dlgListView("Dir.", Pin_Dir, psel) { s[1] = Pin_Dir[psel]; dlgAccept(); } // 2011-05-23
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ dlgStretch(1);
+ }
+ };
+ return s[0]+"\t"+s[1];
+}
+
+
+// ** change direction of pin in parsed list ** 2008-04-02
+void change_dir(int cnt) {
+ string ndir[];
+ int cntdirection = 0;
+ int found = 0;
+ for (int n = 0; n < cnt; n++) {
+ found = 0;
+ for (int i = 0; i < cntdirection; i++) {
+ if (ndir[i] == Pin_Direc[n]) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ ndir[cntdirection] = Pin_Direc[n];
+ cntdirection++;
+ }
+ }
+ string info;
+ sprintf(info, "found %d directions", cntdirection);
+ int sel;
+ for (int i = 0; i < cntdirection; i++) {
+ ndir[i] += "\t" + ndir[i];
+ }
+ int Result = dlgDialog("Change Direction") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgLabel(info);
+ dlgListView("Direction\tnew", ndir, sel) ndir[sel] = strupr(ch_dir(ndir[sel])); // 2011-05-23
+ }
+ dlgLabel(Existdir); // 2011-05-23
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ dlgStretch(1);
+ }
+ };
+ if (!Result) return;
+ for (n = 0; n < cnt; n++) {
+ string s[];
+ for (int i = 0; i < cntdirection; i++) {
+ strsplit(s, ndir[i], '\t');
+ if (Pin_Direc[n] == s[0]) {
+ Pin_Direc[n] = s[1];
+ break;
+ }
+ }
+ }
+ gen_viewlist(cnt);
+ return;
+}
+
+
+// *** generate package for NOT BGA ***
+void gen_package(string PacName) {
+ real mpad_stand_out = pad_stand_out; // 2005-12-01 save parameter for display
+ real mypad_length = ypad_length;
+ real mxpad_length = xpad_length;
+ real center_offset;
+ int middle = cnt_side % 2;
+ if (middle) {
+ center_offset = cnt_side / 2 * basic_pad_grid;
+ }
+ else {
+ center_offset = cnt_side / 2 * basic_pad_grid - basic_pad_grid / 2;
+ }
+ real pin_length = (xA_pac - xD_pac) / 2;
+
+ string h;
+ real k; // koordinate for Pad line
+ real xcoord, ycoord;
+ string SMDdirection;
+ string pad_rect;
+ int padnumber = 1;
+ sprintf(h, "#2010-09-24\nEDIT %s.PAC;\n", PacName); // 2005-11-03
+ paccmd += h;
+ sprintf(h, "GRID %s %.4f ON;\n", genpac_grid, grid_val/2); // 2008-11-07 set actual grid to generate package
+ paccmd += h;
+ sprintf(h, "SET WIRE_BEND 2;\n");
+ paccmd += h;
+ sprintf(h, "CHANGE ROUNDNESS %.0f;\n", roundness_restring);
+ paccmd += h;
+ sprintf(h, "CHANGE LAYER 1;\n");
+ paccmd += h;
+
+
+ // ** make SMD or PAD ** 2005-12-01
+ if (smd_pad) {
+ pad_stand_out = 0; // no offset from mechanical-pin to pad-drill
+ ypad_length = 0;
+ sprintf(h, "CHANGE DRILL %.4f;\n", xpad_length); // PAD drill diameter
+ paccmd += h;
+ sprintf(h, "CHANGE SHAPE %s;\n", PadShape[pad_shape]);
+ paccmd += h;
+ sprintf(h, "CHANGE DIAMETER %.4f;\n", xpad_length + roundness_restring);
+ paccmd += h;
+ xpad_length = 0; // 2005-12-01
+ }
+ else {
+ sprintf(h, "CHANGE SMD %.4f %.4f;\n", SMD_diameter, SMD_diameter);
+ paccmd += h;
+ }
+
+ switch (pad_layout) { // check Package PAD placement
+ case 0 : // ### quad package with Pin 1 on TOP of LEFT side (corner) ###
+ for (int q = 0; q < 4; q++) {
+ for (int n = 0; n < cnt_side; n++) {
+ k = n * basic_pad_grid - center_offset;
+ switch(q) {
+ case 0 : // 1. quadrant 1.-Pad TOP of LEFT side
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ ycoord = k * -1;
+ xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ -xA_pac/2, ycoord - pad_width/2,
+ -xA_pac/2 + pin_length, ycoord + pad_width/2
+ );
+ break;
+
+ case 1 : // 2. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length);
+ xcoord = k;
+ ycoord = -xA_pac / 2 - pad_stand_out + xpad_length/2;
+ pin_length = (yA_pac - yD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xcoord - pad_width/2, -yA_pac/2,
+ xcoord + pad_width/2, -yA_pac/2 + pin_length
+ );
+ break;
+
+ case 2 : // 3. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ xcoord = xA_pac / 2 + pad_stand_out - xpad_length/2;
+ ycoord = k;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xA_pac/2, ycoord - pad_width/2,
+ xA_pac/2 - pin_length, ycoord + pad_width/2
+ );
+ break;
+
+ case 3 : // 4. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length);
+ xcoord = k * -1;
+ ycoord = xA_pac / 2 + pad_stand_out - xpad_length/2;
+ pin_length = (yA_pac - yD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xcoord - pad_width/2, yA_pac/2,
+ xcoord + pad_width/2, yA_pac/2 - pin_length
+ );
+ break;
+
+ }
+
+ if (smd_pad) { // 2005-12-01
+ sprintf(h, "PAD '%d' (%.4f %.4f);\n", padnumber, xcoord, ycoord);
+ }
+ else {
+ sprintf(h, "SMD %s '%d' (%.4f %.4f);\n", SMDdirection, padnumber, xcoord, ycoord);
+ }
+ paccmd += h;
+ paccmd += pad_rect;
+ sprintf(used_pad_number[padnumber], "%d", padnumber); // 2008-11-07 for check package pad names
+ padnumber++;
+ }
+ }
+ sprintf(h, "LAYER 21;\nWIRE .2032 (%.4f %.4f) (%.4f %.4f);\n",
+ -xD_pac/2 + package_wire_width,
+ yD_pac/2 - mark_length,
+ -xD_pac/2 + mark_length,
+ yD_pac/2 - package_wire_width
+ );
+ paccmd += h;
+ break;
+
+ case 1 : // ### quad package with Pin 1 on MIDDLE of LEFT side ###
+ for (int qm = 0; qm < 5; qm++) {
+ for (int n = 0; n < cnt_side; n++) {
+ k = n * basic_pad_grid - center_offset;
+ switch(qm) {
+ case 0 : // 1. quadrant 1.-Pad MIDDLE of LEFT side
+ if (n >= cnt_side/2 - 0.5) {
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2;
+ ycoord = k * -1;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ -xA_pac/2, ycoord - pad_width/2,
+ -xA_pac/2 + pin_length, ycoord + pad_width/2
+ );
+ }
+ else SMDdirection = ""; // ** clear, do not genearate line **
+ break;
+
+ case 1 : // 2. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length);
+ xcoord = k;
+ ycoord = -xA_pac / 2 - pad_stand_out + xpad_length/2;
+ pin_length = (yA_pac - yD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xcoord - pad_width/2, -yA_pac/2,
+ xcoord + pad_width/2, -yA_pac/2 + pin_length
+ );
+ break;
+
+ case 2 : // 3. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ xcoord = xA_pac / 2 + pad_stand_out - xpad_length/2;
+ ycoord = k;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xA_pac/2, ycoord - pad_width/2,
+ xA_pac/2 - pin_length, ycoord + pad_width/2
+ );
+ break;
+
+ case 3 : // 4. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length);
+ xcoord = k * -1;
+ ycoord = yA_pac / 2 + pad_stand_out - xpad_length/2;
+ pin_length = (yA_pac - yD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xcoord - pad_width/2, yA_pac/2,
+ xcoord + pad_width/2, yA_pac/2 - pin_length
+ );
+ break;
+
+ case 4 : // 1. quadrant pad right side to middle
+ if (n < cnt_side/2 - 0.5) {
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ ycoord = k * -1;
+ xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ -yA_pac/2, ycoord - pad_width/2,
+ -yA_pac/2 + pin_length, ycoord + pad_width/2
+ );
+ }
+ else SMDdirection = ""; // ** clear, do not genearate line **
+ break;
+ }
+ if (SMDdirection) {
+ if (smd_pad) { // 2005-12-01
+ sprintf(h, "PAD '%d' (%.4f %.4f);\n", padnumber, xcoord, ycoord);
+ }
+ else {
+ sprintf(h, "SMD %s '%d' (%.4f %.4f);\n", SMDdirection, padnumber, xcoord, ycoord);
+ }
+ paccmd += h;
+ paccmd += pad_rect;
+ sprintf(used_pad_number[padnumber], "%d", padnumber); // 2008-11-07 for check package pad names
+ padnumber++;
+ }
+ }
+ }
+ sprintf(h, "LAYER 21;\nCIRCLE .2032 (%.4f 0) (%.4f 0);\n",
+ -xD_pac/2 + xpad_length + mark_length/2,
+ -xD_pac/2 + xpad_length + mark_length
+ );
+ paccmd += h;
+ break;
+
+ case 2 : // dual in line package
+ for (int qd = 0; qd < 2; qd++) {
+ for (int n = 0; n < cnt_side; n++) {
+ k = n * basic_pad_grid - center_offset;
+ switch(qd) {
+ case 0 : // 1. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ ycoord = k * -1;
+ xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ -xA_pac/2, ycoord - pad_width/2,
+ -xA_pac/2 + pin_length, ycoord + pad_width/2
+ );
+ break;
+
+ case 1 : // 2. quadrant
+ sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length);
+ xcoord = xA_pac / 2 + pad_stand_out - xpad_length/2;
+ ycoord = k;
+ pin_length = (xA_pac - xD_pac) / 2;
+ sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n",
+ xA_pac/2, ycoord - pad_width/2,
+ xA_pac/2 - pin_length, ycoord + pad_width/2
+ );
+ break;
+ }
+ if (smd_pad) { // 2005-12-01
+ sprintf(h, "PAD '%d' (%.4f %.4f);\n", padnumber, xcoord, ycoord);
+ }
+ else {
+ sprintf(h, "SMD %s '%d' (%.4f %.4f);\n", SMDdirection, padnumber, xcoord, ycoord);
+ }
+ paccmd += h;
+ paccmd += pad_rect;
+ sprintf(used_pad_number[padnumber], "%d", padnumber); // 2008-11-07 for check package pad names
+ padnumber++;
+ }
+ }
+ sprintf(h, "LAYER 21;\nARC CCW .2032 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n",
+ -mark_length,
+ yD_pac/2 - package_wire_width,
+ mark_length,
+ yD_pac/2 - package_wire_width,
+ mark_length,
+ yD_pac/2 - package_wire_width
+ );
+ paccmd += h;
+ break;
+ }
+
+ sprintf(h, "SET WIRE_BEND 0;\n");
+ paccmd += h;
+ sprintf(h, "CHANGE LAYER 21;\n");
+ paccmd += h;
+ sprintf(h, "WIRE .2032 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n",
+ -xD_pac /2 + package_wire_width,
+ -yD_pac /2 + package_wire_width,
+ xD_pac /2 - package_wire_width,
+ yD_pac /2 - package_wire_width,
+ -xD_pac /2 + package_wire_width,
+ -yD_pac /2 + package_wire_width
+ );
+ paccmd += h;
+ // mark edge on pin 1
+ sprintf(h, "SET WIRE_BEND 2;\n");
+ paccmd += h;
+ sprintf(h, "CHANGE SIZE %.2f;\n", textsize);
+ paccmd += h;
+ sprintf(h, "CHANGE LAYER 25;\n");
+ paccmd += h;
+ sprintf(h, "TEXT >NAME (%.4f %.4f);\n",
+ -xA_pac/2, yA_pac/2 + textsize*0.5);
+ paccmd += h;
+ sprintf(h, "CHANGE LAYER 27;\n");
+ paccmd += h;
+ sprintf(h, "TEXT >VALUE (%.4f %.4f);\n",
+ -xA_pac/2, -yA_pac/2 - textsize*1.5);
+ paccmd += h;
+ sprintf(h, "DESCRIPTION '%s
Place Package in BRD or delete Device in SCH";
+ else Error += "Place Device in SCH or delete Package in BRD!";
+ }
+ int Result = dlgDialog("Make Value Consistent") {
+ int sel_nf, sell = -1, ssort = -2 ,dsl = 1 , psl = 1;
+ dlgHBoxLayout {
+ dlgGridLayout {
+ if (Error) {
+ dlgCell( 0, 0) {
+ dlgLabel(Error);
+ }
+ if (cnt_nf) {
+ dlgCell( 0, 1) {
+ dlgVBoxLayout {
+ dlgLabel("To many Devices respectively Elements in Editor, see list.");
+ dlgLabel("&For show selected Device/Element, double-click in list");
+ dlgListView("Name\tValue\tPackage\tSheet\tEditor", notfound, sel_nf) cmd_exit(notfound[sel_nf]);
+ }
+ }
+ }
+ }
+ else {
+ if (board) {
+ if (cnt_SCHempty) {
+ dlgCell( 1, 0) {
+ dlgVBoxLayout {
+ dlgLabel("Do not use empty values when use this ULP!");
+ dlgLabel(" First set VALUE in SCHEMATIC");
+ dlgLabel(" (double-click in list)");
+ dlgStretch(1);
+ }
+ }
+ dlgCell( 1, 1) {
+ dlgVBoxLayout {
+ string evSch; sprintf(evSch, "%d empty &Values in Schematic!", cnt_SCHempty);
+ dlgLabel(evSch);
+ dlgListView("NAME\tValue in BRD", emptySchList, sell, ssort) setVal(emptySchList[sell]);
+ }
+ }
+ }
+ }
+ if (schematic) {
+ if (cnt_BRDempty) {
+ dlgCell( 1, 0) {
+ dlgVBoxLayout {
+ dlgLabel("Do not use empty values when use this ULP!");
+ dlgLabel(" First set VALUE in BOARD");
+ dlgLabel(" (double-click in list)");
+ dlgStretch(1);
+ }
+ }
+ dlgCell( 1, 1) {
+ dlgVBoxLayout {
+ string evBrd; sprintf(evBrd, "%d empty &Values in Board!", cnt_BRDempty);
+ dlgLabel(evBrd);
+ dlgListView("Name\tValue in SCH", emptyBrdList, sell, ssort) setVal(emptyBrdList[sell]);
+ }
+ }
+ }
+ }
+ }
+
+ dlgCell( 1, 2) {
+ dlgHBoxLayout {
+ dlgSpacing(12);
+ dlgPushButton("Show Device and Package without Contacts") show_no_contact();
+ }
+ }
+ }
+ dlgStretch(1);
+ }
+ if (!command) {
+ dlgSpacing(8);
+ dlgLabel("VALUES are consistent");
+ }
+
+ dlgLabel("");
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgLabel(InfoSch);
+ dlgListView("Name\tValue\tPackage", DeviceList, devsel, dsl);
+ }
+ dlgVBoxLayout {
+ dlgLabel(InfoBrd);
+ dlgListView("Name\tValue\tPackage", ElementList, pacsel, psl);
+ }
+ }
+ dlgHBoxLayout {
+ if (!Error && !cnt_SCHempty && !cnt_BRDempty) {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ }
+ else {
+ dlgPushButton("OK") dlgReject();
+ dlgPushButton("Do it") dlgAccept(); // 2010-01-22
+ }
+ dlgStretch(1);
+ dlgLabel(usage);
+ dlgStretch(1);
+ dlgLabel("Version " + Version);
+ }
+ };
+ if (!Result) exit(0);
+ if (!command) exit(0);
+ }
+
+ // ****** show script ******
+// int ssel, bsel, dsel;
+ int Result = dlgDialog("Make VALUE consistent") {
+ dlgHBoxLayout {
+ if (command) {
+ dlgVBoxLayout {
+ dlgLabel("Change values in " + argv[1]);
+ dlgLabel("Command");
+ dlgTextEdit(command);
+ }
+ }
+ else {
+ dlgVBoxLayout {
+ dlgLabel("Values are consistent");
+ }
+ }
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-Cancel") dlgReject();
+ dlgStretch(1);
+ dlgLabel(" Version " + Version);
+ }
+ };
+ if (Result) {
+ if (command) {
+ string scriptfile = filesetext(readfile, "~.scr");
+ output(scriptfile, "wtD") printf("%s",command);
+ exit("script '" + scriptfile + "';ERC\n");
+ }
+ }
+ exit (0);
+}
+
+
+int noexist(string name, int cnt) {
+ int is = 1;
+ for (int n = 0; n < cnt; n++) {
+ if (s_name[n] == name) {
+ is = 0;
+ break;
+ }
+ }
+ return is;
+}
+
+
+// ### Main ###
+runcount = strtol(argv[2]);
+if (runcount == 1) {
+ string cmd;
+ lines_cnt = fileread( lines, readfile);
+ if (board) {
+ int rnp = fileread(DeviceList_no_pac, readfile_no_pac);
+ }
+ if (schematic) {
+ int rop = fileread(ElementList_only_pac, readfile_only_pac);
+ }
+}
+
+
+// *** Board ***
+if (board) {
+ string b_name[], b_value[], b_package[];
+ string b_name_only_pac[], b_value_only_pac[], b_package_only_pac[];
+
+ board(B) {
+ B.elements(E) {
+ int PACcontact = 0;
+ E.package.contacts(C) {
+ b_name[brd_cnt] = E.name;
+ b_value[brd_cnt] = E.value;
+ b_package[brd_cnt] = E.package.name;
+ brd_cnt++;
+ PACcontact++;
+ break;
+ }
+ if (!PACcontact) {
+ b_name_only_pac[brd_cnt_only_pac] = E.name;
+ b_value_only_pac[brd_cnt_only_pac] = E.value;
+ b_package_only_pac[brd_cnt_only_pac] = E.package.name;
+ brd_cnt_only_pac++;
+ }
+ }
+
+ sort (brd_cnt, brd_Index, b_value, b_name);
+ for (n = 0; n < brd_cnt; n++) {
+ brd_name[n] = b_name[brd_Index[n]] ;
+ brd_value[n] = b_value[brd_Index[n]] ;
+ brd_package[n] = b_package[brd_Index[n]];
+ sprintf(ElementList[n], "%s\t%s\t%s\t0", brd_name[n], brd_value[n], brd_package[n] );
+ }
+ sort (brd_cnt_only_pac, brd_Index_only_pac, b_value_only_pac, b_name_only_pac);
+ for (n = 0; n < brd_cnt_only_pac; n++) {
+ brd_name_only_pac[n] = b_name_only_pac[brd_Index_only_pac[n]] ;
+ brd_value_only_pac[n] = b_value_only_pac[brd_Index_only_pac[n]] ;
+ brd_package_only_pac[n] = b_package_only_pac[brd_Index_only_pac[n]];
+ sprintf(ElementList_only_pac[n], "%s\t%s\t%s", brd_name_only_pac[n], brd_value_only_pac[n], brd_package_only_pac[n] );
+ }
+
+ if (runcount < 1) {
+ output(readfile, "wtD") {
+ for(int x = 0; x < brd_cnt; x++) {
+ printf("%s\t%s\t%s\t0\n", brd_name[x], brd_value[x], brd_package[x] );
+ }
+ }
+ output(readfile_only_pac, "wtD") {
+ for(int x = 0; x < brd_cnt_only_pac; x++) {
+ printf("%s\t%s\t%s\n", brd_name_only_pac[x], brd_value_only_pac[x], brd_package_only_pac[x] );
+ }
+ }
+ runcount++;
+ string cmd;
+ sprintf( cmd, "edit '%s';\n run '%s' SCH %d;\n", filesetext(B.name, ".sch"), argv[0], runcount );
+ exit(cmd);
+ }
+ sch_cnt = lines_cnt;
+ string s[];
+ for (n = 0; n < sch_cnt; n++) {
+ strsplit(s, lines[n], '\t');
+ sch_name[n] = s[0];
+ sch_value[n] = s[1];
+ sch_package[n] = s[2];
+ sch_sheet[n] = strtol(s[3]);
+ sprintf(DeviceList[n], "%s\t%s\t%s\t%d", sch_name[n] , sch_value[n], sch_package[n], sch_sheet[n] );
+ }
+ }
+ menue();
+}
+
+// *** Schematic ***
+if (schematic) {
+ string s_value[], s_package[];
+ int s_sheet[];
+ string s_name_no_pac[];
+ string s_value_no_pac[];
+ string s_package_no_pac[];
+ int s_sheet_no_pac[];
+
+ schematic(S) {
+ S.sheets(SH) {
+ SH.parts(PA) {
+ if (PA.device.package) {
+ int PACcontact = 0;
+ PA.device.package.contacts(C) {
+ PACcontact++;
+ break;
+ }
+ if (PACcontact) {
+ if (noexist(PA.name, sch_cnt)) {
+ s_name[sch_cnt] = PA.name;
+ s_value[sch_cnt] = PA.value;
+ s_package[sch_cnt] = PA.device.package.name;
+ PA.instances(IN) { // Gate
+ if (IN.sheet) {
+ s_sheet[sch_cnt] = IN.sheet;
+ sch_cnt++;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ s_name_no_pac[sch_cnt_no_pac] = PA.name;
+ s_value_no_pac[sch_cnt_no_pac] = PA.value;
+ s_package_no_pac[sch_cnt_no_pac] = PA.device.package.name;
+ PA.instances(IN) { // Gate
+ if (IN.sheet) {
+ s_sheet_no_pac[sch_cnt_no_pac] = IN.sheet;
+ sch_cnt_no_pac++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ sort (sch_cnt, sch_Index, s_name);
+ for (n = 0; n < sch_cnt; n++) {
+ sch_name[n] = s_name[sch_Index[n]] ;
+ sch_value[n] = s_value[sch_Index[n]] ;
+ sch_package[n] = s_package[sch_Index[n]];
+ sch_sheet[n] = s_sheet[sch_Index[n]];
+ sprintf(DeviceList[n], "%s\t%s\t%s\t%d", sch_name[n] , sch_value[n], sch_package[n], sch_sheet[n]);
+ }
+ for (n = 0; n < sch_cnt_no_pac; n++) {
+ sch_name_no_pac[n] = s_name_no_pac[n] ;
+ sch_value_no_pac[n] = s_value_no_pac[n] ;
+ sch_package_no_pac[n] = s_package_no_pac[n];
+ sch_sheet_no_pac[n] = s_sheet_no_pac[n];
+ sprintf(DeviceList_no_pac[n], "%s\t%s\t%s\t%d", sch_name_no_pac[n] , sch_value_no_pac[n], sch_package_no_pac[n], sch_sheet_no_pac[n]);
+ }
+
+ if (runcount < 1) {
+ output(readfile, "wtD") {
+ for(int x = 0; x < sch_cnt; x++) {
+ printf("%s\t%s\t%s\t%d\n", sch_name[x], sch_value[x], sch_package[x], sch_sheet[x] );
+ }
+ }
+ output(readfile_no_pac, "wtD") {
+ for(int x = 0; x < sch_cnt_no_pac; x++) {
+ printf("%s\t%s\t%s\t%d\n", sch_name_no_pac[x], sch_value_no_pac[x], sch_package_no_pac[x], sch_sheet_no_pac[x] );
+ }
+ }
+ runcount++;
+ string cmd;
+ sprintf( cmd, "edit '%s';\n run '%s' BRD %d;\n", filesetext(S.name, ".brd"), argv[0], runcount );
+ exit(cmd);
+ }
+ brd_cnt = lines_cnt;
+ string s[];
+ for ( n = 0; n < brd_cnt; n++) {
+ strsplit(s, lines[n], '\t');
+ brd_name[n] = s[0];
+ brd_value[n] = s[1];
+ brd_package[n] = s[2];
+ sprintf(ElementList[n], "%s\t%s\t%s\t0", brd_name[n], brd_value[n], brd_package[n] );
+ }
+ }
+ menue();
+}
diff --git a/trunk/ulp/make_bga_package.bmp b/trunk/ulp/make_bga_package.bmp
new file mode 100644
index 00000000..1930fc47
Binary files /dev/null and b/trunk/ulp/make_bga_package.bmp differ
diff --git a/trunk/ulp/make_package_dual.bmp b/trunk/ulp/make_package_dual.bmp
new file mode 100644
index 00000000..ae5eeb9c
Binary files /dev/null and b/trunk/ulp/make_package_dual.bmp differ
diff --git a/trunk/ulp/make_package_meass_pacinfo.bmp b/trunk/ulp/make_package_meass_pacinfo.bmp
new file mode 100644
index 00000000..9d5a3553
Binary files /dev/null and b/trunk/ulp/make_package_meass_pacinfo.bmp differ
diff --git a/trunk/ulp/make_package_meass_pacinfo2.bmp b/trunk/ulp/make_package_meass_pacinfo2.bmp
new file mode 100644
index 00000000..3f66416c
Binary files /dev/null and b/trunk/ulp/make_package_meass_pacinfo2.bmp differ
diff --git a/trunk/ulp/make_package_meass_padinfo-oct.bmp b/trunk/ulp/make_package_meass_padinfo-oct.bmp
new file mode 100644
index 00000000..969b9a54
Binary files /dev/null and b/trunk/ulp/make_package_meass_padinfo-oct.bmp differ
diff --git a/trunk/ulp/make_package_meass_padinfo-round.bmp b/trunk/ulp/make_package_meass_padinfo-round.bmp
new file mode 100644
index 00000000..67865d6b
Binary files /dev/null and b/trunk/ulp/make_package_meass_padinfo-round.bmp differ
diff --git a/trunk/ulp/make_package_meass_padinfo-sqr.bmp b/trunk/ulp/make_package_meass_padinfo-sqr.bmp
new file mode 100644
index 00000000..8ed8ac8a
Binary files /dev/null and b/trunk/ulp/make_package_meass_padinfo-sqr.bmp differ
diff --git a/trunk/ulp/make_package_meass_smdinfo.bmp b/trunk/ulp/make_package_meass_smdinfo.bmp
new file mode 100644
index 00000000..3db9de0f
Binary files /dev/null and b/trunk/ulp/make_package_meass_smdinfo.bmp differ
diff --git a/trunk/ulp/make_package_quad_left.bmp b/trunk/ulp/make_package_quad_left.bmp
new file mode 100644
index 00000000..6e0510c8
Binary files /dev/null and b/trunk/ulp/make_package_quad_left.bmp differ
diff --git a/trunk/ulp/make_package_quad_middle.bmp b/trunk/ulp/make_package_quad_middle.bmp
new file mode 100644
index 00000000..719d6d49
Binary files /dev/null and b/trunk/ulp/make_package_quad_middle.bmp differ
diff --git a/trunk/ulp/make_symbol_dual1.bmp b/trunk/ulp/make_symbol_dual1.bmp
new file mode 100644
index 00000000..c9382bce
Binary files /dev/null and b/trunk/ulp/make_symbol_dual1.bmp differ
diff --git a/trunk/ulp/make_symbol_dual2.bmp b/trunk/ulp/make_symbol_dual2.bmp
new file mode 100644
index 00000000..c09a12d8
Binary files /dev/null and b/trunk/ulp/make_symbol_dual2.bmp differ
diff --git a/trunk/ulp/make_symbol_quad.bmp b/trunk/ulp/make_symbol_quad.bmp
new file mode 100644
index 00000000..f65171a2
Binary files /dev/null and b/trunk/ulp/make_symbol_quad.bmp differ
diff --git a/trunk/ulp/make_symbol_single.bmp b/trunk/ulp/make_symbol_single.bmp
new file mode 100644
index 00000000..7097a61f
Binary files /dev/null and b/trunk/ulp/make_symbol_single.bmp differ
diff --git a/trunk/ulp/make_symbol_stripe.bmp b/trunk/ulp/make_symbol_stripe.bmp
new file mode 100644
index 00000000..d5d72e3c
Binary files /dev/null and b/trunk/ulp/make_symbol_stripe.bmp differ
diff --git a/trunk/ulp/maskdata.ulp b/trunk/ulp/maskdata.ulp
new file mode 100644
index 00000000..d94ff808
--- /dev/null
+++ b/trunk/ulp/maskdata.ulp
@@ -0,0 +1,752 @@
+#usage "This EAGLE User Language Program generates a script file "
+ "maskdata.scr that generates new layers for solder stop mask "
+ "and cream frame. See parameter section in this file.
"
+ " "
+ "In these layers each symbol can be edited separately."
+ " "
+ "Known limitation: Octagon shaped pads are covered with a round stop symbol."
+ "
"
+ "Das ULP erzeugt ein Script-File maskdata.scr, das vier "
+ "neue Layer fuer die Loetstop- und Lotpastensymbole erzuegt. "
+ "Die Definition kann im Abschnitt parameter veraendert werden. "
+ " "
+ "In diesem Layer kann jedes Symbol einzeln bearbeitet werden."
+ " "
+ "Einschraenkungen: Octagon Pads erhalten eine runde Loetstoppmake!"
+ "
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+int grid = 1;
+string GridUnit[] = { "MIC", "MM", "MIL", "INCH" };
+real GridWidth[] = { 10.2, 0.0102, 0.4, 0.0004 }; // default by grid
+if (board) { board(B) grid = B.grid.unit; }
+if (library) { library(L) grid = L.grid.unit; }
+
+real width = GridWidth[grid];
+string layer = "1";
+string gridstr = "";
+real D = 0.01;
+real L = 0.99;
+
+real angle = 30.0; // angle of Stub
+int arcres = angle / 3; // resolution of angle in steps
+real angle_offset = 0.0; // rotate the complete stub
+int polygon = 1; // draw as polygon
+real arcsinXa;
+real arcsinYa;
+real arcsinXe;
+real arcsinYe;
+real ox, oy; // offset X Y
+string signame = "";
+
+string cmd_draw_info = "";
+string s;
+string h;
+string err = " ";
+
+int rank = 0;
+if (board) rank = 1;
+string polyinit;
+sprintf (polyinit, "CHANGE ORPHANS ON;\nCHANGE POUR SOLID;\nCHANGE RANK %d;\n", rank);
+
+real wwidth2;
+real RadiusL;
+real angleL;
+
+int test = 0;
+
+// ******************** Functions ****************************
+string esigname(string sig) {
+ if (sig) sig = "'" + sig + "'";
+ return sig;
+}
+
+// ************************************************************************
+string xy_arc( real ang, real radius, real offx, real offy) {
+ string xy;
+ real rad = PI / 180 * ang;
+ sprintf(xy, "(%.4f %.4f)\n",
+ offx + (cos(rad) * radius),
+ offy + (sin(rad) * radius) );
+ return xy;
+}
+
+real bogenY2( real ang, real radius) {
+ real rad = PI / 180 * (ang/2);
+ return sin(rad) * radius;
+}
+
+real bogenX( real ang, real radius) {
+ real rad = PI / 180 * (ang/2);
+ return cos(rad) * radius;
+}
+
+
+// ***
+real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) {
+ real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
+ real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
+
+ if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+ if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+ if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+ if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+ if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
+ WinkelNeu = (Xalt - Xorigin) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+ if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */
+ WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+ if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */
+ WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * cos(rad)); }
+}
+
+real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) {
+ real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin)));
+ real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */
+
+ if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+ if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */
+ WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+ if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+ if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */
+ WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+ if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */
+ WinkelNeu = (Xalt - Xorigin) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+ if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */
+ WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+ if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */
+ WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel;
+ real rad = PI / 180 * WinkelNeu;
+ return (RADIUS * sin(rad)); }
+}
+
+
+real radiusY(real ang, real rry) {
+ real r = (rry*2) / sin(PI / 180 * ang) / 2;
+ return r;
+}
+
+
+string check_values(void) {
+ string error = "";
+ wwidth2 = width/2;
+ RadiusL = D + L - wwidth2;
+ angleL = angle - (width / ((RadiusL * 2 * PI) / 360));
+ arcsinXa = bogenX( angle, D) + wwidth2;
+ arcsinYa = bogenY2( angle, D + wwidth2) - wwidth2;
+ arcsinXe = arcsinXa;
+ arcsinYe = -arcsinYa;
+ if (arcsinYa < 0) {
+ sprintf(error, "Set D to %.4f while W %.4f < wire width %.4f",
+ radiusY(angle/2, wwidth2), bogenX( angle, D), width );
+ }
+ return error;
+}
+
+
+// *** draw arc ***
+string draw_arc(int draw_resol, real draw_radius, real draw_arc_degree, real draw_ang_off, real offx, real offy) {
+ real start_arc_degree = draw_ang_off - draw_arc_degree/2;
+ if (start_arc_degree < 0) start_arc_degree += 360;
+ real end_arc_degree = start_arc_degree + draw_arc_degree;
+ real arcstep = (end_arc_degree - start_arc_degree) / draw_resol;
+ string e;
+ for (real winkel = start_arc_degree; winkel < end_arc_degree + 0.0001; winkel += arcstep) {
+ e += xy_arc(winkel, draw_radius, offx, offy) ;
+ }
+ return e;
+}
+
+
+// *************************************************************
+void menue(void) {
+ dlgDialog("Radial Stub") {
+ dlgHBoxLayout {
+ dlgSpacing(150);
+ dlgLabel("Measures in " + GridUnit[grid] + " (Grid)");
+ dlgStretch(1);
+ dlgGroup(" Draw as") {
+ dlgVBoxLayout {
+ dlgRadioButton("W&ire", polygon);
+ dlgRadioButton("&Polygon", polygon);
+ dlgHBoxLayout {
+ dlgLabel("&Width");
+ dlgSpacing(15);
+ dlgRealEdit(width);
+ dlgStretch(1);
+ }
+ }
+ }
+ }
+ dlgHBoxLayout {
+ dlgLabel(cmd_draw_info, 1);
+ dlgGridLayout {
+ dlgCell( 1, 1) dlgLabel(" ");
+ dlgCell( 2, 1) dlgLabel("Lay&er");
+ dlgCell( 2, 2) dlgStringEdit(layer);
+ dlgCell( 2, 3) dlgSpacing(8);
+ if (board) {
+ dlgCell( 2, 4) dlgLabel("&Signal name");
+ dlgCell( 2, 5) dlgStringEdit(signame);
+ }
+ dlgCell( 6, 1) dlgLabel("&L");
+ dlgCell( 6, 2) dlgRealEdit(L, 0, +1600);
+ dlgCell( 7, 1) dlgLabel("&D");
+ dlgCell( 7, 2) dlgRealEdit(D, 0, +1600);
+ dlgCell( 9, 1) dlgLabel("&Angle");
+ dlgCell( 9, 2) dlgRealEdit(angle, 0.0, 180.0);
+ dlgCell( 9, 4) dlgLabel("Angle &offset ");
+ dlgCell( 9, 5) dlgRealEdit(angle_offset, 0.0, 360.0);
+ dlgCell( 10, 1) dlgLabel("A&rc res.");
+ dlgCell( 10, 2) dlgIntEdit(arcres, 6, 180);
+ dlgCell( 11, 2) dlgLabel(" (steps)");
+
+ dlgCell( 14, 4) dlgLabel("&X offset");
+ dlgCell( 14, 5) dlgRealEdit(ox, -800.0, +800.0);
+ dlgCell( 15, 4) dlgLabel("&Y offset");
+ dlgCell( 15, 5) dlgRealEdit(oy, -800.0, +800.0);
+ }
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgSpacing(50);
+ }
+ dlgLabel(err, 1);
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") {
+ err = check_values();
+ if (err) {
+ if (dlgMessageBox(err, "Accept", "No") == 0) {
+ D = radiusY(angle/2, wwidth2);
+ err = "";
+ }
+ else if (dlgMessageBox("Confirm (the values) ?", "Yes", "No") == 0) dlgAccept();
+ }
+ else dlgAccept();
+ }
+ dlgPushButton("-Cancel") { dlgReject(); exit(0); }
+ dlgStretch(1);
+ }
+ };
+ return;
+}
+
+// ***** Main ******
+void main(void) {
+ if (library) signame = "";
+ menue();
+ if (angle_offset) {
+ real nX = Xneu(arcsinXa, arcsinYa, 0, 0, angle_offset);
+ real nY = Yneu(arcsinXa, arcsinYa, 0, 0, angle_offset);
+ arcsinXa = nX;
+ arcsinYa = nY;
+ nX = Xneu(arcsinXe, arcsinYe, 0, 0, angle_offset);
+ nY = Yneu(arcsinXe, arcsinYe, 0, 0, angle_offset);
+ arcsinXe = nX;
+ arcsinYe = nY;
+ }
+ esigname(signame);
+ gridstr = GridUnit[grid];
+
+ sprintf(s, "SET WIRE_BEND 2;\n");
+ if (gridstr) s += "GRID " + gridstr + ";\n";
+ if (layer) s += "CHANGE LAYER " + layer + ";\n";
+ sprintf(h, "CHANGE WIDTH %.4f;\n", width);
+ s += h;
+ if (polygon) {
+ s += polyinit;
+ sprintf(h, "POLY %s ", signame );
+ }
+ else sprintf(h, "WIRE %s ", signame );
+ s += h;
+ sprintf(h, " (%.4f %.4f)", arcsinXa + ox, arcsinYa + oy); // *** draw sinw ***
+ s += h;
+ sprintf(h, " (%.4f %.4f)", arcsinXe + ox, arcsinYe + oy);
+ s += h;
+ s += draw_arc(arcres, RadiusL, angleL, angle_offset, ox, oy); // *** draw arc ***
+ sprintf(h, " (%.4f %.4f)", arcsinXa + ox, arcsinYa +oy);
+ s += h;
+ if (gridstr) {
+ sprintf(h, ";\nGRID LAST;\n");
+ s += h;
+ }
+ if (test) if (dlgMessageBox(s, "OK", "ESC") != 0) exit (-1);
+ exit (s);
+}
diff --git a/trunk/ulp/mill-outlines-bott.bmp b/trunk/ulp/mill-outlines-bott.bmp
new file mode 100644
index 00000000..23c59011
Binary files /dev/null and b/trunk/ulp/mill-outlines-bott.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-dim-down.bmp b/trunk/ulp/mill-outlines-cnc-dim-down.bmp
new file mode 100644
index 00000000..bf3200bc
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-dim-down.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-down.bmp b/trunk/ulp/mill-outlines-cnc-down.bmp
new file mode 100644
index 00000000..16c8897a
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-down.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-drill-down.bmp b/trunk/ulp/mill-outlines-cnc-drill-down.bmp
new file mode 100644
index 00000000..78024534
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-drill-down.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-drill-safety.bmp b/trunk/ulp/mill-outlines-cnc-drill-safety.bmp
new file mode 100644
index 00000000..78024534
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-drill-safety.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-fastvelocity.bmp b/trunk/ulp/mill-outlines-cnc-fastvelocity.bmp
new file mode 100644
index 00000000..488481a1
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-fastvelocity.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-parkposition.bmp b/trunk/ulp/mill-outlines-cnc-parkposition.bmp
new file mode 100644
index 00000000..8f6821e4
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-parkposition.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-rpm.bmp b/trunk/ulp/mill-outlines-cnc-rpm.bmp
new file mode 100644
index 00000000..038b6648
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-rpm.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-safety.bmp b/trunk/ulp/mill-outlines-cnc-safety.bmp
new file mode 100644
index 00000000..36ad043c
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-safety.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-up.bmp b/trunk/ulp/mill-outlines-cnc-up.bmp
new file mode 100644
index 00000000..225c4c7e
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-up.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc-velocity.bmp b/trunk/ulp/mill-outlines-cnc-velocity.bmp
new file mode 100644
index 00000000..bec12bc6
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-velocity.bmp differ
diff --git a/trunk/ulp/mill-outlines-cnc.bmp b/trunk/ulp/mill-outlines-cnc.bmp
new file mode 100644
index 00000000..00f22459
Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc.bmp differ
diff --git a/trunk/ulp/mill-outlines-coppdim.bmp b/trunk/ulp/mill-outlines-coppdim.bmp
new file mode 100644
index 00000000..802ff0a4
Binary files /dev/null and b/trunk/ulp/mill-outlines-coppdim.bmp differ
diff --git a/trunk/ulp/mill-outlines-dimension-contours.bmp b/trunk/ulp/mill-outlines-dimension-contours.bmp
new file mode 100644
index 00000000..032a07a2
Binary files /dev/null and b/trunk/ulp/mill-outlines-dimension-contours.bmp differ
diff --git a/trunk/ulp/mill-outlines-drc-info.bmp b/trunk/ulp/mill-outlines-drc-info.bmp
new file mode 100644
index 00000000..c6566f95
Binary files /dev/null and b/trunk/ulp/mill-outlines-drc-info.bmp differ
diff --git a/trunk/ulp/mill-outlines-drill-velocity.bmp b/trunk/ulp/mill-outlines-drill-velocity.bmp
new file mode 100644
index 00000000..726037cd
Binary files /dev/null and b/trunk/ulp/mill-outlines-drill-velocity.bmp differ
diff --git a/trunk/ulp/mill-outlines-drill.bmp b/trunk/ulp/mill-outlines-drill.bmp
new file mode 100644
index 00000000..bbf8457a
Binary files /dev/null and b/trunk/ulp/mill-outlines-drill.bmp differ
diff --git a/trunk/ulp/mill-outlines-eagle.bmp b/trunk/ulp/mill-outlines-eagle.bmp
new file mode 100644
index 00000000..2abf5f0b
Binary files /dev/null and b/trunk/ulp/mill-outlines-eagle.bmp differ
diff --git a/trunk/ulp/mill-outlines-free.bmp b/trunk/ulp/mill-outlines-free.bmp
new file mode 100644
index 00000000..515cf1fd
Binary files /dev/null and b/trunk/ulp/mill-outlines-free.bmp differ
diff --git a/trunk/ulp/mill-outlines-get_board_zero.bmp b/trunk/ulp/mill-outlines-get_board_zero.bmp
new file mode 100644
index 00000000..1a0218cc
Binary files /dev/null and b/trunk/ulp/mill-outlines-get_board_zero.bmp differ
diff --git a/trunk/ulp/mill-outlines-hole.bmp b/trunk/ulp/mill-outlines-hole.bmp
new file mode 100644
index 00000000..24d1c85f
Binary files /dev/null and b/trunk/ulp/mill-outlines-hole.bmp differ
diff --git a/trunk/ulp/mill-outlines-hpgl.bmp b/trunk/ulp/mill-outlines-hpgl.bmp
new file mode 100644
index 00000000..ab60d250
Binary files /dev/null and b/trunk/ulp/mill-outlines-hpgl.bmp differ
diff --git a/trunk/ulp/mill-outlines-inner-polygon-contour.bmp b/trunk/ulp/mill-outlines-inner-polygon-contour.bmp
new file mode 100644
index 00000000..98e4afb3
Binary files /dev/null and b/trunk/ulp/mill-outlines-inner-polygon-contour.bmp differ
diff --git a/trunk/ulp/mill-outlines-inner-polygon-contour1.bmp b/trunk/ulp/mill-outlines-inner-polygon-contour1.bmp
new file mode 100644
index 00000000..6e060227
Binary files /dev/null and b/trunk/ulp/mill-outlines-inner-polygon-contour1.bmp differ
diff --git a/trunk/ulp/mill-outlines-inside-milling.bmp b/trunk/ulp/mill-outlines-inside-milling.bmp
new file mode 100644
index 00000000..0ef33849
Binary files /dev/null and b/trunk/ulp/mill-outlines-inside-milling.bmp differ
diff --git a/trunk/ulp/mill-outlines-isel.bmp b/trunk/ulp/mill-outlines-isel.bmp
new file mode 100644
index 00000000..be6a44bd
Binary files /dev/null and b/trunk/ulp/mill-outlines-isel.bmp differ
diff --git a/trunk/ulp/mill-outlines-isol-pour.bmp b/trunk/ulp/mill-outlines-isol-pour.bmp
new file mode 100644
index 00000000..09cfd719
Binary files /dev/null and b/trunk/ulp/mill-outlines-isol-pour.bmp differ
diff --git a/trunk/ulp/mill-outlines-mildimension.bmp b/trunk/ulp/mill-outlines-mildimension.bmp
new file mode 100644
index 00000000..d1562bdf
Binary files /dev/null and b/trunk/ulp/mill-outlines-mildimension.bmp differ
diff --git a/trunk/ulp/mill-outlines-mirror-nc-bottom.bmp b/trunk/ulp/mill-outlines-mirror-nc-bottom.bmp
new file mode 100644
index 00000000..4acdc8cb
Binary files /dev/null and b/trunk/ulp/mill-outlines-mirror-nc-bottom.bmp differ
diff --git a/trunk/ulp/mill-outlines-mirror-nc-top.bmp b/trunk/ulp/mill-outlines-mirror-nc-top.bmp
new file mode 100644
index 00000000..923af5d0
Binary files /dev/null and b/trunk/ulp/mill-outlines-mirror-nc-top.bmp differ
diff --git a/trunk/ulp/mill-outlines-mirror.bmp b/trunk/ulp/mill-outlines-mirror.bmp
new file mode 100644
index 00000000..a6c160cf
Binary files /dev/null and b/trunk/ulp/mill-outlines-mirror.bmp differ
diff --git a/trunk/ulp/mill-outlines-multi-dimension.bmp b/trunk/ulp/mill-outlines-multi-dimension.bmp
new file mode 100644
index 00000000..453ec17c
Binary files /dev/null and b/trunk/ulp/mill-outlines-multi-dimension.bmp differ
diff --git a/trunk/ulp/mill-outlines-no-blowup.bmp b/trunk/ulp/mill-outlines-no-blowup.bmp
new file mode 100644
index 00000000..26f18cc2
Binary files /dev/null and b/trunk/ulp/mill-outlines-no-blowup.bmp differ
diff --git a/trunk/ulp/mill-outlines-nomir.bmp b/trunk/ulp/mill-outlines-nomir.bmp
new file mode 100644
index 00000000..b0e64b21
Binary files /dev/null and b/trunk/ulp/mill-outlines-nomir.bmp differ
diff --git a/trunk/ulp/mill-outlines-null_reference-drilling.bmp b/trunk/ulp/mill-outlines-null_reference-drilling.bmp
new file mode 100644
index 00000000..0d42ed8c
Binary files /dev/null and b/trunk/ulp/mill-outlines-null_reference-drilling.bmp differ
diff --git a/trunk/ulp/mill-outlines-null_reference.bmp b/trunk/ulp/mill-outlines-null_reference.bmp
new file mode 100644
index 00000000..1a3d8888
Binary files /dev/null and b/trunk/ulp/mill-outlines-null_reference.bmp differ
diff --git a/trunk/ulp/mill-outlines-ovrlpfp.bmp b/trunk/ulp/mill-outlines-ovrlpfp.bmp
new file mode 100644
index 00000000..8eb4e964
Binary files /dev/null and b/trunk/ulp/mill-outlines-ovrlpfp.bmp differ
diff --git a/trunk/ulp/mill-outlines-ovrlppp.bmp b/trunk/ulp/mill-outlines-ovrlppp.bmp
new file mode 100644
index 00000000..7b7c60c0
Binary files /dev/null and b/trunk/ulp/mill-outlines-ovrlppp.bmp differ
diff --git a/trunk/ulp/mill-outlines-plus-text.bmp b/trunk/ulp/mill-outlines-plus-text.bmp
new file mode 100644
index 00000000..e3cdf24e
Binary files /dev/null and b/trunk/ulp/mill-outlines-plus-text.bmp differ
diff --git a/trunk/ulp/mill-outlines-pour.bmp b/trunk/ulp/mill-outlines-pour.bmp
new file mode 100644
index 00000000..09cfd719
Binary files /dev/null and b/trunk/ulp/mill-outlines-pour.bmp differ
diff --git a/trunk/ulp/mill-outlines-question.bmp b/trunk/ulp/mill-outlines-question.bmp
new file mode 100644
index 00000000..03038de2
Binary files /dev/null and b/trunk/ulp/mill-outlines-question.bmp differ
diff --git a/trunk/ulp/mill-outlines-resolution.bmp b/trunk/ulp/mill-outlines-resolution.bmp
new file mode 100644
index 00000000..6ee483a2
Binary files /dev/null and b/trunk/ulp/mill-outlines-resolution.bmp differ
diff --git a/trunk/ulp/mill-outlines-script.bmp b/trunk/ulp/mill-outlines-script.bmp
new file mode 100644
index 00000000..a1803653
Binary files /dev/null and b/trunk/ulp/mill-outlines-script.bmp differ
diff --git a/trunk/ulp/mill-outlines-sec-isol.bmp b/trunk/ulp/mill-outlines-sec-isol.bmp
new file mode 100644
index 00000000..be1c6418
Binary files /dev/null and b/trunk/ulp/mill-outlines-sec-isol.bmp differ
diff --git a/trunk/ulp/mill-outlines-sec-isolate.bmp b/trunk/ulp/mill-outlines-sec-isolate.bmp
new file mode 100644
index 00000000..f5e3c14e
Binary files /dev/null and b/trunk/ulp/mill-outlines-sec-isolate.bmp differ
diff --git a/trunk/ulp/mill-outlines-spacing.bmp b/trunk/ulp/mill-outlines-spacing.bmp
new file mode 100644
index 00000000..a2aa8d43
Binary files /dev/null and b/trunk/ulp/mill-outlines-spacing.bmp differ
diff --git a/trunk/ulp/mill-outlines-top.bmp b/trunk/ulp/mill-outlines-top.bmp
new file mode 100644
index 00000000..12d690b3
Binary files /dev/null and b/trunk/ulp/mill-outlines-top.bmp differ
diff --git a/trunk/ulp/mill-outlines-via.bmp b/trunk/ulp/mill-outlines-via.bmp
new file mode 100644
index 00000000..32d66c47
Binary files /dev/null and b/trunk/ulp/mill-outlines-via.bmp differ
diff --git a/trunk/ulp/mill-outlines.def b/trunk/ulp/mill-outlines.def
new file mode 100644
index 00000000..aec8539f
--- /dev/null
+++ b/trunk/ulp/mill-outlines.def
@@ -0,0 +1,61 @@
+HPGL
+2; 1 SelectedDevice
+0.20000000; 2 MillToolOutl
+0.00000000; 3 MillToolIsolate fuer Polygon-Isolate
+0.60000000; 4 MillToolFree
+1; 5 SelectedLayer1
+16; 6 SelectedLayer16
+0.8; 7 DrillPad
+0.8; 8 DrillVia
+0.8; 9 DrillHole
+20; 10 OverlapOutlPercent
+20; 11 OverlapRubOutPercent
+0.50000000; 12 Distance_Copper_Dimension
+2.00000000; 13 DimensionMillTool
+1; 14 Millfreeyes
+10.00000000; 15 Holder_Spacing
+0; 16 Onlydrill
+1; 17 Generatedrills
+2.0; 18 Max_Drill_Diameter
+0.00000000; 19 Z_down
+0.00000000; 20 Drill_z_deep
+0.00000000; 21 Mill_z_safety
+0; 22 Spindle_rpm
+0.00000000; 23 Tool_vel
+0.00000000; 24 Fast_vel
+0.00000000; 25 Drill_Vel
+0; 26 DrillRefOn
+3.00000000; 27 DrillRefDiameter
+-6.00000000; 28 DrillRefDeep
+1; 29 UseRack
+0; 30 SelectedPlusLayerTop
+0; 31 SelectedPlusLayerBot
+1; 32 Mirror_On
+1; 33 MachineMenuOn
+0.00000000; 34 ParkXposition
+0.00000000; 35 ParkYposition
+0.00000000; 36 ParkZposition
+0.00000000; 37 Z_dimension
+1; 38 Dim_on_off
+-2.00000000; 39 Mz_down
+-3.80000000; 40 Mdrill_z_deep
+1.00000000; 41 Mmill_z_safety
+15000; 42 Mspindle_rpm
+2.00000000; 43 Mtool_vel
+5.00000000; 44 Mfast_vel
+0.50000000; 45 MDrill_Vel
+0; 46 MdrillRefOn
+3.00000000; 47 MdrillRefDiameter
+-6.00000000; 48 MdrillRefDeep
+10.00000000; 49 MparkXposition
+10.00000000; 50 MparkYposition
+80.00000000; 51 MparkZposition
+-3.80000000; 52 Mz_dimension
+1; 53 Mdim_on_off
+1; 54 Mmillfreeyes
+0.60000000; 55 MMillToolFree
+2.00000000; 56 MDimensionMillTool
+1; 57 MInner_contour
+3; 58 CNCmillResolution
+0; 58 MillOnlyContour
+! *** Do not change the order of this lines *** !
diff --git a/trunk/ulp/mill-outlines.ulp b/trunk/ulp/mill-outlines.ulp
new file mode 100644
index 00000000..ddd0023c
--- /dev/null
+++ b/trunk/ulp/mill-outlines.ulp
@@ -0,0 +1,5688 @@
+#usage "en: Export milling data for a board layout in SCRIPT, HPGL, ISEL, CNC\n"
+ "
"
+ "Author: support@cadsoft.de"
+ ,
+ "de: Export von Fräsdaten aus einem Board in SCRIPT, HPGL, ISEL, CNC"
+ "
"
+ "Author: support@cadsoft.de"
+
+#require 6.0500
+
+// ****************** History *************************************************
+// place VIA with SIGNAL '~_REAL_OUTLINEMILL_~' in to break throgh for milling
+// this as outside contour.
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+// 2002-05-08 - reverse milling
+// 2002-06-23 - Polygon:CHANGE THERMAL OFF
+// 2003-05-14 - With REFERENCE-Circle (Drill) to mirror for drilling machine
+// - Switch On/Off 2. isolate/cupper pouring
+// 2003-09-02 - Switch On/Off drills
+// 2004-04-24 - String ulp_path no longer necessary
+// 2004-07-21 - expand reference package menu
+// by select layer, switch mirror on/off
+// place VIAs with SIGNAL '~_REAL_OUTLINEMILL_~'
+// in to break throgh for milling as outside contour.
+// Language en/de
+// 2004-08-12 - ISEL Interface/Isel-Zwischenformat
+// Referenz:
+// | Übersicht des isel Zwischenformat zur Maschinensteuerung
+// | "isel ZF in deutsch.pdf" Stand 08.11.1999
+// 2004-10-18 - Abfrage ob DRC fehlerfrei durchlaufen wurde.
+// - bei vorhandener .def-Datei werden diese Parameter als Defaultgeladen.
+// - Sichern der Einstellungen in def-Datei.
+// 2005-05-18 - ** output no shorter filling wires as MillToolFree diameter **
+// - Hinweis auf den erfolgreichen (fehlerfreien) Design-Rule-Check
+// damit man im voraus abklären kann ob auch alles mit dem
+// benutztenFräser isoliert (gefräst) werden kann.
+// - Überprüfung der CLASS-Clerance mit dem Durchmesser des
+// Isolationsfräser Tool#1.
+// 2005-05-23 - UseRack: (switch), to can use also a Rack with HPGL and Nc-Machine-Code
+// for users to have a machine with automaticle tool change.
+// UseRack: Wenn mehr als die 3 Standarddurchmesser benutzt werden,
+// werden zusätzliche Tools (1/10mm gerundet) generiert für das Bohren
+// (auch in HPGL --> SPxx / Script) für Anwender die eine Fräsmaschine mit
+// automatischen Werkzeugwechsel besitzen.
+// - SP8 in HPGL bedeutet: Die Platine muß auf dem Frästisch umgedreht werden
+// ** nur HPGL ** www.cnc-papst.de * reiner_marcus@hotmail.com **
+// 2005-06-16 - Isel-Zwischenformat Extension ".cnp"
+// 2005-06-23 - Drilling way optimised / Bohrwege Streckenoptimiert
+// - Beim RubOut wird der Fräser nicht angehoben, wenn sich die X-Koordinate
+// weniger als der Fräserradius ändert.
+// Schalter 'Lift_Off' wird nicht im Menu angezeigt, sondern ist fix im ULP.
+// - Zusätzlicher (plus) Layer zum fräsen von Texten in Kupferflächen (Polygon).
+// - Maschinen-Menu kann abgeschaltet werden für _nur_ Benutzer von HPGL
+// Schalter 'MachineMenuOn'
+// ** nur HPGL ** www.cnc-papst.de * reiner_marcus@hotmail.com **
+//
+// 2005-09-28 *** für LPKF laut Hr. Böhm (agfeo) keine Formatbeschreibung zu erhalten
+// *** wird also wieder gecancelt ***
+//
+// 2005-09-30 - Device-Reinit bei Layer 45 Holes nicht offset 100 addieren.
+// - CNC
+//
+// 2005-11-21 - LPKF entfernt
+//
+// 2005-12-22 - Unit & Format bei [Masch. Nullpunkt] [Lade Beispiel] auf mm und 2.4 setzen
+// 2006-01-23 - Only Drills gibt jetzt nur die Drills aus
+// (ohne Meldung von fehlerhaften Parametern bzw. Layern)
+// 2006-01-25 - $ in temporären Namen in ~ (Tilde) geändert.
+// - Temporäre Files werden mit "wtD" geöffnet
+// - !Generatedrills; keine Abfrage der Bohrdurchmeser auf Gültigkeit
+// 2006-02-13 - Wegen Rechenungenauigkeit muß für Fräswege zwischen den Leiterbahnen und
+// einem evtl. vorhandenem Füll-Polygon die Spurbreite (Clearance/Isolate)
+// zu WIRE (Arc) um Inaccurateness breiter eingestellt werden, da es sonst
+// an gebogenen Leiterbahnsegmenten zu Fehlerhaften nicht berechneten Fräswegen
+// kommen kann. Also die gefräste Isolation nicht komplett geschlossen ist.
+// * Nur Isolationsfräsen:
+// Hier wird die Drehrichtung (Rotation) der berechneten Polygon-Kontur
+// zu der Kontur von Signal-Polygonen ermittelt, da sich die Kontur der Füllung
+// einmal rechts-drehend an den Leiterzug (WIRE/PAD/VIA-Struktur) und einmal
+// links-drehend an ein evtl. vorhandenes Polygon (Versorgungs-Polygon)um den
+// Leiterzug anschmiegt.
+// Dadurch würde die Isolation also der Fräsweg doppelt ausgegeben werden.
+// Bei inaktiven [] Rub out werden nur linksdrehende Polygonkonturen ausgegeben
+// um den Fräsaufwand zum reinen Isolieren zu minimieren.
+// Bei aktiven [] Rub out werden linksdrehende wie auch rechtsdrehende Polygon-
+// konturen ausgegeben, um der geätzten Version einer Leiterplatte so nah wie
+// Möglich zu kommen. *
+//
+// 2006-07-26 - Generate separated layer +100 +101 +102 for milling tools.
+// - check Polygons of Rank 6.
+// - Use Rank 1 of polygon to generate real outline contour
+// to milling out from holder.
+// - Correct Rank on all generated Polygons.
+// 2006-08-01 - Check if POLYGON placed. If Yes, check if CLASS-Clearance 0.005 mm > Tool#1
+// but if problem with routet WIRE out of 0 45 90 Degree.
+// Es kann vorkommen, dass durch math. Rundung der Coordinaten das Polygon
+// nicht in die Isolationskanäle fliessen kann.
+// 2006-11-07 - Ausfräsen aus dem Träger (Dimensionlinie) berichtigt, war nur bei Script aktiv.
+// - dru Datei wird gelesen um den tatsächlichen Copper-Dimension Wert zu erhalten,
+// ist keine .dru gespeichert wird der defaultvalue benutzt und darauf hingewiesen.
+// 2006-12-11 - Maschinen-Menu aus/einschalten mit Checkbox.
+//
+// 2007-10-08 - Fräserbreiten ab 5 micron zulassen wg. Laser.
+//
+// 2008-11-12 - Layerzuordnung berichtigt, nicht das Flag, sondern die Layernummer benutzen.
+// - Delete von Polygon mit SHIFT und Via mit Ripup.
+// - Layerzuweisung vor Kontour fräsen.
+//
+// 2009-02-04 - Clear via airwire
+// 2009-02-05 - Correct mill tool for millout
+// 2009-03-31 - Correct koordinate delete special polygon and via # alf@cadsoft.de
+// corrected layer to millout (if only Layer 16 selected)
+// Holder spacing in script
+// Check if Dimension placed
+//
+// 2010-01-20 - Check DRC-Layer-Setup (1*16)
+// Check counts of outlines at layer Dimension
+//
+// 2010-01-25 - Use contour option positiv/negativ (rotation)
+// to switch on/off draw also polygon inside contours
+//
+// 2010-02-02 - Check and Set DRC-Layer-Setup and CLASS clearance to mill tool #1 + Inaccurateness
+//
+// 2010-04-08 - Milling always inner contour of pooring
+// CNC data finished
+//
+// 2010-08-06 - Info Durchbrüche als Dialog
+// Die gespeicherten Designregeln dürfen bis zu 30 Sekunden alt sein.
+//
+// 2010-10-28 - Prüfe die Designrules und benutze CLASSen, falls CLASSen benutzt sind,
+// sonst ändere die Design-Regeln.
+//
+// 2011-01-27 - Z-Achse in CNC-Device G00 / G01 Z..
+// Referenzfahrt am Anfang
+// Z_down -> Actualmilldeep, zum hochfahren mit -1 multipliziert (pos. Vorzeichen)
+//
+// 2011-02-02 - Wenn 2. Milling (und Rubout) abgeschaltet waren, dann wurde auch das 1. mal nicht isoliert.
+// Milling [ ] innercontour BitMap waren getauscht.
+// Wählbare Auflösung 3.2 3.3 3.4 im CNC Menu.
+// Programmierter Halt für umdrehen der Platine.
+//
+// 2011-02-03 - Auflösung in mit und ohne Kommastelle.
+// Mill_z_safety, Drill_z_deep, Z_down, Z_dimension als Option bei RUN ...
+//
+// 2011-02-09 - Generiere ein Refpackage mit 2 Circle und platziere dieses Package
+// an der berechneten linken unteren Ecke.
+// * Anfrage am 2010-10-13 *
+// ISEL-Device berichtigt: MOVE Z -> MOVEABS Z
+// Überprüfung der Erzeugungszeit der DRU-Datei auf 120 Sekunden erhöht.
+// Ist ein Refpackge platziert, darf die Dimension nicht gefräst werden,
+// sonst würde man in die Haltestifte fräsen!
+// Abfrage ob trotzdem gefräst werden soll.
+//
+// 2011-03-10 Nur Kontur fräsen
+//
+// 2011-06-17 Fehlermeldung bezüglich Mehrfachkonturen (Dimesion) um außerhalb der Dimension
+// stehende Texte oder Logos erweitert.
+//
+// 2011-09-28 Holderspacing corrected und Stegbreite 0.2mm, unabhängig vom Fräserdurchmesser
+// WIRE_BEND wieder auf 2 (diagonal stellen).
+//
+// 2011-10-04 Durchbrüche/Mehrfachkonturen berichtigt, Info Durchbrüche erweitert.
+//
+// 2011-10-20 Hinweis auf "Only milling Dimension".
+// Brichtigt: Bohrungen fräsen von Holes größer maximal vorkommenden Fräserdurchmesser.
+// Milling und Z-Achsen menu auf Tabs getrennt.
+//
+// 2011-11-21 Isel-Format: Fräser Z-Achse wieder hoch.
+//
+// 2012-01-12 Auflösung mit 8 Nachkommastellen. Wird der erweiterten internen Auflösung gerecht,
+// da es sonst zu fehlenden Wires kommen kann.
+//
+// 2012-01-13 Dimension immer in Layer 103 zeichnen.
+// ScriptDrillFile wird nicht mehr automatisch eingelesen,
+// da sonst die Holes doppelt vorhanden sind und DRC-Fehler erzeugen.
+// Im Device SCRIPT wird je nach benutzten Layer die Außenkontur im Layer 103 bzw. 118 erzeugt.
+//
+// 2012-01-16 Überprüfung der CLASSen vor der Überprüfung der Design-Regeln.
+// Die Design-Regeln werden jetzt immer zuerst gespeichert.
+//
+// 2012-01-20 Menu Prüfe Einstellungen "OK" Button geändert [Change &Tool #1]
+//
+// 2012-01-25 MillOnlyContour : Nur aus Träger fräsen berichtigt.
+// Layer 103 bzw. 118 anlegen.
+// Jetzt mit Tool #1 an DRC-Clearance / CLASS-Clearance anpassen und nicht die Clearance ändern.
+//
+// 2012-02-09 Korrigietre DRC-Parameter (minDistWireWire) Überprüfung.
+// Wenn der Parameter minDistWireWire groß genug ist, dann
+// werden die CLASSen nicht mehr geprüft.
+//
+// 2012-03-09 Zum ändern der Breite des Fräs-Polygon wurde das B.area. benutzt,
+// was aber nicht einer der Koordinaten des "Fräs-Polygon" entsprach!
+// Dadurch wurde unter Umständen ein anderes Element gewählt.
+// Jetzt wird eine Wire-Koordinate des Fräs-Polygon selbst herangezogen.
+//
+// 2012-03-20 Behandlung der Bohrungen (HOLE) größer Max. drill diam berichtigt.
+// Die Fräswege werden in der Option Script im Layer 118 erzeugt und in die *_drl.scr geschrieben.
+//
+// 2013-03-05 Holder Spacing berichtigt.
+// Drills und Holes werden in die Scriptdatei geschrieben und im Layer 144 145 gezeichnet
+// ScriptDrillFile und *_drl.scr wird nicht mehr benötigt.
+// Bohrungen größer Maxdrill berichtigt, in Script + HPGL.
+// Fehlermeldung bez. der Vias des Signal '~_REAL_OUTLINEMILL_~' ohne Option Tool#2 blow up berichtigt.
+// GRID (last) zurück stellen.
+// Kommentarzeilen in HPGL entfernt (Markierung #HPGLxxxx), da GC-Prevue damit Probleme hat.
+//
+// 2013-04-18 Tool 9 eingerichtet, zum Fräs-Bohren von Drills größer Max_Drill_Diameter
+// Initialisierung bei HPGL nur einmal
+// 2013-04-19 Abfrage bez. des Ausfräsen aus dem Trägermateriel bei platzierten Fangzapfen
+// Menüpunkt und Parameter zum Referenzbohrungen bohren auskommentiert.
+// 2013-04-30 Versatz/Offset berichtigt, beim fräsen von nur Bottom-Seite und platzierten Referen-Package
+// HPGL wird nun in zwei Dateien geschrieben, da die Fräse der FU-Berlin die Tools
+// zu einem optimierten Fräsweg zusammen fasst.
+// 2014-10-06 HPGL_TOP_ext = "_top.plt" Namenserweiterung bei HPGL für Daten des Top layer
+// Am Ende wird eine Nachricht ausgegeben, in welche Datei die Fräsdaten geschrieben wurden,
+// wichtig bei HPGL da auf Wunsch der FU Berlin nun je Seite (Top/Bottom) eine Datei erzeugt wird.
+// 2014-11-26 InfoREFPack in englisch
+//
+// 2015-03-24 RIPUP der VIA '~_REAL_OUTLINEMILL_~' innerhalb eines Innendurchbruch erst am Ende löschen
+// Devices SCRIPT wird am Ende wieder eingelesen
+//
+/* ** to do :
+Scalierung bei HPGL vorwahl 2/5/10
+** */
+
+string Version = "Version 6.2.2"; // 2015-03-24 alf@cadsoft.de
+
+string Header = "Outlines generator for PCB milling.";
+
+int test = 0; // Flag zum debuggen
+int test2 = 0; // 2. Flag zum debuggen
+
+/* ****************************************************
+ Complete the following steps to add a new output device definition:
+
+ 1. Add a new member to the 'enum { devScript = 1, ...'
+ 2. Add the new (unique!) device name to 'DeviceNames[]'
+ 3. Add the necessary 'case dev...' branches to
+ 'DeviceInit()',
+ 'DeviceReInit()',
+ 'DeviceDraw()',
+ 'CircleDraw()',
+ 'ArcDraw()'
+ and 'DeviceEnd()'
+
+ 4. Add also new Tool values to
+ 'toolFiles()'
+ and 'ValueInit()'
+***************************************************** */
+
+// Actually draw a line on the output device.
+// 'state' is defined as
+// 0 = this is the first line of a partial polygon
+// 1 = this is a "middle" line (neither the first nor the last one)
+// 2 = this is the last line of a partial polygon
+// 3 = this is a drill coordinate
+// 4 = this is one line (polygon fillings)
+
+/* *********************************************************************************
+ 2006-02-08
+ Achtung bei Kupferflächen die durch ein POLYGON gefüllt sind!
+ Durch die Rechenungenauigkeit (max. Auflösung der Eagle-Einheit) muß man
+ die CLASS-Clearance um den Betrag breiter angegeben werden, da sonst um
+ gekrümmte Leiterbahnen (Arc) teilweise keine Polygon-Kontur berechnet wird.
+ Aber nur wenn das Isolate kleiner der Fräserbreite + dem Ungenauigkeitsfaktor ist.
+************************************************************************************ */
+real Inaccurateness = 0.005; // 2006-02-08
+
+string DRC_CopperDimension = "mdCopperDimension"; // der Parameter in der .dru
+
+enum { false = -1 };
+enum { First_line, Middle_line, Last_line, Drill_coord, One_line } ;
+
+string INFOhelp = usage;
+string INFOhelpBut = "Help";
+string CANCEL = "-Cancel";
+string BACK = "-Back";
+string ACCEPT = "Accept";
+string YES = "YES";
+string NO = "NO";
+string ON = "ON";
+string OFF = "OFF";
+string BREAK = "<--";
+string NEXT = "Further";
+string DRCCHECK = "Check CLASS";
+string DRC_checked = "Befor milling the PCB, start the DRC (Design Rule Check) " +
+ "with the milling diameter (isolate) in CLASS clearance. " +
+ "All Clearance ERROR define a not isolated wire track! ";
+
+int Class_used[];
+string SClass[]; // 2010-02-02
+
+string INFOpolyClass;
+sprintf(INFOpolyClass, "If used a filling Polygon on Board, please check Clearance of Design-Rules/Classes if %.8f mm greater " +
+ "as Milling Tool #1, damit bei Leiterbahnen die nicht im 0°45°oder 90°Winkel also mit beliebigen Winkel " +
+ "verlegt sind, eventuelle Füllprobleme wegen Rechenungenauigkeit vermieden werden.", Inaccurateness);
+
+string SavePar = "&Save parameter";
+string Machine_Menu_Info = "Switch On Off the Mashine Menu for Z-Axis mashines! " +
+ "If accept to change this the ULP save the aktual Parameter und restart!";
+string Z_Machine_Menu = "Z Axis Menu";
+
+string INFOinside = "Info Break through";
+
+string INFOinnerContour = "If inside the board one or more breakthruogh you can place a VIA with SIGNAL name " +
+ "'~_REAL_OUTLINEMILL_~' to milling this.";
+string PlaceVIA = "place VIA";
+string DRCinfo = "Distance info: Distance Copper/Dimension (see DRC) this is the distance between "
+ "the polygon and outline of the board. "
+ "Do not use value 0 for Copper/Dimension in Design-Rules-Distance (DRC). ";
+ "";
+
+string Ref_pac = "_REFERENCE_HOLE_"; // *** special package for mirror milling data ***
+
+string InfoREFERENCE = "Generate a special package with " +
+ "REFERENCE circles in Layer 45 Holes. " +
+ "Place it in the layout for milling and " +
+ "mirroring (bottom side) with offset and " +
+ "start this ULP again. " +
+ "The position of the circles are defined " +
+ "in the NC drill data file which comes " +
+ "from the NC machine (eg. Excellon).
";
+
+string InfoREFPack = "There is placed a reference package in order to take the catching pins of the " +
+ "milling machine for calculating the axis of reflection. " +
+ "In this case milling the board out of the carrier should be switched off! " +
+ "However, if you prefer to have the board contour milled out, please check the distance "
+ "between the circles and layer Dimension!";
+
+string A_refpack = "A reference package is placed!";
+string InfoRefHole = "Drill referenz holes (fixing bolt) ";
+string InfoRefOff = "Drill reference holes OFF.";
+string InfoRefOn = "Drill reference holes ON.";
+
+string DrBrowse = "Browse";
+string REFdialog = " - generate refernece and place on Board";
+string LoadRefFile = "&Load ref. File";
+string Example_Ref = "Load Example";
+string DRILLref = "Select drill reference file (Holes)";
+string PLACErefpac1 = "After reference package placing start the ";
+string PLACErefpac2 = " to set the USEed libraries back.";
+string SHOWRackFile = "Show rack file";
+string SAVE_file = "Save Outlines file";
+string REFinfo2 = "Press button Zero reference to generate a reference Package from a NC-Drill file " +
+ "to place reference safety grip (circles) on PCB for exact mirroring the bottom side " +
+ "of PCB on milling machine.";
+
+string ZeroRef = "Zero refere&nce";
+string No_reftext = "!No reference file loaded.";
+
+string Script_Used = "SCRIPT used! Return the millings as WIRE to Board-Editor. ";
+
+string OnlyDrillHpgl = "Generate only drill file.";
+string INFOtext1_on = "Milling top side.";
+string INFOtext16_on = "Milling bottom side (mirror).";
+string INFOtext1_off = "Milling top side.";
+string INFOtext16_off = "Milling bottom side (mirror).";
+string TextInfoPlus = "Plus milling layer (to milling text inverting in a ploygon). " +
+ "Only can use with Top or Bottom layer.";
+string TOOLdiamIso = "Tool diameter for isolate. ";
+string OVERlapIso = "Overlap isolate - blow up in percent (%).";
+string OVERlapRubOut = "Overlap rub-out diameter in percent %.";
+string TOOLdiamBlow = "Tool diameter for Blow-Up/Rub-Out If value set to 0, no Blow-Up (second isolate) and Rub-Out (free milling) is generated.";
+string TOOLdiamRub = "Rub-Out is off! Tool diameter for sec. isolate If value set, Blow-Up (second isolate) is generated.";
+string MILLfreeYes = "You must set value to Blow-Up.";
+string MILLfreeNo = "No blow up and Rub-Out is generated while value is set to 0.";
+string INFOmirror0 = "Layer 16 (Bottom) not mirrored.";
+string INFOmirror1 = "Layer 16 (Bottom) is mirrored.";
+
+string GENdrilON = "Generate drill data.";
+string GENdrilOFF = "Drills (PAD, VIA, HOLE) are disabled. ";
+string PADdrildiam = "PAD drill diameter";
+string VIAdrilldiam = "VIA drill diameter.";
+string HOLEdrildiam = "HOLE drill diameter.";
+string USErackON = "Use drill rack (1/10mm) see also Tool Assignment.";
+string USErackOFF = "Use only 3 drills (Pad, Via, Hole).";
+string DrillLabel = "HPGL file include drills";
+
+string DIMmiltoolOFF = "Mill diameter for cut out. Cut out OFF.";
+string DIMmiltoolON = "Mill diameter for cut out. Cut out ON.";
+string INFOspacing = "This value determins the minimum length of a edge where a spacer will be set.
" +
+ "Spacers will be set on vertical & horizontal and in HPGL-Format only.
" +
+ "The width of the spacer depends on the diameter of Mill Board/Dim. " +
+ "The value 0 switch off this functioon.";
+
+string INFOresolution = "Integer digits, fractional digits."; // 2011-02-02
+string INFOdeep = "Drilling deep value.";
+string INFOzsafety = "This is the value of lift up the milling tool to change the tool.";
+string INFOzAxisUp = "This is the value of lift up the milling tool to move fast (safty).";
+string INFOzAxisDown = "This is the value of push down the milling tool in to the PCB.";
+
+string INFOvdrill = "Drilling velocity mm/s.";
+string INFOvelocity = "Milling velocity mm/s.";
+string INFOfastVel = "Move velocity (no milling) mm/s.";
+string INFOrpm = "Spindle rotation per minute.";
+string INFOmaxdrill = "The maximum used drill diamter.";
+string DIMdown = "The z parameter for milling Board-Dimension.";
+string PARKinfo = "The park position of milling tool to mirror the board.";
+string SaveInfo = "Menu parameter saved!<\nobr>";
+string FaultDRCdist1 = "!The value for Copper/Dimension is greater than the Mill Board/&Dim diameter.
" +
+ "Check/change Distance Copper/Dimension in Design Rules DRC
" +
+ "or accept a distance of ";
+
+string FaultDRCdist2 = "mm to board dimension.
";
+
+string Error5 = "The CLASS clearance is lower at milling diameter (tool #1)! " +
+ "Befor milling the PCB, start the DRC (Design Rule Check) " +
+ "with the milling diameter (isolate) in CLASS clearance. " +
+ "All Clearance ERROR define a not isolated wire track! "; // 2005-12-22 alf@cadsoft.de
+
+string INFOInaccurat = "Due to possible arithmetic imprecision you have to increase " +
+ "the value for the track width the cutter uses for milling between " +
+ "traces and possible copper planes - Clearance/Isolate to Wire " +
+ "(Arc) - by %.3f mm. Otherwise it could happen that curved wires " +
+ "won't be milled correctly. The isolating area won't be a closed " +
+ "one, then.";
+
+string Mill_mInner_contour = "Process inner milling contours as well, for example, the isolation "
+ "of thermal reliefs inside polygons.";
+
+string MissingDimension = "!Missing Dimension.\nFirst place dimension outline in layer 20.";
+
+string RefDrillDiameter = "Drill diameter ";
+string RefDrillDeep = " Deep ";
+
+string Get_Board_Zero = "Set board &zero"; // 2010-10-13
+string Info_Board_Zero = "Generate a package with two circle and placed this package at the left bottom corner, to mark the machine zero. "; // 2011-02-07
+
+
+/***** deutche Sprache *****/
+if (language() == "de") {
+ INFOhelp = usage;
+ INFOhelpBut = "Hilfe";
+ CANCEL = "-Abbruch";
+ BACK = "-Zurück";
+ ACCEPT = "Akzeptieren";
+ YES = "JA";
+ NO = "NEIN";
+ ON = "EIN";
+ OFF = "AUS";
+ BREAK = "<--";
+ NEXT = "Weiter";
+ DRCCHECK = "Prüfe &CLASS";
+ sprintf(DRC_checked, "Bevor Sie die Fräsdatengenerierung starten, müssen Sie zuerst das Layout mit dem " +
+ "DRC (Design Rule Check) überprüfen. " +
+ "Stellen Sie die Clearance der benutzten CLASS(en) um mindestens %.3f mm größer dem Fräserdurchmesser ein. " +
+ "Jeder Clearance-ERROR bedeutet eine nicht isolierte Leiterbahn! ", Inaccurateness);
+
+ sprintf(INFOpolyClass, "Ist ein füllendes Polygon im Board plaziert, dann muß die Clearance der Design-Rules/Class um %.3f mm größer " +
+ "als der Fräserdurchmesser sein. Damit bei Leiterbahnen die nicht im 0 45 oder 90 Winkel also mit " +
+ "beliebigen Winkel verlegt sind, eventuelle Füllprobleme wegen Rechenungenauigkeit vermieden werden.", Inaccurateness);
+
+ SavePar = "Parameter &sichern";
+ Machine_Menu_Info = "Ein/Ausschalten der Maschinenparamter für die Z-Achse. Nach Ändernung des Paramter werden die aktuellen Einstellungen gespeichert und das ULP neu gestartet.";
+
+ Z_Machine_Menu = "Z-Achsen Menü";
+
+ Script_Used = "SCRIPT-Ausgabe! Die Fräsbahnen (Daten) werden als WIRE in das Board geladen. ";
+
+ INFOinside = "Info Durchbrüche";
+ INFOinnerContour = "
Damit Durchbrüche innerhalb der Platine ebenfalls ausgefräst werden, " +
+ "muß in jedem Durchbruch eine VIA mit dem SIGNAL Namen " +
+ "'~_REAL_OUTLINEMILL_~' platziert werden. " +
+ "Ein Durchbruch darf kein HOLE sein, daß bedeutet,bei kreisrunden "
+ "Durchbrüchen muß ein CIRCLE im Layer Dimension gezeichnet werden.
"; // 2011-10-04
+
+ DRCinfo = "Distance info:
" + // geändert 2010-08-04
+ "Distance Copper/Dimension (siehe auch DRC) das ist die Distanz " + // der Wert wird jetz aus den Design-Reglen gelesen,
+ "zwischen dem Polygon (Kupfer) und der Kontur (Layer 20 Dimension) des Board.
"+ // daher wird der Hinweiß nicht merh beötigt.
+ "" +
+ "Dieser Wert wird aus den Design-Rules gelesen! " +
+ "Benutzen Sie nicht den Wert 0 für Copper/Dimension " +
+ "in den Design-Rules - Distance. " +
+ "
";
+
+ InfoREFERENCE = "Generiert ein spezielles Package mit Referenzkreisen (Circle) im Layer 45 Holes. " +
+ "Platzieren Sie das Package im Layout für fräsen und spiegeln (Bottom Seite) " +
+ "mit Offset und starten das ULP erneut. " +
+ "Als Dateneingabe für die Koordinaten dieser Kreise kann das NC-Drill-File " +
+ "von der NC-Maschine (Excellon) benutzt werden. " +
+ "Es kann auch jedes Package mit der Bezeichnung " + Ref_pac + " " +
+ "als Referenz für den Maschinennullpunkt und die Spiegellinie benutzt werden." +
+ "
" +
+ "Achtung: Die Referenzfangzapfen dürfen nicht über das Maß von Leiterplattenstärke "
+ "minus Frästiefe hinausschauen, sonst werden diese Fangzapfen angefräst, was zum abbrechen des Fräser "
+ "führen kann." +
+ ""; // 2011-02-09
+
+ REFinfo2 = "Klicken Sie auf Masch. Nullpunkt zum generieren " +
+ "eines Referenzpackage aus " +
+ "NC-Drill Daten um Referenzfangzapfen (Circle) im Board zu platzieren für " +
+ "die exakte Berechnung der Fräsdaten bezogen auf den Nullpunkt der " +
+ "NC-Anlage und für die Spiegelung der Unterseite.";
+
+ InfoREFPack = "Es ist ein Referenzpackage platziert, um die Fangzapfen der Fräsmaschine zur Berechnung der " +
+ "Spiegelachse heranzuziehen. Dadurch darf das Ausfräsen aus dem Träger an der Dimension unter Umständen nicht " +
+ "eingeschaltet werden! Wollen Sie die Platine trotzdem aus dem Träger fräsen, überprüfen Sie die " +
+ "Abstände der Circle zum Layer Dimension!"; // englisch!?
+
+ ZeroRef = "Masch. &Nullpunkt";
+
+ No_reftext = "!Keine Referenzdatei geladen.";
+
+ DrBrowse = "Durchsuchen";
+ LoadRefFile = "&Lade ref. Datei";
+ Example_Ref = "Lade Beispiel";
+
+ REFdialog = " - Generiere Referenz-Package und platziere auf Board";
+ DRILLref = " Wähle Drill reference Datei (Holes)";
+ A_refpack = "Ein Referenzpackage ist platziert!";
+ InfoRefHole = " Fangzapfen bohren ";
+ InfoRefOff = "Bohren der Fangzapfen AUS.";
+ InfoRefOn = "Bohren der Fangzapfen EIN.";
+
+ PLACErefpac1 = "Starten Sie nach der Platzierung des Referenzpackage das Script ";
+ PLACErefpac2 = " um die erzeugte LBR aus der USE-Liste zu löschen.";
+
+ SHOWRackFile = "Bohrer definition";
+ SAVE_file = "Outline Datei sichern";
+
+ DrillLabel = "Drills in HPGL Datei enthalten";
+
+ OnlyDrillHpgl = "Nur Bohrdaten erzeugen!.";
+
+ INFOtext1_on = "Top Layer (Oberseite) wird gefräst.";
+ INFOtext16_on = "Bottom Layer (Unterseite) wird gefräst (gespiegelt) ";
+ INFOtext1_off = "Top Layer (Oberseite) AUS.";
+ INFOtext16_off = "Bottom Layer (Unterseite) AUS.";
+ TextInfoPlus = "Zusätzlicher Layer zum fräsen von Texten für Frontplatten. " +
+ "(bzw. Texte in einem Polygon invertiert zu fräsen.)" +
+ "Kann nur in Verbindung mit einem Top- oder Bottom-Layer benutzt werden.";
+
+ TOOLdiamIso = "Werkzeugdurchmesser zum Isolationsfräsen. ";
+ OVERlapIso = "Überlappung von 1. Isolation zu 2. Isolation/Freifräsung in Prozent (%).";
+ OVERlapRubOut = "Überlappung innerhalb der Freifräsung in Prozent %.";
+ TOOLdiamBlow = "Werkzeugdurchmesser für erweiterte Isolation und Freifräsung. " +
+ "Wird der Wert auf 0 gesetzt wird keine erweiterte Isolation " +
+ "und Freifräsung generiert.";
+
+ TOOLdiamRub = "Freifräsung (Rub-Out) ist ausgeschaltet! " +
+ "Es werden nur die Fräswege für eine 2. Isoilation generiert. " +
+ "Wird der Wert auf 0 gesetzt wird keine erweiterte Isolation " +
+ "und Freifräsung generiert.";
+
+ MILLfreeYes = "Es muß ein Wert in Blow-Up (Freifräsung) gesetzt sein.";
+ MILLfreeNo = "Es wird kein 2. Isolationsfräsen plus Freifräsen generiert, da der Wert auf 0 gesetzt ist.";
+ INFOmirror0 = "Layer 16 (Bottom) wird NICHT gespiegelt.";
+ INFOmirror1 = "Layer 16 (Bottom) wird gespiegelt.";
+
+ GENdrilON = "Bohrdaten generierung aktiv.";
+ GENdrilOFF = "Bohrdaten generierung (PAD, VIA, HOLE) ausgeschaltet. ";
+
+ PADdrildiam = "PAD Bohrdurchmesser.
" +
+ "Wenn kein Rack benutzt wird, dann werden alle PADs " +
+ "mit diesem Durchmesser gebohrt. " +
+ "Wenn [] Use Rack aktiviert ist, dann werden die PADs " +
+ "in 1/10 mm Abstufung gebohrt. Siehe Tool Assignment.
";
+
+ VIAdrilldiam = "VIA Bohrdurchmesser.
" +
+ "Wenn kein Rack benutzt wird, dann werden alle VIAs " +
+ "mit diesem Durchmesser gebohrt. " +
+ "Wenn [] Use Rack aktiviert ist, dann werden die VIAs " +
+ "in 1/10 mm Abstufung gebohrt. Siehe Tool Assignment.
";
+
+ HOLEdrildiam = "HOLE Bohrdurchmesser.
" +
+ "Wenn kein Rack benutzt wird, dann werden alle HOLEs "
+ "mit diesem Durchmesser gebohrt. " +
+ "Wenn [] Use Rack aktiviert ist, dann werden die HOLEs " +
+ "in 1/10 mm Abstufung gebohrt. Siehe Tool Assignment.
";
+
+ USErackON = "Benutze Bohrertabelle (1/10mm), siehe auch Tool Assignment. " +
+ "Die Bohrungen werden auf 1/10 mm gerundet gebohrt.";
+ USErackOFF = "Benutze nur 3 Bohrer für Pad, Via, Hole.
" +
+ "Alle PADs, VIAs und HOLEs werden mit den im Menu " +
+ "angegeben Werten gebohrt.
";
+
+ DIMmiltoolOFF = "Fräserdurchmeser zum ausfräsen aus dem Träger. Ausfräsen AUS.";
+ DIMmiltoolON = "Fräserdurchmeser zum ausfräsen aus dem Träger. Ausfräsen EIN.";
+
+ INFOspacing = "Dieser Wert definiert die Mindestkantenlänge der Platine damit " +
+ "ein Haltesteg (Spacer) erzeugt wird. " +
+ "Haltestege werden nur an horizontalen oder vertikalen Kanten erzeugt. " +
+ "Die Breite der Stege ist abhängig vom Durchmesser des Fräser " +
+ "(Mill Board/Dim). Der Wert 0 schaltet die Funktion ab.";
+
+ INFOresolution = "Auflösung, Vor- Nachkommastellen der Koordinaten."; // 2011-02-02
+ INFOdeep = "Bohrtiefe in/durch die Platine.";
+ INFOzsafety = "Der Wert um den der Fräser in der Z-Achse über das Werkstück " +
+ "gefahren wird, z.B. für Werkzeugwechsel (Rueckzugsebene).";
+
+ INFOzAxisUp = "Der Wert um den der Fräser in der Z-Achse über das Werkstück " +
+ "gefahren wird, für Schnellvorschub (Sicherheitsabstand).";
+
+ INFOzAxisDown = "Die Frästiefe der Z-Achse.";
+
+ INFOvdrill = "Bohrgeschwindigkeit mm/s.";
+ INFOvelocity = "Fräsgeschwindgkeit mm/sec.";
+ INFOfastVel = "Schnellvorschub (Geschwindigkeit) mm/s";
+ INFOrpm = "Spindlumdrehungen pro Minute";
+ INFOmaxdrill = "Der maximal nutzbare Bohrerdurchmesser. " +
+ "Grössere Bohrungen werden gefräst! " +
+ "Siehe auch Tool Assignment.";
+
+ DIMdown = "Z-Parameter für ausfräsen der Boardkontur.";
+ PARKinfo = "Die Parkposition des Fräskopf zum umdrehen der Leiterplatte.";
+
+ SaveInfo = "Einstellungen gespeichert!<\nobr>";
+
+ FaultDRCdist1 = "!Der Wert von Copper/Dimension ist größer als der Radius von Mill Board/Dim. " +
+ "Überprüfen Sie den Wert von Distance Copper/Dimension in den Design Rules (DRC) " +
+ "oder akzeptieren Sie die Distanz von ";
+ FaultDRCdist2 = " mm zur Boardaussenkannte.";
+
+ PlaceVIA = "platziere VIA";
+
+ Error5 = "Die CLASS-Clearance ist kleiner als der Fäserdurchmesser von Tool #1! " +
+ "Dadurch kann nicht alles isoliert (gefräst) werden. " +
+ "Stellen Sie die CLASS-Clearance auf den Fräserdurchmesser und starten Sie den DRC. " +
+ "Jeder Clearance-Error bedeutet eine nicht isolierte Leiterbahn!";
+
+ sprintf(INFOInaccurat, "Wegen Rechenungenauigkeiten muß für Fräswege zwischen den Leiterbahnen und " + // 2006-02-15
+ "einem evtl. vorhandenem Füll-Polygon die Spurbreite (Clearance/Isolate) zu WIRE (Arc) um " +
+ "%.3f mm breiter eingestellt werden, da es sonst an gebogenen Leiterbahnsegmenten " +
+ "zu Fehlerhaften nicht berechneten Fräswegen kommen kann. Also die gefräste Isolation nicht " +
+ "komplett geschlossen ist. ",
+ Inaccurateness);
+
+ Mill_mInner_contour = "Auch Innenkonturen fräsen (z.B. die Isolation von Termal-Stegen von Polygonen). " + // 2010-01-25
+ "Daruch kann es vorkommen, daß wenn ein (Masse) Polygon im Layout vorhanden ist, " +
+ "die Isolation doppelt, mit entsprechendem Versatz gefräst wird. " +
+ "Die Ursache ist, daß sich eine Kontur an den Leiterbahnzug anlegt, und eine entgegengesetzt " +
+ "verlaufende Kontur an die berechnete Kontur des (Masse) Polygon. " +
+ "Soll ein evtl. zweifaches Freifräsen wegen diesem Umstand verhindert werden, so schalten " +
+ "Sie die Option Milling [] inner contour einfach ab.";
+
+ MissingDimension = "!Keine Dimension.\nPlatzierern Sie zuerst die Aussendimension in Layer 20.";
+ RefDrillDiameter = "Bohrduchmesser ";
+ RefDrillDeep = "Tiefe ";
+ Get_Board_Zero = "Setze Maschinen-&Nullpunkt an linke unter Ecke"; // 2010-10-13
+ Info_Board_Zero = "Erzeugt ein Package mit zwei Kreisen und platziert es an der linken untere Ecke des Board als Manschinen-Nullpunkt."; // 2011-02-07
+} // *** ende language de ***
+
+// ###########################
+// The various output devices
+// ###########################
+enum { none, devScript, devHPGL, devISEL, devCNC };
+int Defaultdevice = devScript; // set default device
+int SelectedDevice = Defaultdevice; // overwritten by load_menu_values()
+int LastSelectedDevice;
+string HPGL_TOP_ext = "_top.plt"; // Namenserweierung bei HPGL für Daten des Top-Layer 2014-10-06
+
+string Device;
+string Layer1, Layer16;
+int SelectedLayer1 = 0;
+int SelectedLayer16 = 0;
+int SelectedPlusLayerTop = 0; // 2005-06-08
+int SelectedPlusLayerBot = 0; // to milling a Text inverse in a copper polygon
+int Mirror_On = 1; // flag can switch mirror off for Layer 16
+
+int ToMillLayer1 = 0;
+int ToMillLayer16 = 0;
+int OutlineMillSignalLayer; // 2004-10-05
+
+string DeviceNames[] = { "Select a device", "SCRIPT", "HPGL", "ISEL", "CNC" };
+string DeviceExt[] = { ".~~~" , ".scr", ".plt", ".ncp", ".ncd" };
+string DefaultSuffix = DeviceExt[SelectedDevice];
+string Ftop = ""; // Fräsdaten für HPGL in zwei Dateien schreiben. 2013-04-30
+ // Die Fräse der FU Berlin optimiert die Fräs- und Bohrwege,
+ // so daß alle Bohrungen und Fräswege mit dem selben Werkzeug zusammengefasst werden.
+
+real GridDistance;
+int GridUnit;
+int GridUnitdist;
+string Gridunit[];
+ Gridunit[GRID_UNIT_MIC] = "mic";
+ Gridunit[GRID_UNIT_MM] = "MM";
+ Gridunit[GRID_UNIT_MIL] = "mil";
+ Gridunit[GRID_UNIT_INCH] = "INCH";
+
+int InitDone = 0; // nur einmal Initialisieren, siehe DeviceInit()
+
+// * set default device and values *
+// Parmameters
+// *** The milling tool diameter ***
+real MillToolOutl = 0.2;
+real MillToolIsolate = 0.0; // das Isolate des Polygon zum Isolationsfräsen
+real minClearance = 0.15; // to check can filled the complete aray with the
+ // special polygon width
+int OverlapOutlPercent = 20; // percent, to avoid fine copper lines while milling out the area
+real MillToolFree = 0.8; // Blow up & free pouring
+int Millfreeyes = 1; // free pouring on/off
+int MInner_contour = 1; // milling positiv/negativ polygon contour 2010-01-25
+
+int Lift_Off = 1; // ** do not lift up the tool for Rubout of polygon filling **
+ // ** if change the direction and X-coordinate < tool radius **
+
+int OverlapRubOutPercent = 20; // percent, to avoid fine copper lines while milling out the area
+real DrillPad = 0.8;
+real DrillVia = 0.8;
+real DrillHole = 0.8;
+int Onlydrill = 0; // output only drill on HPGL
+int Generatedrills = 1; // aktivate drills only in one export file
+ // while drills crashed in 2. run.
+
+real Max_Drill_Diameter = 2.0; // the maximum of drill diameter in mm of T-Code table for ISEL and CNC
+ // editierbar gemacht 2004-12-01
+
+real DimensionMillTool = 2.0; // milling board outline from holder
+int Dim_on_off = 1; // 2006-01-25
+int MillOnlyContour = 0; // 2011-03-10 nur Kontur fräsen
+
+enum { Res32, Res33, Res34, Res3_2, Res3_3, Res3_4 }; // CNC-Resolution ohne und mit Komma 2011-02-03
+int CNCmillResolution = Res3_2; // Auflösung der Koorinaten Vor- Nachkommastellen 2011-02-02
+real Drill_z_deep = -3.8; // drill deep for drilling pads, via, holes
+real Mill_z_safety = 2.0; // safety distance to pcb for change tool
+real Z_down = -2.0; // milling z-axis down for milling
+real Actualmilldeep; // 2011-01-27 in den Funktionen wird nur die aktuelle Frästiefe benutzt
+int Spindle_rpm = 15000; // spindel rotation per minute
+real Tool_vel = 2; // velocity to milling
+real Fast_vel = 5; // velocity to move tool
+real Drill_Vel = 0.5; // drill velocity to drilling in to pcb
+real ParkZposition = 80.0; // 80mm Park poistion to turn pcb for 2.nd side milling
+real ParkXposition = 10.0; // 10mm Park poistion to turn pcb for 2.nd side milling
+real ParkYposition = 10.0; // 10mm Park poistion to turn pcb for 2.nd side milling
+real Z_dimension = -3.8; // 3.8mm Z-Down for milling dimension (contur)
+
+real DistanceDimension;
+real Distance_Copper_Dimension = 0.0001; // default value
+real Holder_Spacing = 10.0; // in mm, the distance to make a holder spacing for outline milling.
+
+// Class check
+string Clearance_check;
+
+// Design-Rules-Chek 2010-10-28
+int UseClass = 0;
+int MinDistCLass = 0;
+string drufile = "";
+string DRUvalues[];
+int DRUlcnt = 0;
+int DRC_changed = 0;
+string DRC_changed_message = "";
+
+// Design Rule Ceck - Values from .dru 2010-01-26
+real mtCopper[];
+real mtIsolate[];
+real minDistWireWire;
+real minDistWirePad;
+real minDistWireVia;
+real minDistPadPad;
+real minDistPadVia;
+real minDistViaVia;
+real minDistSmdPad;
+real minDistSmdVia;
+real minDistSmdSmd;
+real MOI = 0.0; // round((MillToolOutl + Inaccurateness) *1000) / 1000; // Problem bei vergleich von Realzahlen
+real MDW = 0.0; // round(minDistWireWire * 1000) / 1000;
+
+string LayerStack;
+string DelPoly; // 2012-01-13 to delete vitual polygon and via outside off bord
+
+// The HPGL PEN list
+enum { PadDrill = 1, ViaDrill, Contour, BlowUp_RubOut, HoleDrill, DimensionLine, DrillRef, MirrorPCB, nrMaxDrillDiameter } // HPGL Pen select "SP.."
+ /*** MirrorPCB = TOOL (PEN) #8 is reseved for switch PCB on milling machin for milling second side ***/
+ /*** nrMaxDrillDiameter == TOOL (PEN) 9 is reseved for milling drill biger then max drill diameter ***/
+string PenList[];
+PenList[PadDrill] = "PadDrill";
+PenList[ViaDrill] = "ViaDrill";
+PenList[Contour] = "Contour";
+PenList[BlowUp_RubOut] = "Blow-Up/Rub-Out";
+PenList[HoleDrill] = "HoleDrill";
+PenList[DimensionLine] = "DimensionLine";
+PenList[DrillRef] = "DrillRef";
+PenList[MirrorPCB] = "MirrorPCB";
+PenList[nrMaxDrillDiameter] = "max.Drill-Diameter"; // 2013-04-18
+
+string sToolValue[]; // Tool diameter as String
+
+enum { HPGLsolution = 1016 } // Inch/1016 = 0.025 mm
+enum { ISELsolution = 1000 } // mm/1000 Isel format
+
+real Mirror = 1.0;
+int Mill_OffsetX = 0;
+int MillMirr_Offset = 0;
+int Ref_null_offsetY = 0;
+int Ref_offsetX[];
+int Ref_offsetY[];
+int Ref_cnto = 0;
+real RefHoleCircle = 3.0; // Der Durchmesser für den Circle der im Referenz-Package für den Maschinennullpunkt
+ // benutzt wird.
+string Mirror_axis;
+real Drill_mirrorPCB = -1; // for message to mirror the PCB by personal
+
+int MachineMenuOn = 1; // 2011-10-20 maschine menu in seperate Tab
+ // * for www.cnc-papst.de * 2005-06-23
+
+int DrillRefOn = 0; // drill first the referenz holes to fix the pcb on machine
+real DrillRefDiameter = 3.0; // the diameter of referenz holes
+real DrillRefDeep = -6; // the deep of referen holes
+
+// to swap for menu
+real MDrillPad = DrillPad;
+real MDrillVia = DrillVia;
+real MDrillHole = DrillHole;
+real MDimensionMillTool = DimensionMillTool;
+real MHolder_Spacing = Holder_Spacing;
+real MMillToolOutl = MillToolOutl;
+real MOverlapOutlPercent = OverlapOutlPercent;
+real MMillToolFree = MillToolFree;
+real MOverlapRubOutPercent = OverlapRubOutPercent;
+int Mmillfreeyes = Millfreeyes;
+real Mz_down = Z_down;
+real Mdrill_z_deep = Drill_z_deep; // drill deep for drilling pads, via, holes
+real Mmill_z_safety = Mill_z_safety; // safety distance to pcb for change tool
+int Mspindle_rpm = Spindle_rpm; // spindel rotation per minute
+real Mtool_vel = Tool_vel;
+real Mfast_vel = Fast_vel;
+real MDrill_Vel = Drill_Vel;
+real MparkXposition = ParkXposition;
+real MparkYposition = ParkYposition;
+real MparkZposition = ParkZposition;
+real Mz_dimension = Z_dimension;
+int Mdim_on_off = Dim_on_off;
+int MCNCmillResolution = CNCmillResolution;
+real CNCsolution = 100; // mm/100 CNC format (default)
+
+int MdrillRefOn = 0;
+real MdrillRefDiameter = 3.0;
+real MdrillRefDeep = -6.0;
+
+string TrueOutline_coordinate; // The generatet polygon outlines for the milling polygon 2009-03-31
+ // get polygon coordinate from actual design.
+
+string ReservedOutlineSignalName = "_OUTLINES_"; // reserved Signal name for special polygon
+string OutlineMillSignal = "~_REAL_OUTLINEMILL_~"; // used Signal name for calculate the real outline
+string PassDimensionPoly = "PASSDIMESION"; // the true output line, defined by Layer 20 Dimension
+string Pass2 = "PASS_2";
+string PassPour = "PASS_POUR";
+string PassOutmill = "PASS_OUTLINE";
+string InPassDimensionPoly;
+string InPass2;
+string InPassPour;
+string InPassOutmill;
+int menu = 0;
+int cntcontvia = 0; // 2011-10-04
+
+string Showpic[];
+string info; // 2011-10-20 first tab
+string Infotext;
+string zinfo; // 2011-10-20 second tab
+string zInfotext;
+
+string Path;
+string Xfile, MillFileName;
+
+string Fillstyle16 = "CloseDot";
+string Fillstyle1 = "Interleave"; // fill style for layer to return the millings
+ // as wire in to the board layer (if Device == SCRIPT)
+
+string Machineparameter = "";
+
+// ------------- use a rack for drilling extend the tool list ---------------------
+int UseRack = 0; // Use drills with 1/10 mm as in generated Rack
+ // or use only 3 drills 2005-05-23
+real Drill_tools[]; // 2005-05-24
+string Drill_comment[];
+int Cnt_tools = MirrorPCB+2; // the last milling tool
+string Tool_Rack_string;
+string Drilltoolsplus;
+
+int Nc_drill[];
+int Nc_drilld[];
+real Nc_drilldround[];
+int Nc_drillx[];
+int Nc_drilly[];
+int Cnt_ncdrill = 0;
+int Dindex[];
+int index[];
+//int Mark = -1;
+
+int Cntpcw; // the counter of contour wire 2006-02-08
+int Pcwx[], Pcwy[]; // the polygon countour coordinates to calcultae
+
+int maxX = INT_MIN; // 2010-10-13
+int minX = INT_MAX;
+int maxY = INT_MIN;
+int minY = INT_MAX;
+
+
+/* -------------------------------------------------------------------------------
+ ? weiterer Isolationswert (noch eine Fräserbreite) zwischen Isolation und Blow up
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+CNC-Programmierung:
+
+datron.de:
+
+ Vom CAT3D Konverter unterstützte Befehle der DIN 66025 (ISO)
+ G 00 Positionierung / Eilgang
+ G 01 Linearinterpolation
+ G 02 Kreisinterpolation UZ
+ Schraubenlinieninterpolation UZ
+
+ G 03 Kreisinterpolation GUZ
+ Schraubenlinieninterpolation GUZ
+
+ G 20 Maßangaben Zoll
+ G 21 Maßangabe metrisch
+
+ G 40 Werkzeugradiuskorrektur, Löschung
+ G 41 Werkzeugradiuskorrektur, links
+ G 42 Werkzeugradiuskorrektur, rechts
+ G 90 Absolute Maßangabe
+ G 91 Inkrementale Maßangabe
+
+ Weitere ISO-Code Befehle, die vom CATPC berücksichtigt werden:
+ N Satznummer wird ignoriert
+ F Vorschub
+ T Werkzeugwechsel
+
+
+ENGELHARDT GmbH - BedienPCNC.pdf
+
+ G00 POSITIONIEREN IM EILGANG
+ G01 LINEARINTERPOLATION
+ G36 WERKZEUGWECHSEL
+ G74 REFERENZPUNKT FAHREN
+
+ M00 PROGRAMMIERTER HALT
+ M01 PROGRAMMIERTER HALT MIT AKUSTISCHEM SIGNAL
+------------------------------------------------------------------------------- */
+
+
+/************* Functions ******************/
+int viewtest(string nachricht, string cmd) {
+ dlgDialog("Debug/Test") {
+ dlgLabel(nachricht);
+ dlgHBoxLayout dlgSpacing(900);
+ dlgHBoxLayout {
+ dlgTextEdit(cmd);
+ dlgVBoxLayout dlgSpacing(250);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("OK") dlgAccept();
+ dlgSpacing(400);
+ dlgPushButton(CANCEL) { dlgReject(); return -1; }
+ }
+ };
+ return 0;
+}
+
+string filenametop(string s) { // wenn Device HPGL, dann extra Dateiname für Toplayer
+ if (SelectedDevice == devHPGL) {
+ return filesetext(s, HPGL_TOP_ext); // 2014-10-06
+ }
+ return s;
+}
+
+// wait in seconds
+void wait(int sec) {
+ int t = time();
+ while(t+sec > time() );
+ return;
+}
+
+void Warning(string Message, string Details) {
+ dlgMessageBox("Warning: " + Message + " " + Details, "OK");
+ return;
+}
+
+void Fatal(string Message, string Details) {
+ dlgMessageBox("ERROR: " + Message + "
Möchten Sie diese Datei jetzt erzeugen und speichern? ";
+
+ else
+ message = "No Design Rules file found: " +
+ drufile +
+ "
Do you want to create and save this file now? ";
+
+ dlgDialog("Mill Outlines Design Rules") {
+ dlgLabel(message);
+ dlgStretch(1);
+ dlgHBoxLayout {
+ dlgPushButton("+"+YES) {
+ dlgAccept();
+ exit("SET Interface.PreferredUnit 2;\nDRC SAVE '" + drufile + "';\nRUN '" + argv[0] + "'"); // 2010-02-08 setze Einheiten auf metrisch
+ }
+ dlgPushButton(CANCEL) { dlgReject(); exit(0); }
+ dlgStretch(1);
+ }
+ };
+ }
+ return drufile;
+}
+
+string checkClassClear(UL_BOARD B) { // check CLASS Clearance
+ string classchanged = "";
+ Clearance_check = "";
+ real ClassClearance;
+ int CheckDrcWirWire = 0;
+ //real MOI = round((MillToolOutl + Inaccurateness) *1000) / 1000; // Problem bei vergleich von Realzahlen
+ //real MDW = round(minDistWireWire * 1000) / 1000;
+ if (MDW >= MOI) return ""; // 2012-02-09 // 2011-03-10 nur wenn DRC-Clearance kleiner MillToolOutl, dann prüfe CLASSen
+ else CheckDrcWirWire = 1;
+
+ B.classes(CL) {
+ if (Class_used[CL.number]) { // nur benutzte Classen prüfen 2010-02-05
+ UseClass = 1;
+ string s;
+ int n;
+ for (n = 0; n <= CL.number; n++) {
+ ClassClearance = u2mm(CL.clearance[n]);
+ if (ClassClearance < MillToolOutl + Inaccurateness) { // *** 2009-02-05 ***
+ MinDistCLass = n+1;
+ ClassClearance = MillToolOutl + Inaccurateness;
+ sprintf(s, "CLASS %d '%s' %.8fmm %.8fmm %.8fmm %d:%.8fmm;\n",
+ CL.number,
+ CL.name,
+ u2mm(CL.width),
+ u2mm(CL.clearance),
+ u2mm(CL.drill),
+ n,
+ ClassClearance
+ );
+ SClass[CL.number] += s;
+ classchanged += s;
+ }
+ }
+ }
+ }
+ if (classchanged) {
+ string drc_clearance_wire_wire;
+ if (language() == "de") {
+ sprintf(Clearance_check, "Setze Netzklassen-Clearance: "+
+ "Durchmesser Tool #1 = %.8f mm plus Rechenungenauigkeit = %.3f "+
+ "Setze Class Clearance auf %.8f mm oder Fräserdurchmesser <= kleinster CLASS Clearance - %.3f.
" +
+ "Starten Sie anschließend den DRC und überprüfen Sie die Abstände.",
+ MillToolOutl, Inaccurateness,
+ MillToolOutl + Inaccurateness,
+ Inaccurateness
+ );
+ sprintf(drc_clearance_wire_wire, "Prüfen Sie auch im DRC Clearance Wire/Wire: %.8f, oder ändern Sie die CLASS(en).", minDistWireWire); // 2011-03-10
+ }
+ else {
+ sprintf(Clearance_check, "Set Clearance of Net Classes: "+
+ "Diameter of tool #1 = %.8f mm plus Inaccurateness = %.8f "+
+ "Set Clearance to %.8f mm or use a milling tool <= lowest clearance value - %.3f.
");
+ dlgCell( 5, 1) dlgLabel("");
+ dlgCell( 5, 2) dlgLabel("");
+ dlgCell( 5, 3) dlgLabel("");
+
+ dlgCell( 6, 0) dlgLabel("* Park pos. Z ");
+ dlgCell( 6, 1) dlgRealEdit(ParkZposition);
+ dlgCell( 6, 2) dlgLabel(" mm ");
+ dlgCell( 6, 3) dlgPushButton("Park Info") {
+ zinfo = Showpic[35];
+ zInfotext = PARKinfo;
+ }
+
+ dlgCell( 1, 9) dlgSpacing(8);
+
+ dlgCell( 1, 5) dlgLabel("* Spindle ");
+ dlgCell( 1, 6) dlgIntEdit(Spindle_rpm);
+ dlgCell( 1, 7) dlgLabel(" rpm ");
+ dlgCell( 1, 8) dlgPushButton("RPM Info") {
+ zinfo = Showpic[31];
+ zInfotext = INFOrpm;
+ }
+
+
+ dlgCell( 2, 5) dlgLabel("* Tool velocity ");
+ dlgCell( 2, 6) dlgRealEdit(Tool_vel);
+ dlgCell( 2, 7) dlgLabel(" mm/s ");
+ dlgCell( 2, 8) dlgPushButton("Velocity Info") {
+ zinfo = Showpic[29];
+ zInfotext = INFOvelocity;
+ }
+
+ dlgCell( 3, 5) dlgLabel("* Fast velocity ");
+ dlgCell( 3, 6) dlgRealEdit(Fast_vel);
+ dlgCell( 3, 7) dlgLabel(" mm/s ");
+ dlgCell( 3, 8) dlgPushButton("Fast Info") {
+ zinfo = Showpic[30];
+ zInfotext = INFOfastVel;
+ }
+
+
+ dlgCell( 4, 5) dlgLabel("* Drill velocity ");
+ dlgCell( 4, 6) dlgRealEdit(Drill_Vel);
+ dlgCell( 4, 7) dlgLabel(" mm/s ");
+ dlgCell( 4, 8) dlgPushButton("V-Drill Info") {
+ zinfo = Showpic[32];
+ zInfotext = INFOvdrill;
+ }
+
+ dlgCell( 4, 9) dlgLabel(" * currently not used.");
+
+ dlgCell( 6, 5) dlgLabel("* Park pos. X ");
+ dlgCell( 6, 6) dlgRealEdit(ParkXposition);
+
+
+ dlgCell( 6, 8) dlgLabel("* Park pos. Y ");
+ dlgCell( 6, 9) dlgRealEdit(ParkYposition);
+
+ }
+ }
+ dlgStretch(1);
+ }
+ }
+ }
+ } // tab Ende
+ } // tab Widget Ende
+ dlgStretch(1); // 2013-02-19
+ // the file Path/name
+ dlgHBoxLayout {
+ dlgGridLayout {
+ dlgCell( 0, 1) dlgSpacing(15);
+ dlgCell( 0, 2) dlgSpacing(500);
+ dlgCell( 1, 1) { dlgStretch(1); dlgLabel("Mill fil&e"); }
+ dlgCell( 1, 2) dlgStringEdit(Xfile);
+ dlgCell( 1, 3) dlgPushButton(DrBrowse) {
+ string fn = dlgFileSave(SAVE_file, Xfile);
+ if (fn) {
+ Xfile = fn;
+ MillFileName = fn;
+ info = Showpic[1];
+ }
+ }
+ }
+ dlgStretch(1);
+ }
+ dlgHBoxLayout dlgSpacing(600);
+ dlgLabel("Design Rules:" + dru_file);
+ dlgHBoxLayout {
+ dlgStretch(0);
+ dlgPushButton("OK") {
+ //Z_up = Z_down * -1.0; // 2011-01-27 Up und Down muss immer der gleiche Wert sein!
+ if (!SelectedDevice) Error("No device selected!", "Please select a device.", NEXT, CANCEL);
+ else {
+ if (DimensionMillTool) { // **** if used ? ****
+ DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2; // 2009-02-05
+ if (DistanceDimension < 0) { // 2009-02-05 correct wire width for millout
+ string d, d2;
+ sprintf(d, "%.8f", DistanceDimension/2); // 2009-02-05
+ if (language() == "de") { // 2008-11-12
+ sprintf(d2, "Achtung! Die Platine wird um %.8f mm ausserhalb der Dimension aus dem Träger gefäst!",
+ DistanceDimension/2);
+ }
+ else {
+ sprintf(d2, "Attention!\nThe millout is %.8f mm outher the dimension!",
+ DistanceDimension/2);
+ }
+ fault = dlgMessageBox(FaultDRCdist1 + d + FaultDRCdist2 + d2, ACCEPT, BACK);
+ DistanceDimension = 0;
+ }
+ }
+ if(!Onlydrill) { //
+ if (!MillToolOutl) {
+ fault = Error("Illegal diameter: 0", "The Isolate diameter must be greater than zero.", NEXT, CANCEL);
+ }
+
+ if (!SelectedLayer1 && !SelectedLayer16) {
+ if (!MillOnlyContour) { // 2011-03-10 nur Kontur fräsen
+ fault = Error("No layer selected!", "Select layer 1 or 16 or both.", BREAK, CANCEL);
+ }
+ }
+
+ if (Clearance_check) {
+ fault = Error(Error5, "" + Clearance_check + "", "Change &Tool #1", DRCCHECK);
+ if (fault) exit("CLASS");
+ fault = 1;
+ }
+ }
+ if (Holder_Spacing && Holder_Spacing < DimensionMillTool*3) { // 2011-09-28 nur wenn der Fräsweg min. 3 mal länger als der Fräser im Durchmesser ist.
+ fault = Error("", "Holder spacing to smal.", "OK", BACK);
+ }
+ if (!fault) {
+ if (MillOnlyContour) dlgMessageBox("!Milling only Dimension selected.", "OK");
+ MillFileName = Xfile;
+ if (test) output(filesetext(B.name, "-cmd.txt"), "at");
+ Max_Drill_Diameter = round(Max_Drill_Diameter*10) / 10;
+ dlgAccept();
+ }
+ }
+ }
+ dlgPushButton(CANCEL) {
+ dlgReject();
+ exit(0);
+ }
+ dlgSpacing(32);
+ dlgPushButton(SavePar) save_defaults();
+ dlgSpacing(32);
+ dlgPushButton(INFOinside) {
+ dlg_PlaceVia();
+ }
+ dlgStretch(5);
+ dlgLabel(Version);
+ dlgStretch(1);
+ dlgPushButton(INFOhelpBut) dlgMessageBox(INFOhelp, "OK");
+ }
+ };
+ }
+
+ Device = DeviceNames[SelectedDevice];
+ if (SelectedLayer1) {
+ ToMillLayer1 = SelectedLayer1;
+ OutlineMillSignalLayer = SelectedLayer1; // set OutlineMillSignalLayer to last used layer
+ }
+ if (SelectedLayer16) {
+ ToMillLayer16 = SelectedLayer16;
+ OutlineMillSignalLayer = SelectedLayer16;
+ }
+
+ fileerror();
+ output(MillFileName, "wt"); // creat new file
+ Ftop = filenametop(MillFileName);
+ if (Ftop != MillFileName) output(Ftop, "wt"); // erzeuge zusätzliche Datei für Top bei HPGL 2013-04-30
+ if (fileerror()) exit (-1);
+
+ output(filesetext(B.name, "_display~tmp.scr"), "wtD") {
+ printf("DISPLAY NONE 17 18 20 ");
+ board(B) {
+ B.layers(L) {
+ if (L.visible) printf("%d ",L.number);
+ }
+ }
+ switch (SelectedDevice) {
+ case devScript: if (MillOnlyContour) { // 2011-03-10
+ printf(" %d %d ", 1 + 102, 118);
+ }
+ else {
+ if (SelectedLayer1) printf(" %d %d %d", 1 + 100, 1 + 101, 1 + 102); // 2008-11-12
+ if (SelectedLayer16) printf(" %d %d %d", 16 + 100, 16 + 101, 16 + 102);
+ if (SelectedPlusLayerTop) printf(" %d", SelectedPlusLayerTop + 100);
+ if (SelectedPlusLayerBot) printf(" %d", SelectedPlusLayerBot + 100);
+ printf(" 144 145 "); // 2013-02-19 die beiden Layer auch noch anzeigen
+ printf(";#5076 layer reset\n");
+ }
+ break;
+
+ case devHPGL:
+ output(filesetext(MillFileName,".pli"), "wt") {
+ printf("# Plot info generated by:\n# %s\n# %s\n# from %s\n# at %s\n# Drill tools\n", argv[0], Version, B.name, t2string(time()) );
+ }
+ toolFiles(); // generate Rack and Wheel file
+ break;
+
+ case devISEL:
+ output(filesetext(MillFileName,".isi"), "wt") {
+ printf("IMF_PBL_V1.0 - PICTURES BY PC - Eagle mill-outline.ulp\n");
+ printf("; Plot info generated by %s %s\n# from %s\n# at %s\n# Used tools\n", argv[0], Version, B.name, t2string(time()) );
+ }
+ toolFiles(); // generate Rack and Wheel file
+ break;
+
+ case devCNC:
+ output(filesetext(MillFileName,".nci"), "wt") {
+ printf("#M48 Plot info generated by %s %s\n# from %s\n# at %s\n# Used tools\n", argv[0], Version, B.name, t2string(time()) );
+ }
+ break;
+ }
+ }
+ if (MillOnlyContour) { // ***** 2011-03-10 *****
+ string omillout;
+ string Cmd;
+
+ sprintf(Cmd, "LAYER Milloutlines %d;\n", 1 + 102);
+
+ DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2;
+ if (DistanceDimension < 0) { // 2009-02-05 correct wire width for millout
+ DistanceDimension = 0;
+ }
+
+ real x1 = u2mm(B.area.x1) - DimensionMillTool/2, y1 = u2mm(B.area.y1) - MillToolFree/2,
+ x2 = u2mm(B.area.x2) + DimensionMillTool/2, y2 = u2mm(B.area.y2) + MillToolFree/2;
+
+
+ sprintf(omillout, "grID MM;\nDISPLAY NONE 17 %d;\n", ToMillLayer1 + ToMillLayer16);
+ Cmd += omillout;
+ // ** make temporary Net for Normal Polygon Orphen OFF
+ // ** to milling the pcb-contour with holder **
+ sprintf(omillout, "chANGE laYER 1;\n"); /**** mit dieser Option immer von Top fräsen *****/
+ Cmd += omillout;
+ Cmd += "SET WIRE_BEND 2;\n";
+ sprintf(omillout, "VIA '%s' (%.8f %.8f);\n",
+ OutlineMillSignal,
+ x1 - DimensionMillTool/2, // plaziere Via innerhalb des Polygon
+ y1 - DimensionMillTool/2 // damit es kein Orphan wird.
+ );
+ Cmd += omillout;
+ sprintf(omillout, "CHANGE ISOLATE 0;\n");
+ Cmd += omillout;
+ sprintf(omillout, "CHANGE ORPHANS OFF;\n");
+ Cmd += omillout;
+ Cmd += "SET WIRE_BEND 0;\n";
+ Cmd += "CHANGE RANK 1;\n"; // 2006-07-26
+
+
+ sprintf(omillout, "POLyGON '%s' %.8f (%.8f %.8f) (%.8f %.8f) (%.8f %.8f);\nRATSNEST;\n",
+ OutlineMillSignal, DistanceDimension,
+ x1 - DimensionMillTool - Distance_Copper_Dimension,
+ y1 - DimensionMillTool - Distance_Copper_Dimension,
+ x2 + DimensionMillTool + Distance_Copper_Dimension,
+ y2 + DimensionMillTool + Distance_Copper_Dimension,
+ x1 - DimensionMillTool - Distance_Copper_Dimension,
+ y1 - DimensionMillTool - Distance_Copper_Dimension);
+ Cmd += omillout;
+ Cmd += "SET WIRE_BEND 2;\n"; // 2011-09-28
+ Cmd += RUN_pass(PassOutmill);
+ exit(Cmd);
+ }
+ generateTruePolygonOutlines(); // generate the true Dimension outline as polygon.
+ }
+}
+
+// *** generate Copper pouring ***
+void genInPassPour(int Layer) {
+ string fname = MillFileName;
+ if (Layer == 1) fname = filenametop(MillFileName); // 2013-04-30
+ if(SelectedLayer16 && ToMillLayer16) {
+ if (Mirror_On) {
+ Mirror = -1.0; // *** mirror flag for Layer 16 *** 2005-06-21
+ }
+ else {
+ MillMirr_Offset = 0; // ** reset mirror offset **
+ Mirror = 1.0;
+ }
+ }
+ else if(SelectedLayer1 && ToMillLayer1) {
+ MillMirr_Offset = 0; // ** reset mirror offset **
+ Mirror = 1.0;
+ }
+ output(fname, "at") {
+ if (test) printf(";#*** InPassPour\n");
+ if (SelectedDevice == devScript) printf("\n# 2. isolate\n");
+ if (InPassPour && MillToolFree == 0) return; // 2011-02-08
+ printf("%s", WriteOutlines(ReservedOutlineSignalName, Layer ));
+ }
+ return;
+}
+
+// *** generate outlines by polygon.contours.wires ***
+void genPass2(int Layer) {
+ board(B) {
+ Actualmilldeep = Z_down; // 2011-01-27 milling Z Achse
+ real x1 = u2mm(B.area.x1) - MillToolFree/2 , y1 = u2mm(B.area.y1) - MillToolFree/2 ;
+
+ string fname = MillFileName;
+ if(Layer == 1) { // wenn Top und HPGL dann in 2. Datei schreiben
+ fname = filenametop(MillFileName);
+ }
+ output(fname, "at") {
+ if (SelectedDevice == devScript) {
+ printf("\n#5200 InPass2 1. isolate Layer %d \n", Layer); // 2013-04-30
+ }
+ DeviceInit(Contour, Layer);
+ printf("%s", WriteOutlines(ReservedOutlineSignalName, Layer )); // the isolated contour gecheckt 2001-01-31
+ if (SelectedPlusLayerTop && Layer == 1) genPlusLayer(SelectedPlusLayerTop);
+ if (SelectedPlusLayerBot && Layer == 16) genPlusLayer(SelectedPlusLayerBot);
+ }
+ if (MillToolFree < 0) MillToolFree = 0.2;
+ real overlapfree = MillToolFree * OverlapRubOutPercent / 100;
+ real overlapoutl = MillToolOutl * OverlapOutlPercent / 100;
+
+ string Cmd;
+ sprintf(Cmd, "CHANGe wIDTH %.8f %s;\nCHANGe iSOLATE %.8f %s;\n",
+ MillToolFree - overlapfree, polycoord1(TrueOutline_coordinate), // x1, y1, waren die falschen Koordinaten!
+ MillToolOutl + ( (overlapfree / 2 ) - overlapoutl), polycoord1(TrueOutline_coordinate) ); // 2012-03-09 benutze zum ändern der Breite eine Koordinate des Polygon selbst.
+ if (test2) if (dlgMessageBox("!5168 Anschliesend muß das Polygon die untenstehende Breite erhalten!\n" + Cmd, "OK", "CANCEL") != 0) exit(-5215);
+
+ Cmd += "RATSNEST;\n" + RUN_pass(PassPour);
+ if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd);
+ if (test) if (viewtest("5389 if (InPass2) Jetzt bekommt das Polygon die andere Breite!!! genPass2() " + PassPour +":", Cmd) != 0) exit(-5219);
+ exit(Cmd);
+ }
+}
+
+/******************
+*** run passes ****
+*******************/
+if (InPassDimensionPoly) { // ## first run calculate the real outline ##
+ if (test2) if (dlgMessageBox("#5228 1. Dimension ermitteln", "ok", "esc") != 0) exit(-5228);
+ //
+ // The actual outlines (Dimension) generator
+ //
+ board(B) {
+ Actualmilldeep = Z_dimension;
+ trueOutlineDraw(OutlineMillSignal);
+ string s;
+ string Cmd;
+ real x1 = u2mm(B.area.x1) - MillToolFree, y1 = u2mm(B.area.y1) - MillToolFree,
+ x2 = u2mm(B.area.x2) + MillToolFree, y2 = u2mm(B.area.y2) + MillToolFree;
+ DistanceDimension = (DimensionMillTool / 2 - Distance_Copper_Dimension);
+ if (DistanceDimension < 0) DistanceDimension = 0.001;
+
+ // ** delete the temporary Polygon **
+ // 2008-11-12 get actual coordinate
+ B.signals(S) {
+ if (S.name == OutlineMillSignal) {
+ int cntco = 0;
+ S.polygons(PL) {
+ int i = 1;
+ int active;
+ do {
+ active = 0;
+ PL.contours(W, i) {
+ active = 1;
+ // do something with the wire
+ cntco++; // 2010-01-20 Anzahl der Konturen ermitteln,
+ break;
+ }
+ i++;
+ } while (active);
+ i = -1;
+
+ PL.wires(W) {
+ sprintf( s, "DELETE (S%.8f %.8f);\n", u2mm(W.x1), u2mm(W.y1) );
+ Cmd += s;
+ break;
+ }
+ break;
+ }
+ S.vias(V) { // get absolut coordiante of via
+ // ** delete the temporary Via after board outline contour and inner contour**
+ cntcontvia++;
+ // 2015-03-24 do not ripup the via befor milling a exist inner contour
+ // sprintf( s, "RIPUP (%.8f %.8f);\n", u2mm(V.x), u2mm(V.y) );
+ // if (dlgMessageBox(s, "nein", "ja") != 0) {
+ // Cmd += s;
+ // }
+ }
+ if (cntco > cntcontvia+1) { // 2011-10-04 wenn Anzahl der Kontouren+1 größer als vorhandene Vias,
+ // dann ist die Diemension nicht in Ordnung!
+ string i1, i2;
+ sprintf(i1, "%d Konturen im Polygon %s gefunden
" +
+ "Überprüfen Sie die Dimension (Layer 20). " +
+ "Das Layout besteht aus mehreren Outlines. ",
+ cntco, S.name);
+
+ sprintf(i2, "Beispiel: Auf der linken Seite im Bild ist ausserhalb der Platine ein Kreis im Layer 20. " +
+ "Verbinden Sie die zweite Kontur mit einer Linie im Layer 20, wie auf der rechten Seite zu sehen ist.
" +
+ "
" +
+ "Anschliessend an diese Meldung wird nur der Layer Dimension angezeigt! " +
+ "Schalten Sie entsprechende Layer wieder mit DISPLAY ein.
");
+
+ dlgDialog("Contour error") { // 2010-01-20
+ dlgLabel(i1);
+ dlgLabel("");
+ dlgLabel(i2);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ exit (Cmd+"DISPLAY NONE 20;\nWIN FIT;LAYER 20 "); // 2010-01-20 Polygon und Via löschen, und nur Layer Dimension anzeigen.
+ }
+ }
+ }
+ Cmd += "SET WIRE_BEND 2;\n";
+ sprintf(s, "CHANGE ISOLATE %.8f;\n", MillToolIsolate); // 2006-07-26
+ Cmd += s;
+ sprintf(s, "CHANGE RANK 6;\n"); // 2006-07-26
+ Cmd += s;
+ if (SelectedLayer16) {
+ sprintf(s, "CHANGE LAYER 16;\n"); // first milling bottom layer
+ Cmd += s;
+ }
+ else if (SelectedLayer1) {
+ sprintf(s, "CHANGE LAYER 1;\n");
+ Cmd += s;
+ }
+ sprintf(s, "POLYGOn '%s' %.8f %s;\nRATSNEST;\n",
+ ReservedOutlineSignalName, MillToolOutl, TrueOutline_coordinate);
+ Cmd += s;
+ Cmd += RUN_pass(Pass2);
+
+ if (test) if (viewtest("if (InPassDimensionPoly) 2008-11-12 *****************:", Cmd) != 0) exit(-5324);
+ if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd);
+ exit(Cmd);
+ }
+}
+
+
+
+// ****************** the passes ****************************
+// *** milling the isolation #1 ***
+if (InPass2) { // second run, first isolate
+ if (test2) if (dlgMessageBox("#5335 2. Erste Isolation fräsen Pass2\nPolygonstart: " + TrueOutline_coordinate, "ok", "esc") != 0) exit(-5335);
+ Actualmilldeep = Z_down; // 2011-01-27 milling Z Achse
+ /*** after InPass2 must/can Copper pouring ***/
+ if(SelectedLayer16 && ToMillLayer16) {
+ if (Mirror_On) {
+ Mirror = -1.0;
+ }
+ else {
+ MillMirr_Offset = 0; // ** reset mirror offset **
+ Mirror = 1.0;
+ }
+ OutlineMillSignalLayer = SelectedLayer16;
+ genPass2(16); // 2008-11-12 nicht das Flag übergeben, sondern den Layer
+ }
+ else if(SelectedLayer1 && ToMillLayer1) {
+ MillMirr_Offset = 0; // ** reset mirror offset **
+ Mirror = 1.0;
+ OutlineMillSignalLayer = SelectedLayer1;
+ genPass2(1); // 2008-11-12 nicht das Flag übergeben, sondern den Layer
+ }
+}
+
+
+// *** Copper pouring ***
+if (InPassPour) { // third run, wide isolate und copper pouring
+ if (test2) if (dlgMessageBox("#5360 3. zweites mal Isolation fräsen mit breiteren Fräser und ausräumen!", "ok", "esc") != 0) exit(-5360);
+ string Cmd;
+ string millout;
+ string s;
+ string coordoutline;
+ Actualmilldeep = Z_down; // 2011-01-27 milling Z Achse
+ board(B) {
+ real x1 = u2mm(B.area.x1) - MillToolFree/2, y1 = u2mm(B.area.y1) - MillToolFree/2;
+ real x2 = u2mm(B.area.x2) + MillToolFree/2, y2 = u2mm(B.area.y2) + MillToolFree/2;
+ // 2008-11-12 Polygon-Layer ermitteln
+ B.signals(S) {
+ if (S.name == ReservedOutlineSignalName) {
+ S.polygons(P) {
+ sprintf(s, "DISPLAY %d;\n", P.layer); // 2008-11-12 ermittle den aktuellen Polygon Layer
+ Cmd += s;
+ P.wires(W) {
+ sprintf(coordoutline, "(%.8f %.8f)", u2mm(W.x1), u2mm(W.y1) );
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ if(ToMillLayer16 && ToMillLayer1) {
+ // *** if double layer, first generate Layer 16 (mirrored) ***
+ genInPassPour(16); // 2008-11-12 use layer not flag
+ ToMillLayer16 = 0;
+ output(MillFileName, "at") { // *** the first run is finished ***
+ // *** ReInit with mirror PCB on machine ***
+ // *** 2005-05-24
+ DeviceReInit(MirrorPCB, ToMillLayer16, "5338"); // *** message to personal must mirror the milling PCB on machine ***
+ }
+ sprintf(s, "CHANGE ISOLATE 0 %s;\nCHANGE LAYER 1 %s;\nCHANGE WIDTH %.8f %s;\nRATSNEST;\n",
+ coordoutline,
+ coordoutline,
+ MillToolOutl, coordoutline);
+ if (test2) if (dlgMessageBox("#5398 Breiter Fräser:\n" + s, "ok", "esc") != 0) exit(-5398);
+ Cmd += s;
+ Cmd += RUN_pass(Pass2);
+ exit(Cmd);
+ }
+ else if(ToMillLayer16 || ToMillLayer1) {
+ if(ToMillLayer16) genInPassPour(16); // 2008-11-12
+ else if (ToMillLayer1) {
+ MillMirr_Offset = 0; // ** OK reset mirror offset ** 2005-05-23
+ genInPassPour(1);
+ }
+ B.signals(S) {
+ if (S.name == ReservedOutlineSignalName) {
+ S.polygons(P) {
+ P.wires(W) {
+ sprintf(DelPoly, "DELETE (S %.8f %.8f);\n", u2mm(W.x1), u2mm(W.y1) ); // 2009-03-31 gesamtes Polygon löschen
+ Cmd += DelPoly;
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ sprintf(millout, "DISPLAY NONE 17 %d;\n", ToMillLayer1 + ToMillLayer16);
+ Cmd += millout;
+
+ // ** make temporary Net for Normal Polygon Orphen OFF
+ // ** to milling the pcb-contour with holder **
+ string millout;
+
+ // 2009-03-31 set correct layer for milling out
+ if (SelectedLayer16 && ToMillLayer16) OutlineMillSignalLayer = 16; // 2009-03-31
+ sprintf(millout, "cHANGE lAYER %d;\n", OutlineMillSignalLayer);
+ Cmd += millout;
+ sprintf(millout, "VIA '%s' (%.8f %.8f);\n",
+ OutlineMillSignal,
+ x1 + .1, // plaziere Via innerhalb des Polygon 2006-05-17
+ y1 + .1 // damit es kein Orphan wird.
+ );
+ Cmd += millout;
+ sprintf(millout, "CHANGE ISOLATE 0;\n");
+ Cmd += millout;
+ sprintf(millout, "CHANGE ORPHANS OFF;\n");
+ Cmd += millout;
+ Cmd += "SET WIRE_BEND 0;\n";
+ Cmd += "CHANGE RANK 1;\n"; // 2006-07-26
+
+ DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2;
+ if (DistanceDimension < 0) { // 2009-02-05 correct wire width for millout
+ DistanceDimension = 0;
+ }
+ }
+ sprintf(millout, "POLyGON '%s' %.8f (%.8f %.8f) (%.8f %.8f) (%.8f %.8f);\nRATSNEST;\n",
+ OutlineMillSignal, DistanceDimension,
+ x1 - DimensionMillTool - Distance_Copper_Dimension,
+ y1 - DimensionMillTool - Distance_Copper_Dimension,
+ x2 + DimensionMillTool + Distance_Copper_Dimension,
+ y2 + DimensionMillTool + Distance_Copper_Dimension,
+ x1 - DimensionMillTool - Distance_Copper_Dimension,
+ y1 - DimensionMillTool - Distance_Copper_Dimension);
+ Cmd += millout;
+ Cmd += "SET WIRE_BEND 2;\n"; // 2011-09-28
+ Cmd += RUN_pass(PassOutmill);
+ if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd);
+ if (test) if (viewtest("if (InPassPour) >> " + PassOutmill + ": jetzt kommt aus dem Träger ausfräsen:", Cmd) != 0) exit(-5463);
+ exit(Cmd);
+ }
+}
+
+
+// *** drill holes (milling bigger holes) and milling out from holder ***
+if (InPassOutmill) { // ## fourth run, drill holes, milling big holes and milling out from raw matarial by dimension
+ if (test2) if (dlgMessageBox("#5471 4. Aus dem Träger fräsen!", "ok", "esc") != 0) exit(-5471);
+ Actualmilldeep = Drill_z_deep; // 2011-01-27
+ string fname = MillFileName;
+
+ if (SelectedLayer16 && ToMillLayer16) OutlineMillSignalLayer = 16; // 2009-03-31
+ if (OutlineMillSignalLayer == 16) {
+ if (Mirror_On) {
+ Mirror = -1.0; // *** mirror flag for Layer 16 ***
+ }
+ else {
+ MillMirr_Offset = 0; // ** reset mirror offset **
+ Mirror = 1.0;
+ }
+ }
+ else if(OutlineMillSignalLayer == 1) {
+ fname = filenametop(MillFileName);
+ MillMirr_Offset = 0; // ** reset mirror offset **
+ Mirror = 1.0;
+ } // ** OK ** 2005-06-23
+
+ board(B) {
+ Actualmilldeep = Drill_z_deep; // 2011-01-27
+ get_rack(B);
+ set_tool_rack(); // ** set tool rack again for Holes drilling
+ string Cmd;
+ output(fname, "at") {
+
+ if (test2) if (dlgMessageBox("#5498 Aus dem Träger fräsen!\n" + MillFileName, "ok", "esc") != 0) exit(-5498);
+ // *** now milling PCB from holder outside Dimension Line *** 2006-11-07
+ if (SelectedDevice == devScript) printf("\n# milling dimension #5500\n");
+ if (Dim_on_off) { // soll überhaupt die Dimension gefräst werden? 2011-02-09
+ if (MillOnlyContour) OutlineMillSignalLayer = 1; /**** 2011-03-10 wenn nur Konturfräsen, dann immer Layer 1 ****/
+ printf("%s", WriteOutlines( OutlineMillSignal, OutlineMillSignalLayer )) ; // milling outline(Dimension) 2009-03-31
+ }
+ // *** last but not least the HOLE(s) ***
+ switch (SelectedDevice) {
+ case devScript: /**** 2008-12-05 new file == "wt" ****/
+ printf("#5508 WriteHoles() in the same script\n"); // 2013-02-19
+ // WriteHoles(OutlineMillSignalLayer); ist schon erledigt
+ printf("SET UNDO_LOG ON;\n");
+ printf("WIN FIT;\n");
+ break;
+
+ case devHPGL:
+ break;
+
+ case devISEL:
+ if (Generatedrills) { printf("#5518\n"); WriteHoles(OutlineMillSignalLayer); }
+ break;
+
+ case devCNC:
+ if (Generatedrills) { printf("#5522\n"); WriteHoles(OutlineMillSignalLayer); }
+ break;
+
+ default:
+ dlgMessageBox("undefined Device!\nULP aborted.", "OK"); exit(0);
+ break;
+ }
+ DeviceEnd();
+
+ real x1 = u2mm(B.area.x1) - DimensionMillTool/2, y1 = u2mm(B.area.y1) - MillToolFree/2,
+ x2 = u2mm(B.area.x2) + DimensionMillTool/2, y2 = u2mm(B.area.y2) + MillToolFree/2;
+
+ // delete temporary Polygon and VIA
+ B.signals(S) { // 2008-11-12 get absolute coordinate of reseved polygon
+ if (S.name == OutlineMillSignal) {
+ int cntcontp = 0;
+ int cntcontn = 0;
+ int cntvia = 0;
+ S.vias(V) {
+ cntvia++;
+ }
+ string del_pol;
+ S.polygons(POL) {
+ POL.wires(W) {
+ sprintf(del_pol, "Grid MM;\nDELETE (S %.8f %.8f);", u2mm(W.x1), u2mm(W.y1) );
+ Cmd += del_pol;
+ break;
+ }
+ break;
+ }
+ S.vias(V) { // 2008-11-12 get actual coordiante of via
+ // ** delete the temporary Via **
+ sprintf( del_pol, "RIPUP (%.8f %.8f);\nRATSNEST;\n", u2mm(V.x), u2mm(V.y) ); // 2009-02-04 clear via airwire
+ Cmd += del_pol;
+ }
+ int activ;
+ S.polygons(POL) { // 2011-03-10 check Elemente ausserhalb der Dimension
+ do {
+ activ = 0;
+ POL.contours(W, cntcontp+1) {
+ cntcontp++;
+ activ = 1;
+ break;
+ }
+ POL.contours(W, cntcontn-1) {
+ cntcontn--;
+ activ = 1;
+ break;
+ }
+ } while (activ);
+ }
+ cntcontn *= -1;
+ if (cntcontp == cntvia && cntcontn == 1) { // 2011-10-04
+ ; // alles in bester Ordnung
+ }
+ else {
+ if (MillToolFree) { // 2013-03-05 nur wenn Tool#2 blow-up benutzt
+ string polerror;
+ string polerrorimg = "";
+ sprintf(polerror, "ERROR: %d VIA, %d positive und %d negative Konturen im Polygon %s
" +
+ "Überprüfen Sie, ob außerhalb der Boardkontur, Texte, Logos oder sonstige Elemente im Top oder Bottom Layer " +
+ "platziert sind und entweder entfernen Sie diese Elemente oder wechseln sie in einen nicht Kupferlayer. " +
+ "Entfernen Sie mit DELETE/RIPUP alle Elemente außerhalb der Dimension, bzw. verbinden " +
+ "Sie evtl. mehrfach vorhandene Dimensionen (Konturen) miteinander. Beispiel:",
+ cntvia, cntcontp, cntcontn, OutlineMillSignal
+ );
+ dlgDialog("Polygon Error") {
+ dlgLabel(polerror);
+ dlgLabel(polerrorimg);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+ }
+ Cmd += "SCRIPT '" + filesetext(B.name, "_display~tmp.scr") + "';\n";
+ string g;
+ sprintf(g, "GRID %s %.f;\nWIN FIT;", Gridunit[GridUnitdist], GridDistance);
+ Cmd+=g;
+ }
+ }
+ }
+ if (SelectedDevice == devScript) {
+ printf("\n#5607 *** InPassOutmill\n");
+ printf("# milling dimension\n");
+ }
+ }
+
+ // SelectedLayer1 beim letzten PASS2 muß 1 ToMillLayerX noch übrig bleiben !!!
+ // SelectedLayer16 überprüfen ob noch ein Layer aktiv ist, der letzte !! 2006-10-05
+
+ switch (SelectedDevice) {
+ case devScript: if (MillOnlyContour) { // 2011-03-10
+ Cmd += "SCRIPT '" + MillFileName + "';\n"; // execute script
+ Cmd += "SCRIPT '" + filesetext(B.name, "_display~tmp.scr") + "';\n";
+ }
+
+ else {
+ Cmd += "SCRIPT '" + MillFileName + "';\n"; // execute script
+ Cmd += "SCRIPT '" + filesetext(B.name, "_display~tmp.scr") + "';\n";
+ string s;
+ if (ToMillLayer1) {
+ sprintf(s, "DISPLAY %d;\n", SelectedLayer1 + 101); // 2006-07-26
+ Cmd += s;
+ sprintf(s, "DISPLAY %d;\n", SelectedLayer1 + 102);
+ Cmd += s;
+ }
+ if (ToMillLayer16) {
+ sprintf(s, "DISPLAY %d;\n", SelectedLayer16 + 101); // 2012-01-13
+ Cmd += s;
+ sprintf(s, "DISPLAY %d;\n", SelectedLayer16 + 102); // 2012-01-13
+ Cmd += s;
+ }
+ }
+ break;
+
+ case devHPGL:
+ Cmd += "script '" + filesetext(B.name, "_display~tmp.scr") + "';\n";
+ break;
+
+ case devISEL:
+ Cmd += "script '" + filesetext(B.name, "_display~tmp.scr") + "';\n";
+ break;
+
+ case devCNC:
+ Cmd += "script '" + filesetext(B.name, "_display~tmp.scr") + "';\n";
+ break;
+
+ }
+ string g;
+ if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd);
+ sprintf(g, "GRID %s %.f;\nWIN FIT;\n", Gridunit[GridUnitdist], GridDistance);
+ Cmd += g + "SET OPTIMIZING ON;\n";
+ if (!test) Cmd += "SET UNDO_LOG ON;\n";
+
+ switch (SelectedDevice) {
+ case devScript:
+ break;
+
+ case devHPGL:
+ if (test) showHPGLinfo();
+ break;
+
+ case devISEL:
+ if (test) showISELinfo();
+ break;
+
+ case devCNC:
+ if (test) showCNCinfo();
+ break;
+ }
+ if (test) if (viewtest("if (InPassOutmill) :", Cmd) != 0) exit(-5675);
+ sprintf(g, "GRID %s %.f;\nWIN FIT;\n", Gridunit[GridUnitdist], GridDistance);
+ Cmd+=g;
+ if (SelectedDevice == devHPGL) {
+ sprintf(g, "RUN ulpmessage 'Erzeugte Dateien: %s %s'", MillFileName, filenametop(MillFileName)); // 2014-10-06
+ }
+ else {
+ sprintf(g, "RUN ulpmessage 'Erzeugte Datei %s'", MillFileName); // 2014-10-06
+ }
+ Cmd+=g;
+ exit(Cmd);
+ }
+}
+
diff --git a/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp b/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp
new file mode 100644
index 00000000..41e96fae
--- /dev/null
+++ b/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp
@@ -0,0 +1,432 @@
+#usage "de:Spiegelt das gesamte Board, spiegelt dann die Bauteile an ihrem Origin zurück und zeichnet die Leiterbahnen "
+ "(Top/Bottom) gespiegelt ohne die Layer zu tauschen. "
+ "Um zum Beispiel aus dem Layout für einem linken Scheinwerfer das Layout für einen rechten Scheinwerfer zu erzeugen.
"
+ "Bei symmetrischen zweipoligen Bauteilen in senkrechter Ausrichtung reicht es die Bauteile einfach zurück zu spiegeln, "
+ "symmetrische zweipolige Bauteile in waagerechter Ausrichtung müssen zusätzlich um 180 gedreht werden "
+ "um die Position der PADs mit den Leiterbahnen wieder in Einklang zu bringen.
"
+ "Achtung: Asymmetrische und mehrreihige Bauteile wie SOT23 SO14 ... können nicht ohne weiteres gespiegelt und "
+ "die Anbindung der Leiterbahnen an den PADs behalten werden. "
+ "Hier muß der Layouter die gerouteten Wire (Leiterbahnen) teilweise aufripen und neu verlegen. "
+ "Um die Anschlüsse zu überprüfen wird der DRC gestartet und die die Fehlerliste angezeigt. Jeder Overlap bedeutet "
+ "eine falsch angeschlossene Leiterbahn die entsprechend behandelt werden muß. "
+ "Je nach Symmetrie des Bauteiles muß entweder das Bauteil verschoben/gedreht und/oder die Wire neu verlegt werden "
+ "(RIPUP und ROUTE).
"
+ "Interessant ist schon die Definition beim Anlegen in der Bibliothek, so wie beim platzieren der Bauteile "
+ "im Board ob man den entsprechenden Platz für die gespiegelte Version freihalten kann. "
+ "Das erspart einiges an Nacharbeit. "
+ "Unter Umständen mach es Sinn das Bauteil symmetrisch in Bezug auf die PADs und asymmetrisch zu den Packagekonturen "
+ "anzulegen, damit dann der Origin zwischen den Pads liegt und man das Bauteil nur noch drehen mus.
"
+ "Die Meldung ! Alle Signale umwandeln? muß mit Ja beanbtwortet werden, damit die Leiterbahnen aufgeript "
+ "werden können."
+ "
"
+ "Author: alf@cadsoft.de"
+ ,
+ "en: Mirrors the whole board, flips the components back to their original positions and draws the "
+ "mirrored traces in top and bottom without changing the original layer.
"
+ "For example, for creating the layout for a headlamp on the left out of the layout of a headlamp on the right side. "
+ "In case you are using symmetrical two-pole components in a vertical orientation it suffices to mirror the components, "
+ "if they are in a horizontal orientation you additionally have to rotate them by 180 degrees in order to conciliate "
+ "the position of the pads and the traces. "
+ "Note: Asymmetric and multi-row components like SOT23, SO14.... can't be mirrored without mixing up the connections "
+ "between pads and traces. In this case you have to ripup the traces and layout them correctly afterwards. "
+ "For checking the connections, run the DRC and look into the errors list. Each overlap error shows a mis-connected "
+ "trace you have to take care on. "
+ "Depending on the symmetry of the component you have to move/rotate it and/or re-route the traces (RIPUP and ROUTE).
"
+ "Think of this already when creating the library element and placing the component in the layout, and try to "
+ "reserve some space for the mirrored component. This can save a lot of effort. "
+ "I can be senseful to create the component symmetric in terms of the pads and asymmetric in terms of the package "
+ "contours so that the origin is located between the pads and you finally only have to rotate the component.
"
+ "The message Ripup all signals? has to be answered with Yes in order to ripup all signals."
+ "
" + usage, "OK");
+ exit(-1);
+}
+
+
+/* **********************************************************************************
+ Der MicroSoft-Fehler: BACKSLASH
+ Ein Backslach ist ein Escape-Zeichen um ein Steuerzeichen zu maskieren.
+ Unter Windows wird als Pfad-Trennzeichen der Backslash '\' benutzt,
+ und nicht wie unter UNIX der Slash '/'!
+ Eagle benutzt aus Kompatibilitätsgründen zu Linux und Macintosh intern als
+ Pfad-Trennzeichen den Slash '/'.
+ Unter Windows wird in allen File-Funktionen im ULP vor der Ausführung der Slash
+ zu einem Backslash gewandelt. Damit funktionieren alle ULPs auf allen Plattformen.
+ Soll unter Windows einem system()-Aufruf ein Pfad- oder Datei-Name übergeben werden,
+ so muß man zuerst den Slash zu einen Backslash wandeln, da nicht unterschieden
+ werden kann, ob es sich um einen Pfad oder eine Option des Aufrufes handelt.
+********************************************************************************** */
+
+// change slash to backslash for windows
+string cs2bs(string s) {
+ int pos;
+ do {
+ pos = strchr(s, '/');
+ if (pos >= 0) s[pos] = '\\';
+ } while (pos >= 0);
+ return s;
+}
+
+
+if (board) board(B) {
+ Directory = filedir(B.name);
+}
+else if (schematic) schematic(S) {
+ Directory = filedir(S.name);
+}
+else if (library) library(L) {
+ Directory = filedir(L.name);
+}
+
+// Check if exist subdirectory.
+string f[];
+int n = fileglob(f, Directory+SubDirectory);
+if (n) {
+ //dlgMessageBox("!Directory exist:\n\n" + Directory+SubDirectory, "OK");
+ exit(0);
+}
+
+/*** generate DOS command ***/
+sprintf(DOScommand, "CMD.EXE /C MKDIR \"%s%s\"", cs2bs(Directory), cs2bs(SubDirectory) );
+system(DOScommand);
+
diff --git a/trunk/ulp/mount-marks-smd.ulp b/trunk/ulp/mount-marks-smd.ulp
new file mode 100644
index 00000000..efad11c1
--- /dev/null
+++ b/trunk/ulp/mount-marks-smd.ulp
@@ -0,0 +1,82 @@
+#usage "Data generation for mounting machines
\n"
+ "This ULP generates files for top and bottom layers "
+ "wich can be used with mounting machines. "
+ "Use x and y coordinates of the origin points (units: mm) of the SMD elements"
+ "and packages from defined lbr."
+ "The syntax of the output data looks like this:
\n"
+ "This ULP generates files for top and bottom layers "
+ "wich can be used with mounting machines. "
+ "Use x and y coordinates of the origin points (units: mm) of the SMD elements"
+ "and packages from defined lbr."
+ "The syntax of the output data looks like this:
"
+ "Name x-coord y-coord Rotation Value Package
"
+ "Author: support@cadsoft.de"
+
+string def_lbr = "marks"; // 2013-10-25 open the exported list in a dialog to show
+ // define a library name to export also place coordinates
+ // 2006.04.18 alf@cadsoft.de
+
+char Tab = '\t'; // ';';
+
+
+board(B) {
+ // Get filename
+ string fileNameTop = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt");
+ if (fileNameTop == "") exit(0);
+ string fileNameBot = dlgFileSave("Save File", filesetext(B.name, ".mnb"), "*.mnb");
+ if (fileNameBot == "") exit(0);
+
+ int wasSmd = 0;
+ output(fileNameBot, "wt") ;
+ output(fileNameTop, "wt") {
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (E.mirror == 0) {
+ printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n",
+ E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab,
+ E.angle, Tab, E.value, Tab, E.package.name);
+ }
+ else {
+ output(fileNameBot, "at") {
+ printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n",
+ E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab,
+ E.angle, Tab, E.value, Tab, E.package.name);
+ }
+ }
+ break;
+ }
+ if (strupr(E.package.library) == strupr(def_lbr)) {
+ if (E.mirror == 0) {
+ printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n",
+ E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab,
+ E.angle, Tab, E.value, Tab, E.package.name);
+ }
+ else {
+ output(fileNameBot, "at") {
+ printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n",
+ E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab,
+ E.angle, Tab, E.value, Tab, E.package.name);
+ }
+ }
+ }
+ }
+ }
+ string mt, mb;
+ int cntt = fileread(mt, fileNameTop);
+ int cntb = fileread(mb, fileNameBot);
+ dlgDialog("Mount data") {
+ dlgHBoxLayout dlgSpacing(500);
+ dlgLabel("Top place");
+ dlgTextView(mt);
+ dlgLabel("Bottom place");
+ dlgTextView(mb);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton("OK") dlgAccept();
+ dlgStretch(1);
+ }
+ };
+}
+
diff --git a/trunk/ulp/mount-trace.ulp b/trunk/ulp/mount-trace.ulp
new file mode 100644
index 00000000..414a8a4d
--- /dev/null
+++ b/trunk/ulp/mount-trace.ulp
@@ -0,0 +1,290 @@
+#usage "MOUNT TRACE shows all parts on the top layer with the same values of a board for manual assembling.
"
+ "RUN mount-trace (this help page) "
+ "RUN mount-trace -Lgenerate a trace list from current board. "
+ "RUN mount-trace 0set pointer to zero. "
+ "RUN mount-trace +pointer+1, show the next value(s). "
+ "RUN mount-trace ++pointer+1, show a dialog with the counts, value and package. "
+ "RUN mount-trace -pointer-1, show the previous value(s). "
+ "RUN mount-trace --pointer-1, show a dialog with the counts, value and package. "
+ "RUN mount-trace -Mmirror the whole board [make Bottom to Top] "
+ " save board with an extended name and generate trace list from this side.
"
+ "Tip: Define function key(s) with ASSIGN for easier use of this ULP.
"
+ "Author: support@cadsoft.de
"
+
+string Hilfe = "MOUNT TRACE zeigt alle Bauteile auf der Top-Seite mit gleichem Value für manuelles Bestücken.
" +
+ "RUN mount-trace (diese Hilfeseite) " +
+ "RUN mount-trace -Lgeneriert die Trace-Liste des aktuellen Boards. " +
+ "RUN mount-trace 0setzt den Zeiger auf null. " +
+ "RUN mount-trace +Zeiger+1, zeige die Bauteile mit dem nächsten Wert an. " +
+ "RUN mount-trace ++Zeiger+1, zeige die Anzahl, den Wert und das Package der Bauteile in einem Dialog. " +
+ "RUN mount-trace -Zeiger-1, zeige die Bauteile mit dem vorhergehenden Wert an. " +
+ "RUN mount-trace --Zeiger-1, zeige die Anzahl, den Wert und das Package der Bauteile in einem Dialog. " +
+ "RUN mount-trace -MSpiegelt das ganze Board [Unten nach Oben], speichert das Board mit " +
+ "Namenserweiterung und generiert dafür eine Liste der Bauteile auf der Oberseite.
" +
+ "Tip: Setzen Sie sich Funktionstasten [ASSIGN] mit den Optionen für eine einfachere Bedienung.
"
+ "Generates a file that can be used with mounting machines. "
+ "The x- and y- coordinates (units: mil) are calculated as mean of "
+ "maximum and mimimum value of the pads or smds origin points. "
+ "The calculated value does not necessarily fit with the origin "
+ "point of the part in the layout."
+ "All elements populated in currently set assembly variant are considered."
+ "
"
+ "The syntax of the output data looks like this:"
+ "
"
+ "value;x-coord;y-coord;rotation;name"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+// History:
+// 2012-06-12: Extended to assembly variants
+
+if (board) board(B) {
+
+ // Get filename
+ string fileName = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt");
+ if (fileName == "") exit(0);
+
+ output(fileName) {
+
+ B.elements(E) if (E.populate) {
+
+ int xmax =-2147483648,
+ xmin = 2147483647,
+ ymax = xmax,
+ ymin = xmin;
+
+ E.package.contacts(C) {
+
+ if (C.x > xmax) xmax = C.x;
+ if (C.y > ymax) ymax = C.y;
+ if (C.x < xmin) xmin = C.x;
+ if (C.y < ymin) ymin = C.y; }
+
+
+ printf("%s;%5.0f;%5.0f;%3.0f;%s \n",
+ E.value, u2mil((xmin + xmax)/2), u2mil((ymin + ymax)/2),
+ E.angle, E.name );
+ }
+ }
+}
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+}
diff --git a/trunk/ulp/mountsmd.ulp b/trunk/ulp/mountsmd.ulp
new file mode 100644
index 00000000..413f8557
--- /dev/null
+++ b/trunk/ulp/mountsmd.ulp
@@ -0,0 +1,93 @@
+#usage "Data generation for mounting machines\n"
+ "
"
+ "Generates files for smds on the top and bottom layers "
+ "wich can be used with mounting machines. "
+ "The x and y coordinates (units: mm) of the SMD elements are calculated "
+ "as mean of maximum and mimimum value of the smds origin points. "
+ "The calculated value does not necessarily fit with the origin "
+ "point of the part in the layout."
+ "All SMD elements populated in currently set assembly variant are considered."
+ "
"
+ "The syntax of the output data looks like this:"
+ "
"
+ "name x-coord y-coord rotation value package"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+if (board) board(B) {
+
+ // Get filename
+ string fileName = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt");
+ if (fileName == "") exit(0);
+
+ output(fileName) {
+
+ B.elements(E) if (E.populate) {
+
+ int wasSmd,
+ xmax =-2147483648,
+ xmin = 2147483647,
+ ymax = xmax,
+ ymin = xmin;
+
+ wasSmd = 0;
+
+ E.package.contacts(C) {
+ if (C.smd && C.smd.layer == 1) {
+ wasSmd = 1;
+
+ if (C.x > xmax) xmax = C.x;
+ if (C.y > ymax) ymax = C.y;
+ if (C.x < xmin) xmin = C.x;
+ if (C.y < ymin) ymin = C.y;
+ }
+ }
+
+ if (wasSmd)
+ printf("%s %5.2f %5.2f %3.0f %s %s\n",
+ E.name, u2mm((xmin + xmax)/2), u2mm((ymin + ymax)/2),
+ E.angle, E.value, E.package.name);
+ }
+ }
+
+ // Get filename
+ fileName = dlgFileSave("Save File", filesetext(B.name, ".mnb"), "*.mnb");
+ if (fileName == "") exit(0);
+
+ output(fileName) {
+
+ B.elements(E) if (E.populate) {
+
+ int wasSmd,
+ xmax =-2147483648,
+ xmin = 2147483647,
+ ymax = xmax,
+ ymin = xmin;
+
+ wasSmd = 0;
+
+ E.package.contacts(C) {
+ if (C.smd && C.smd.layer == 16) {
+ wasSmd = 1;
+
+ if (C.x > xmax) xmax = C.x;
+ if (C.y > ymax) ymax = C.y;
+ if (C.x < xmin) xmin = C.x;
+ if (C.y < ymin) ymin = C.y;
+ }
+ }
+
+ if (wasSmd)
+ printf("%s %5.2f %5.2f %3.0f %s %s\n",
+ E.name, u2mm((xmin + xmax)/2), u2mm((ymin + ymax)/2),
+ E.angle, E.value, E.package.name);
+ }
+ }
+}
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+}
diff --git a/trunk/ulp/net-bus-labeling.ulp b/trunk/ulp/net-bus-labeling.ulp
new file mode 100644
index 00000000..56dea6e0
--- /dev/null
+++ b/trunk/ulp/net-bus-labeling.ulp
@@ -0,0 +1,266 @@
+#usage "de:NET/BUS LABEL platzieren
"
+ "Um Netze automatisch mit einem Label zu versehen, muß man eine Gruppe um den Bereich "
+ "der NET/BUS-Wire definieren, an denen ein LABEL platziert werden soll. "
+ "Es wird an jedem selektierten Ende eines NET/BUS-Wire in der Gruppe ein LABEL platziert. "
+ "Man sollte also die Gruppe so wählen, daß nur eine Ende des Wire groupiert wird."
+ "Das LABEL wird bei einem NET mit einem Offset von 10 Mil, bei einem BUS mit einem Offset 20 Mil "
+ "über die waagrechte Linie gestellt, bzw. bei einer senkrechten Linie links daneben. "
+ "Ein zweiter Offset sorgt dafür, daß das LABEL um ein halbes GRID (50 Mil) vom Beginn des Wire, "
+ "in der selben Richtung wie sich der Wire erstreckt, platziert wird. "
+ "Das LABEL wird entsprechend der Ausrichtung des Wire gedreht. "
+ "Die Textgröße des LABEL wird auc 70 Mil gesetzt."
+ "
"
+ "Author alf@cadsoft.de
"
+ ,
+ "en:NET/BUS labeling
"
+ "For labeling nets automatically you have to draw a GROUP around the area you want to "
+ "have labels placed. "
+ "There can be labels at net/bus bends only. Which is usually the location where "
+ "two bus or net coordinates converge."
+ "A label for a net will be placed with an offset of 10 mil, for a bus with an offset of 20 mils "
+ "above a horizontal wire, or left of a vertical wire. A second offset places the label half the "
+ "grid (50 mil) from the beginning in wire direction. The label will be placed in the "
+ "same rotation the wire has. The text size of the label is 70 mil. "
+ "
"
+ "Author alf@cadsoft.de
"
+
+#require 5.1200
+
+string Version = "1.0.0"; // 2013-05-28
+
+real NetLabelOffset = 10.0; // offset zur Netlinie in MIL
+real BusLabelOffset = 25.0; // offset zur Buslinie in MIL
+real LabelLineOffset = 50.0; // in Mil
+real LabelSize = 70.0; // Mil
+int cntS = 0;
+int SegWireX1[], SegWireY1[], SegWireX2[], SegWireY2[], WireDirection[], WireType[], SegWireSide[];
+int GroupSelect = 0;
+int islabelgen = 0;
+
+enum { None, Buswire, Netwire, Horizontal, Vertical, Diagonal, Left, Right, Up, Down, Cross };
+string Cmd;
+string s;
+
+int test = 0;
+
+/*** Functions ***/
+void header(void) {
+ sprintf(s, "DISPLAY NONE 91 92;\n");
+ Cmd+=s;
+ sprintf(s, "CHANGE Size %.4fmil;\n", LabelSize);
+ Cmd+=s;
+ return;
+}
+
+void trailer(void) {
+ sprintf(s, "DISPLAY LAST;\n");
+ Cmd+=s;
+ return;
+}
+
+void gencmd(int index1, int direction, int side) {
+ // Jetzt muß nur ermittelt werden,
+ // in welche Richtung der Wire steht,
+ // und ob das Label verschoben werden muß,
+ // wenn der weiterführende Wire senkrecht und auf der
+ // rechten oder linken Seite des Wire steht.
+
+ int x, y;
+ string mirror = "";
+ real lxoffset, lyoffset;
+ int wirealignment, rotateangle = 0;
+ real labeloffset;
+ if (WireType[index1] == Buswire) labeloffset = BusLabelOffset;
+ else if (WireType[index1] == Netwire) labeloffset = NetLabelOffset;
+ else if (dlgMessageBox("WireType?", "OK", "CANCEL") != 0) exit(-65);
+
+ if (direction == Horizontal) { // also eine waagrechte Linie
+ if (side == 1) {
+ x = SegWireX1[index1];
+ y = SegWireY1[index1];
+
+ if (SegWireX1[index1] < SegWireX2[index1]) {
+ wirealignment = Right;
+ }
+ else {
+ wirealignment = Left;
+ }
+ }
+ else if (side == 2) {
+ x = SegWireX2[index1];
+ y = SegWireY2[index1];
+ if (SegWireX2[index1] < SegWireX1[index1]) {
+ wirealignment = Right;
+ }
+ else {
+ wirealignment = Left;
+ }
+ }
+ else {
+ if (dlgMessageBox("Error horizontal", "OK", "Cancel") != 0) exit(-96);
+ return;
+ }
+ }
+ else if (direction == Vertical) { // also eine senkrechte Linie
+ if (side == 1) {
+ x = SegWireX1[index1];
+ y = SegWireY1[index1];
+
+ if (SegWireY1[index1] < SegWireY2[index1]) {
+ wirealignment = Up;
+ }
+ else {
+ wirealignment = Down;
+ }
+ }
+ else if (side == 2) {
+ x = SegWireX2[index1];
+ y = SegWireY2[index1];
+ if (SegWireY2[index1] < SegWireY1[index1]) {
+ wirealignment = Up;
+ }
+ else {
+ wirealignment = Down;
+ }
+ }
+ else {
+ if (dlgMessageBox("Error vertical", "OK") != 0) exit(-123);
+ return;
+ }
+ }
+ else {
+ dlgMessageBox("Error cross", "ok");
+ }
+
+ if (wirealignment == Right) {
+ lyoffset = labeloffset; // oberhalb der Linie
+ lxoffset = LabelLineOffset; // nach rechts versetzt
+ mirror = "";
+ }
+ if (wirealignment == Left) {
+ lyoffset = labeloffset; // oberhalb der Linie
+ lxoffset = LabelLineOffset * -1.0; // nach links versetzt
+ mirror = "M";
+ }
+ if (wirealignment == Up) {
+ lxoffset = labeloffset * -1.0; // links von der Linie
+ lyoffset = LabelLineOffset; // nach oben versetzt
+ mirror = "";
+ rotateangle = 90;
+ }
+ if (wirealignment == Down) {
+ lxoffset = labeloffset * -1.0; // links von der Linie
+ lyoffset = LabelLineOffset * -1.0; // nach unten versetzt
+ mirror = "M";
+ rotateangle = 270;
+ }
+
+ sprintf(s, "LABEL (%.4fmil %.4fmil) (%.4fmil %.4fmil);\n",
+ u2mil(x), u2mil(y),
+ u2mil(x)+lxoffset, u2mil(y)+lyoffset
+ );
+ Cmd+=s;
+ sprintf(s, "ROTATE =R0 (%.4fmil %.4fmil);\n", u2mil(x)+lxoffset, u2mil(y)+lyoffset); // stelle rotate wieder auf 0
+ Cmd+=s;
+
+ if (!rotateangle && mirror) {
+ sprintf(s, "MIRROR (%.4fmil %.4fmil);\n", u2mil(x)+lxoffset, u2mil(y)+lyoffset);
+ Cmd+=s;
+ }
+ if (rotateangle) {
+ sprintf(s, "ROTATE =%sR%d (%.4fmil %.4fmil);\n", mirror, rotateangle, u2mil(x)+lxoffset, u2mil(y)+lyoffset);
+ Cmd+=s;
+ }
+ islabelgen++;
+ return;
+}
+
+void genlabel(void) {
+ for (int n = 0; n < cntS; n++) {
+ gencmd(n, WireDirection[n], SegWireSide[n]);
+ }
+ return;
+}
+
+void addwireseg(UL_WIRE W, string wname, int type, int side) {
+ SegWireX1[cntS] = W.x1;
+ SegWireY1[cntS] = W.y1;
+ SegWireX2[cntS] = W.x2;
+ SegWireY2[cntS] = W.y2;
+ WireType[cntS] = type;
+ SegWireSide[cntS] = side;
+
+ if (SegWireX1[cntS] == SegWireX2[cntS] || SegWireY1[cntS] == SegWireY2[cntS]) {
+ if (SegWireX1[cntS] == SegWireX2[cntS]) {
+ WireDirection[cntS] = Vertical;// wire senkrecht
+ }
+ else if (SegWireY1[cntS] == SegWireY2[cntS]) {
+ WireDirection[cntS] = Horizontal;// wire waagrecht
+ }
+ cntS++;
+ }
+ return;
+}
+
+/*** main ***/
+if (sheet) {
+ sheet(S) {
+ S.nets(N) {
+ status(N.name);
+ N.segments(SEG) {
+ SEG.wires(W) {
+ int side = ingroup(W);
+ if (side == 1 || side == 2) { // Wire bei denen beide Seiten in der Group sind, werden nicht benutzt
+ GroupSelect = 1;
+ addwireseg(W, N.name, Netwire, side);
+ }
+ }
+ }
+ }
+ S.busses(B) {
+ status(B.name);
+ B.segments(SEG) {
+ SEG.wires(W) {
+ int side = ingroup(W);
+ if (side == 1 || side == 2) { // Wire bei denen beide Seiten in der Group sind, werden nicht benutzt
+ GroupSelect = 1;
+ addwireseg(W, B.name, Buswire, side);
+ }
+ }
+ }
+ }
+ }
+ if (!GroupSelect) {
+ dlgMessageBox("!Selektieren Sie zuerst mit GROUP die NET/BUS-Wire.", "OK");
+ exit(0);
+ }
+ else {
+ header();
+ genlabel();
+ trailer();
+ }
+
+ if (test) {
+ string scmd;
+ sprintf(scmd, "%d Wire gefunden", cntS);
+ dlgDialog("test") {
+ dlgLabel(scmd);
+ dlgHBoxLayout dlgSpacing(800);
+ dlgHBoxLayout {
+ dlgVBoxLayout dlgSpacing(600);
+ dlgTextEdit(Cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+OK") dlgAccept();
+ dlgPushButton("-ESC") { dlgReject(); exit(-99); }
+ }
+ };
+ }
+ if (!islabelgen) {
+ dlgMessageBox("!No wire (horizontal/vertical) for LABEL found, check GROUP.
"+usage, "OK");
+ exit(-1);
+ }
+ exit(Cmd);
+}
+
+else dlgMessageBox("Starten Sie das ULP in einem Schaltplan", "OK");
\ No newline at end of file
diff --git a/trunk/ulp/netlist-converter.ulp b/trunk/ulp/netlist-converter.ulp
new file mode 100644
index 00000000..ca3a05f2
--- /dev/null
+++ b/trunk/ulp/netlist-converter.ulp
@@ -0,0 +1,577 @@
+#usage "Netlist converter for netlist from other CAD-System."
+ "Author: alf@cadsoft.de"
+
+string Version = "Version 1.2"; // 2009-02-26 alf@cadsoft.de
+ // 2009-05-20 Mentor, PADS2000, Accel, Allegro alf@cadsoft.de
+ // 2010-06-17 Allegro 16.2 alf@cadsoft.de
+
+enum { Unknown,
+ Multiwire,
+// OrCad,
+// Tango,
+ Mentor,
+ PADS2000,
+ Accel,
+ Allegro,
+ Allegro162,
+ // insert new types are here
+ Last };
+
+string netListType[];
+ netListType[Unknown] = "Unknown";
+ netListType[Multiwire] = "Multiwire";
+// netListType[OrCad] = "OrCad";
+// netListType[Tango] = "Tango";
+ netListType[Mentor] = "Mentor";
+ netListType[PADS2000] = "PADS2000";
+ netListType[Accel] = "Accel";
+ netListType[Allegro] = "Allegro";
+ netListType[Allegro162] = "Allegro 16.2";
+ // insert new types are here
+ netListType[Last] = "";
+
+
+string NetlistInfo = "Netlist";
+string text, netscript;
+
+int t;
+string line[];
+int lines = 0;
+
+string fname;
+string saveinfo = "";
+
+string L_separator = "SPACE";
+string W_separator = ".";
+
+char Lseparator;
+if (L_separator == "SPACE") Lseparator = ' ';
+else Lseparator = L_separator[0];
+char Wseparator = W_separator[0];
+int NetRow = 1, PartRow = 2, PadRow = 3;
+
+
+/*** Functions ***/
+void genScriptUnknown(void) {
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ for (int n = 0; n < lines; n++) {
+ status(line[n]);
+ string s[];
+ int cnt;
+ int ls = strsplit(s, line[n], Lseparator);
+ int scnt = 0;
+ string startnet;
+ for (int ln = 0; ln < ls; ln++) {
+ if (s[ln]) {
+ scnt++;
+ if (scnt == NetRow) {
+ Lnet = s[ln];
+ if (actualsigname != Lnet) {
+ sprintf(startnet, ";\nSIGNAL '%s' \n", Lnet);
+ actualsigname = Lnet;
+ }
+ else startnet = "\n ";
+
+ }
+ else if (scnt == PartRow) Lpart = s[ln];
+ else if (scnt == PadRow) Lpad = s[ln];
+ }
+ }
+ string h;
+ if (scnt == 3) {
+ sprintf(h, "%s %s %s", startnet, Lpart, Lpad);
+ netscript+=h;
+ }
+ }
+ netscript+=";\n"; // close last command
+ return;
+}
+
+
+void genScriptMultiwire(void) {
+ // defintion of separator for Multiwire;
+ Lseparator = ' ';
+ Wseparator = '.';
+ NetRow = 1;
+ PartRow = 2;
+ PadRow = 3;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ for (int n = 0; n < lines; n++) {
+ status(line[n]);
+ string s[];
+ int cnt;
+ int ls = strsplit(s, line[n], Lseparator);
+ int scnt = 0;
+ string startnet;
+ for (int ln = 0; ln < ls; ln++) {
+ if (s[ln]) {
+ scnt++;
+ if (scnt == NetRow) {
+ Lnet = s[ln];
+ if (actualsigname != Lnet) {
+ sprintf(startnet, ";\nSIGNAL '%s' \n", Lnet);
+ actualsigname = Lnet;
+ }
+ else startnet = "\n";
+
+ }
+ else if (scnt == PartRow) Lpart = s[ln];
+ else if (scnt == PadRow) Lpad = s[ln];
+ }
+ }
+ string h;
+ if (scnt == 3) {
+ sprintf(h, "%s %s %s", startnet, Lpart, Lpad);
+ netscript+=h;
+ }
+ }
+ netscript+=";\n"; // close last command
+ return;
+}
+
+
+void genScriptOrCad(void) {
+ // defintion of separator for Orcad;
+ dlgMessageBox("Orcad converter not defined!", "OK");
+ Lseparator = ' ';
+ Wseparator = '.';
+ NetRow = 1;
+ PartRow = 2;
+ PadRow = 3;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ for (int n = 0; n < lines; n++) {
+ status(line[n]);
+ string s[];
+ int cnt;
+ int ls = strsplit(s, line[n], Lseparator);
+ int scnt = 0;
+ string startnet;
+ for (int ln = 0; ln < ls; ln++) {
+ if (s[ln]) {
+ scnt++;
+ if (scnt == NetRow) {
+ Lnet = s[ln];
+ if (actualsigname != Lnet) {
+ sprintf(startnet, ";\nSIGNAL '%s'", Lnet);
+ actualsigname = Lnet;
+ }
+ else startnet = "\n ";
+
+ }
+ else if (scnt == PartRow) Lpart = s[ln];
+ else if (scnt == PadRow) Lpad = s[ln];
+ }
+ }
+ string h;
+ if (scnt == 3) {
+ sprintf(h, "%s %s %s", startnet, Lpart, Lpad);
+ netscript+=h;
+ }
+ }
+ netscript+=";\n"; // close last command
+ return;
+}
+
+
+void genScriptTango(void) {
+ dlgMessageBox("Tango converter not defined!", "OK");
+ return;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ for (int n = 0; n < lines; n++) {
+ status(line[n]);
+ string s[];
+ int cnt;
+ int ls = strsplit(s, line[n], Lseparator);
+ int scnt = 0;
+ string startnet;
+ for (int ln = 0; ln < ls; ln++) {
+ if (s[ln]) {
+ scnt++;
+ if (scnt == NetRow) {
+ Lnet = s[ln];
+ if (actualsigname != Lnet) {
+ sprintf(startnet, ";\nSIGNAL '%s'", Lnet);
+ actualsigname = Lnet;
+ }
+ else startnet = "\n ";
+
+ }
+ else if (scnt == PartRow) Lpart = s[ln];
+ else if (scnt == PadRow) Lpad = s[ln];
+ }
+ }
+ string h;
+ if (scnt == 3) {
+ sprintf(h, "%s %s %s", startnet, Lpart, Lpad);
+ netscript+=h;
+ }
+ }
+ netscript+=";\n"; // close last command
+ return;
+}
+
+
+void genScriptMentor(void) {
+ // defintion of separator for Multiwire;
+ Lseparator = ' ';
+ Wseparator = '.';
+ NetRow = 1;
+ PartRow = 2;
+ PadRow = 3;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ for (int n = 0; n < lines; n++) {
+ status(line[n]);
+ string s[];
+ int cnt;
+ int ls = strsplit(s, line[n], Lseparator);
+ int scnt = 0;
+ string startnet;
+ if (s[0] == "NET") { // check if a NET line
+ sprintf(startnet, "SIGNAL %s \n", s[1]);
+ for (int ln = 2; ln < ls; ln++) {
+ string pp[];
+ strsplit(pp, s[ln], '-');
+ startnet += " "+pp[0] + " " + pp[1] + "\n";
+ }
+ netscript+=startnet+";\n";
+ }
+ }
+ return;
+}
+
+
+void genScriptPADS2000(void) {
+ // defintion of separator for PADS 2000;
+ if (line[0] != "*PADS2000*") {
+ dlgMessageBox("it's not a *PADS2000* netlist!", "OK");
+ return;
+ }
+ Lseparator = ' ';
+ Wseparator = '.';
+ NetRow = 1;
+ PartRow = 2;
+ PadRow = 3;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ string startnet = "";
+ int startflag = 0;
+ string s[];
+ for (int n = 0; n < lines; n++) {
+ if (startflag) {
+ status(line[n]);
+ int ls = strsplit(s, line[n], Lseparator);
+ if (s[0] == "*SIGNAL*") { // check if a Signal line
+ if (!startnet) {
+ sprintf(startnet, "SIGNAL '%s' \n", s[1]);
+ }
+ else {
+ netscript += startnet+";\n";
+ sprintf(startnet, "SIGNAL '%s' \n", s[1]);
+ }
+ }
+ else if (s[0] == "*END*") { // check if a END of list
+ netscript += startnet+";\n";
+ }
+ else {
+ string pp[];
+ int cntpp = strsplit(pp, line[n], Lseparator);
+ string sp[];
+ for (int np = 0; np < cntpp; np++) {
+ strsplit(sp, pp[np], Wseparator);
+ startnet += " "+sp[0] + " " + sp[1] + "\n";
+ }
+ }
+ }
+ if (line[n] == "*NET*") {
+ startflag = 1;
+ }
+ }
+ return;
+}
+
+
+void genScriptAccel(void) {
+ // defintion of separator for Accel;
+ Lseparator = ' ';
+ Wseparator = '.';
+ saveinfo = "";
+ dlgRedisplay();
+ netscript = "";
+ string startnet = "";
+ int startflag = 0;
+ string s[];
+ string nn[];
+ for (int n = 0; n < lines; n++) {
+ status(line[n]);
+ int ls = strsplit(s, line[n], Lseparator);
+ if (s[0] == "(net") { // check if a Signal line
+ strsplit(nn, line[n], '"');
+ sprintf(startnet, ";\nSIGNAL '%s' \n", nn[1]);
+ netscript += startnet;
+ }
+ else if (s[0] == "(node") {
+ strsplit(nn, line[n], '"');
+ netscript += nn[1] + " " + nn[3] + "\n";
+ }
+ }
+ netscript += ";\n";
+ return;
+}
+
+
+void genScriptAllegro(void) {
+ // defintion of separator for allegro;
+ Lseparator = ' ';
+ Wseparator = '.';
+ NetRow = 1;
+ PartRow = 2;
+ PadRow = 3;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ string startnet = "";
+ int startflag = 0;
+ string s[];
+ for (int n = 0; n < lines; n++) {
+ if (startflag) {
+ status(line[n]);
+ int ls = strsplit(s, line[n], Lseparator);
+ if (s[0] == "$END") { // check if a END of list
+ netscript += ";\n";
+ }
+ else {
+ ls = strsplit(s, line[n], ';');
+ sprintf(startnet, "SIGNAL %s \n", s[0]);
+ netscript += startnet;
+ ls = strsplit(s, line[n], Lseparator);
+ string sp[];
+ for (int np = 1; np < ls; np++) {
+ int cntpp = strsplit(sp, s[np], Wseparator);
+ netscript += " "+sp[0] + " " + sp[1] + "\n";
+ }
+ }
+ }
+ if (line[n] == "$NETS") {
+ startflag = 1;
+ }
+ }
+ return;
+}
+
+void genScriptAllegro162(void) { // 2010-06-17 alf
+ // (GENERATED BY: ALLEGRO 16.2 S034 (v16-2-57BX))
+ // defintion of separator for allegro;
+ Lseparator = ' ';
+ Wseparator = '.';
+ NetRow = 1;
+ PartRow = 2;
+ PadRow = 3;
+ saveinfo = "";
+ dlgRedisplay();
+ string Lnet, Lpart, Lpad;
+ netscript = "";
+ string actualsigname = "";
+ string startnet = "";
+ int startflag = 0;
+ string s[];
+ for (int n = 0; n < lines; n++) {
+ if (startflag) {
+ if (line[n] == "$NETS") {
+ netscript += ";\n";
+ startflag = 0;
+ break;
+ }
+ status(line[n]);
+ int semipos = strchr(line[n], ';');
+ if (semipos > 0) line[n][semipos] = ' '; // replace semikolon to Space 2020-06-17 alf
+ int kommapos = strchr(line[n], ','); // Weiterführungszeichen, dass es in dernächsten Zeile mit dem Signalnamen weiter geht.
+ if (kommapos > 0) line[n][kommapos] = ' '; // replace komma to Space 2020-06-17 alf
+ int ls = strsplit(s, line[n], Lseparator);
+ if (s[0]) {
+ if (startflag == 1) {
+ sprintf(startnet, "SIGNAL '%s' \n", s[0]);
+ startflag++;
+ }
+ else sprintf(startnet, ";\nSIGNAL '%s' \n", s[0]);
+ netscript += startnet;
+ }
+ string sp[];
+ for (int np = 1; np < ls; np++) {
+ if (s[np]) { // 2010-06-16 alf
+ int cntpp = strsplit(sp, s[np], Wseparator);
+ netscript += " "+sp[0] + " " + sp[1] + "\n";
+ }
+ }
+ }
+ if (line[n] == "$NETS") {
+ if (!startflag) startflag = 1;
+ }
+ }
+ return;
+}
+
+
+void save(string f) {
+ dlgRedisplay();
+ string fn = filesetext(f, ".scr");
+ output(fn, "wt") printf("%s", netscript);
+ sprintf(saveinfo, "Scripte saved as: %s", fn);
+ dlgRedisplay();
+ return;
+}
+
+
+string getList(string TypeName) {
+ return dlgFileOpen("Select a " + TypeName + " netlist'", path_epf[0]+"/*.*");
+}
+
+
+int autocheckFormat(void) { // auto check CAD-Format in first 10 lines 2010-06-17 alf
+ for (int n = 0; n < 10; n++) {
+ if (strstr(line[n], "ALLEGRO 16.2") >= 0) return Allegro162;
+ }
+ return 0;
+}
+
+
+// --- main ---
+if (board) {
+ int selType = Unknown;
+ int RESULT = dlgDialog("Netlist Converter") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgLabel(NetlistInfo, 1);
+ dlgTextEdit(text);
+ }
+ dlgVBoxLayout {
+ dlgLabel("EAGLE net script");
+ dlgTextEdit(netscript);
+ }
+ }
+ dlgHBoxLayout {
+ dlgGridLayout {
+ dlgCell(0, 0) dlgLabel("Line separator");
+ dlgCell(0, 1) dlgStringEdit(L_separator);
+ dlgCell(0, 2) dlgLabel("Word separator");
+ dlgCell(0, 3) dlgStringEdit(W_separator);
+ }
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgGridLayout {
+ dlgCell(0, 0) dlgLabel("Net in row");
+ dlgCell(0, 1) dlgIntEdit(NetRow);
+ dlgCell(0, 3) dlgLabel("Part in row");
+ dlgCell(0, 4) dlgIntEdit(PartRow);
+ dlgCell(0, 5) dlgLabel("Pad in row");
+ dlgCell(0, 6) dlgIntEdit(PadRow);
+ }
+ dlgSpacing(200);
+ dlgStretch(1);
+ }
+ dlgHBoxLayout {
+ dlgGroup("Netlist from CAD System") {
+ for (int t = 0; t < Last; t++) {
+ dlgRadioButton(netListType[t], selType) {
+ NetlistInfo = netListType[selType]+ " Netlist";
+ dlgRedisplay();
+ }
+ }
+ }
+ dlgStretch(3);
+ dlgVBoxLayout {
+ dlgLabel("EAGLE NET-SCRIPT Example:");
+ dlgLabel("SIGNAL 'N$1' X1 1 R2 1; SIGNAL 'N$2' R2 2 C2 1 R3 2;");
+ dlgStretch(1);
+ }
+ dlgStretch(2);
+ }
+ dlgLabel(saveinfo, 1);
+ dlgHBoxLayout {
+ dlgPushButton("&Read list") {
+ fname = getList(netListType[selType]);
+ if (!fname) {
+ dlgMessageBox("no file selected", "OK");
+ }
+ else {
+ lines = fileread(text, fname);
+ lines = strsplit(line, text, '\n');
+ selType = autocheckFormat();
+ }
+ }
+ dlgPushButton("&Generate net script") {
+ switch(selType) {
+ case Unknown : if(L_separator == "SPACE") Lseparator = ' ';
+ else if(L_separator == "TAB") Lseparator = '\t';
+ else Lseparator = L_separator[0];
+ Wseparator = W_separator[0];
+ genScriptUnknown();
+ break;
+ case Multiwire : genScriptMultiwire();
+ break;
+// case OrCad : genScriptOrCad();
+ break;
+// case Tango : genScriptTango();
+ break;
+ case Mentor : genScriptMentor();
+ break;
+ case PADS2000 : genScriptPADS2000();
+ break;
+ case Accel : genScriptAccel();
+ break;
+ case Allegro : genScriptAllegro();
+ break;
+ case Allegro162 : genScriptAllegro162();
+ break;
+
+ }
+ }
+ dlgPushButton("&Run net script") {
+ if (!saveinfo) {
+ dlgMessageBox("First save the script.", "OK");
+ }
+ else {
+ if (project.schematic) {
+ dlgMessageBox("!This Script can not start if a consitence schematic loaded!
DO NOT CLOSE SCHEMATIC, YOU LOST CONSISTENCE!", "OK");
+ }
+ else dlgAccept();
+ }
+ }
+ dlgPushButton("&Save net script") {
+ if (netscript) save(fname);
+ else dlgMessageBox("First generate script!", "OK");
+ }
+ dlgPushButton("-CANCEL") dlgReject();
+ dlgStretch(1);
+ dlgLabel(Version);
+ }
+ };
+ if (RESULT) exit("SCRIPT '" + filesetext(fname, ".scr") + "'");
+}
+
+else dlgMessageBox("!Start this ULP in board.", "OK");
\ No newline at end of file
diff --git a/trunk/ulp/netlist_protel.ulp b/trunk/ulp/netlist_protel.ulp
new file mode 100644
index 00000000..d75a4dcd
--- /dev/null
+++ b/trunk/ulp/netlist_protel.ulp
@@ -0,0 +1,93 @@
+/*
+ * This EAGLE User Language Program prints the netlist of a board
+ * in standard Protel format (1.0) (very similar to Tango netlist format)
+ * to import it to Protel PCB software.
+ *
+ * It is also possible to print the netlist of a schematic,
+ * but this will not adhere to the correct Protel format:
+ * package names are missing, pin names instead of pad names.
+ *
+ * If you have only the schematic, just generate the board and run this
+ * ULP in the EAGLE board editor.
+ *
+ * 19.09.2001 Hans Lederer, Ingenieurbüro Lederer, Emmendingen
+ * Hans.Lederer@ib-lederer.de
+ */
+
+if (board) board(B) {
+ output(filesetext(B.name, ".NET")) {
+
+ B.elements(E) {
+ printf("%s\n","[");
+ printf("%s\n",E.name);
+ printf("%s\n",E.package.name);
+ printf("%s\n",E.value);
+ printf("\n\n\n%s\n","]");
+ }
+
+ B.signals(S) {
+ numeric string Part[], Pad[];
+ int cnt = 0, index[];
+
+ S.contactrefs(C) {
+ Part[cnt] = C.element.name;
+ Pad[cnt] = C.contact.name;
+ cnt++;
+ }
+ if (cnt) {
+ sort(cnt, index, Part, Pad);
+ printf("%s\n","(");
+ printf("%s\n",S.name);
+ for (int i = 0; i < cnt; i++)
+ printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]);
+ printf("%s\n",")");
+ }
+ }
+ }
+ }
+
+if (schematic) schematic(SCH) {
+ output(filesetext(SCH.name, ".net")) {
+
+ SCH.parts(P) {
+ int pos_g = strrstr(P.device.name,"GND");
+ int pos_v = strrstr(P.device.name,"VCC");
+ int pos_p = strrstr(P.device.name,"VPP");
+
+ if ((pos_g < 0) && (pos_v < 0) && (pos_p < 0)) {
+ string pkg = P.device.package.name;
+ int dip_dil = strrstr(pkg,"DIL");
+ if ( dip_dil >= 0)
+ pkg[2]='P';
+ printf("%s\n","[");
+ printf("%s\n",P.name);
+ printf("%s\n",pkg);
+ // printf("%s\n",P.device.name);
+ printf("%s\n",P.value);
+ printf("\n\n\n%s\n","]");
+ }
+ }
+
+ SCH.nets(N) {
+ numeric string Part[], Pin[], trimmed, Pad[];
+ int cnt = 0, index[];
+
+ N.pinrefs(P) {
+ Part[cnt] = P.part.name;
+ Pin[cnt] = P.pin.name;
+ Pad[cnt] = P.pin.contact.name;
+ cnt++;
+ }
+
+ if (cnt) {
+ sort(cnt, index, Part, Pin);
+ printf("%s\n","(");
+ printf("%s\n",N.name);
+ for (int i = 0; i < cnt; i++) {
+ printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]);
+ }
+ printf("%s\n",")");
+ }
+ }
+ }
+ }
diff --git a/trunk/ulp/netlist_protel.ulp.INF b/trunk/ulp/netlist_protel.ulp.INF
new file mode 100644
index 00000000..0826d173
--- /dev/null
+++ b/trunk/ulp/netlist_protel.ulp.INF
@@ -0,0 +1,5 @@
+Name: Hans Lederer
+Email: Hans.Lederer at ib-lederer.de
+Organization: Ingenieurbuero Lederer
+Description:
+Generates a netlist in Protel Standard format (similar to Tango)
diff --git a/trunk/ulp/nextdevdescript.ulp b/trunk/ulp/nextdevdescript.ulp
new file mode 100644
index 00000000..b92daf60
--- /dev/null
+++ b/trunk/ulp/nextdevdescript.ulp
@@ -0,0 +1,43 @@
+#usage "Edit next device description\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string dev[];
+string edit = "";
+int count = 0;
+int n = 0;
+
+if (library) library(L) {
+ L.devicesets(D) {
+ count++;
+ dev[count] = D.name;
+ cmd += D.name + "\n";
+ }
+ }
+
+if (deviceset) deviceset(D) {
+ edit = D.name;
+ }
+
+for (n = 1; n < count; n++) {
+ if (edit == dev[n]) {
+ break;
+ }
+ }
+
+if (n < count) {
+ cmd = "EDIT " + dev[n + 1] + ".dev;\n DESCRIPT\n" ;
+ // **************************************************
+ // a ";" must not follow DESCRIPT
+ // otherwise the description is overwritten
+ // with an empty string
+ // **************************************************
+
+ }
+else
+ cmd = "EDIT " + dev[1] + ".dev;\n DESCRIPT\n" ;
+
+exit(cmd);
diff --git a/trunk/ulp/nextpacdescript.ulp b/trunk/ulp/nextpacdescript.ulp
new file mode 100644
index 00000000..7903ac4c
--- /dev/null
+++ b/trunk/ulp/nextpacdescript.ulp
@@ -0,0 +1,44 @@
+#usage "Edit next package description\n"
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+string cmd = "";
+string pac[];
+string edit = "";
+int count = 0;
+int n = 0;
+
+if (library) library(L) {
+ L.packages(P) {
+ count++;
+ pac[count] = P.name;
+ cmd += P.name + "\n";
+ }
+ }
+
+if (package) package(P) {
+ edit = P.name;
+ }
+
+for (n = 1; n < count; n++) {
+ if (edit == pac[n]) {
+ // dlgMessageBox(dev[n+1], "+Ok", "-Cancel");
+ break;
+ }
+ }
+
+if (n < count) {
+ cmd = "EDIT " + pac[n + 1] + ".pac;\n DESCRIPT\n" ;
+ // **************************************************
+ // a ";" must not follow DESCRIPT
+ // otherwise the description is overwritten
+ // with an empty string
+ // **************************************************
+
+ }
+else
+ cmd = "EDIT " + pac[1] + ".pac;\n DESCRIPT\n" ;
+
+exit(cmd);
diff --git a/trunk/ulp/normalize-text.ulp b/trunk/ulp/normalize-text.ulp
new file mode 100644
index 00000000..a69336b6
--- /dev/null
+++ b/trunk/ulp/normalize-text.ulp
@@ -0,0 +1,245 @@
+#usage "Normalize silkscreen text sizes
\n"
+ "
This ULP program smashes all texts on the silkscreen layers. It then normalizes the "
+ "texts so that they all have the same size and thickness. Ratio is calculated from "
+ "the desired thickness.
"
+ "Author: Tennessee Carmel-Veilleux (veilleux@ameth.org)"
+
+/****************************************************************************************
+* *
+* Normalize silkscreen text sizes *
+* *
+* Filename: normalize-text.ulp *
+* Version: 1.0 *
+* Author: Tennessee Carmel-Veilleux *
+* Date: March 31st 2005 *
+* Company: Entreprises Ten Tech *
+* * *
+* This ULP program smashes all texts on the silkscreen layers. It then normalizes the *
+* texts so that they all have the same size and thickness. Ratio is calculated from *
+* the desired thickness. *
+* *
+****************************************************************************************/
+
+#require 5.0300;
+
+string VERSION = "1.1"; // 2008-11-07 alf@cadsoft.de
+
+int result = 0; // Dialog result
+
+string str; // Temporary string
+string cmd = "SET UNDO_LOG OFF;\n"; // Script command to execute
+real text_size = 40.0; // Text size for all texts
+real text_thickness = 8.0; // Text thickness for all texts
+int text_ratio; // Calculated text ratio
+
+int silk_screen_layers[] = {LAYER_TPLACE, LAYER_BPLACE, LAYER_TNAMES,
+ LAYER_BNAMES, LAYER_TVALUES, LAYER_BVALUES,
+ LAYER_TDOCU, LAYER_BDOCU, 125, 126 };
+ // 2008-11-07 Layer 125, 126 is created by panalize.ulp.
+
+enum {UNIT_MIL, UNIT_MM};
+int units = UNIT_MM;
+int lastunit = units;
+text_size = 1.0;
+text_thickness = 0.1;
+
+int visibleLayer[];
+int actualvisible = 0;
+
+
+/* ------------- UTILITY FUNCTIONS --------------- */
+
+//
+// Redisplays the layers that were visible when the ULP was started
+//
+
+void ResetVisible(UL_BOARD B) {
+ sprintf(str, "DISP NONE;\nDISP ");
+ cmd += str;
+ B.layers(L) {
+ if (L.visible) {
+ sprintf(str, "%d ", L.number);
+ cmd += str;
+ }
+ }
+ cmd += ";\n";
+}
+
+//
+// Returns 1 if a layer is a silkscreen layer
+//
+
+int SilkScreenText(int layer) {
+ int i = 0;
+ int found = 0;
+ do { // 2008-11-07
+ if (layer == silk_screen_layers[i]) {
+ found = 1;
+ if (actualvisible != layer) { // display only the layer with text to change
+ // in a script can not select texts by thew same coodiante
+ sprintf(str, "DISPLAY NONE %d;\n", layer);
+ cmd += str;
+ }
+ break;
+ }
+ i++;
+ } while(silk_screen_layers[i]);
+
+ return found;
+}
+
+//
+// Resizes a text element to the specified size and ratio
+//
+void ResizeText(UL_TEXT T, real size, int ratio) {
+ if (SilkScreenText(T.layer)) {
+ switch (units) {
+ case UNIT_MIL:
+ sprintf(str,"CHANGE SIZE %.4f (%.4f %.4f);\nCHANGE RATIO %d (%.4f %.4f);\n",
+ size, u2mil(T.x), u2mil(T.y), ratio, u2mil(T.x), u2mil(T.y));
+ break;
+ case UNIT_MM:
+ sprintf(str,"CHANGE SIZE %.4f (%.4f %.4f);\nCHANGE RATIO %d (%.4f %.4f);\n",
+ size, u2mm(T.x), u2mm(T.y), ratio, u2mm(T.x), u2mm(T.y));
+ break;
+ }
+ cmd += str;
+ }
+}
+
+//
+// Smashes all parts that have an associated package on the board and resize
+// all text to SIZE and RATIO.
+//
+void ProcessTexts(real size, int ratio) {
+ // Display the origins of components
+ switch (units) {
+ case UNIT_MIL:
+ sprintf(str,"GRID MIL 1;\n");
+ break;
+ case UNIT_MM:
+ sprintf(str,"GRID MM 0.1;\n");
+ break;
+ }
+ cmd += str;
+
+ cmd += "DISPLAY NONE 23 24;\n";
+
+ board(B) {
+ B.elements(E) {
+ if (E.package) {
+ // Smash the package to make sure text is CHANGE-able
+ sprintf(str,"SMASH %s;\n", E.name);
+ cmd += str;
+ // Change smashed texts
+ E.texts(T) {
+ ResizeText(T, size, ratio);
+ }
+
+ // Change unsmashed texts
+ E.package.texts(T) {
+ ResizeText(T, size, ratio);
+ }
+ }
+ }
+
+ // Change all manually-added texts
+ B.texts(T) {
+ ResizeText(T, size, ratio);
+ }
+
+ ResetVisible(B);
+ }
+ cmd += "GRID LAST;\nSET UNDO_LOG ON;\n";
+}
+
+/* ------------- MAIN ROUTINE --------------- */
+if (board) {
+ int actsize;
+ result = dlgDialog("Normalize silkscreen text sizes") {
+ sprintf(str,"
Normalize silkscreen text sizes %s
"+
+ "
By Tennessee Carmel-Veilleux (veilleux@ameth.org)
"+
+ "
This ULP normalizes all the text on the silkscreen layers to "+
+ "the specified size and thickness. The ratio is automatically calculated " +
+ "from the size and thickness.
"
+ "Autor: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+/*
+ Complete the following steps to add a new output device definition:
+
+ 1. Add a new member to the 'enum { devScript = 1, ...'
+ 2. Add the new (unique!) device name to 'DeviceNames[]'
+ 3. Add the necessary 'case dev...' branches to 'DeviceInit()', 'DeviceDraw()' and 'DeviceEnd()'
+*/
+
+string I18N[] = {
+ "en\v"
+ "de\v"
+ ,
+ "ERROR: \v"
+ "FEHLER: \v"
+ ,
+ "No board!\v"
+ "Kein Board!\v"
+ ,
+ "This program can only work in the board editor.\v"
+ "Dieses Programm kann nur im Board-Editor angewendet werden.\v"
+ ,
+ "Illegal width: \v"
+ "Ungültige Breite: \v"
+ ,
+ "The width must be greater than zero.\v"
+ "Die Breite muß größer als 0 sein.\v"
+ ,
+ "Illegal layer: \v"
+ "Ungültiger Layer: \v"
+ ,
+ "The layer must be one of 1..16 or 0 to use the current layer.\v"
+ "Der Layer muß im Bereich 1..16 liegen, oder 0 sein um den aktuellen Layer zu wählen.\v"
+ ,
+ "Select a device\v"
+ "Wählen Sie ein Ausgabegerät\v"
+ ,
+ "There is already a signal named \v"
+ "Es existiert bereits ein Signal namens \v"
+ ,
+ " in this board!\v"
+ " in diesem Board!\v"
+ ,
+ "Please make sure that there is no such signal in this board.\v"
+ "Bitte sorgen Sie dafür, daß es kein solches Signal in diesem Board gibt.\v"
+ ,
+ "Illegal device: \v"
+ "Ungültiges Ausgabegerät: \v"
+ ,
+ "Please select one of the known devices.\v"
+ "Bitte wählen Sie eines der bekannten Ausgabegeräte aus.\v"
+ ,
+ "No signal layer active!\v"
+ "Kein Signal-Layer aktiv!\v"
+ ,
+ "Please activate the signal layer to generate outlines for.\v"
+ "Bitte aktivieren den Signal-Layer für den Konturdaten generiert werden sollen.\v"
+ ,
+ "Invalid layer: \v"
+ "Ungültiger Layer: \v"
+ ,
+ "The layer was not found or is not active.\v"
+ "Der Layer konnte nicht gefunden werden oder ist nicht aktiv.\v"
+ ,
+ "Outlines Generator\v"
+ "Konturdaten-Generator\v"
+ ,
+ "&Width\v"
+ "&Breite\v"
+ ,
+ "&Layer\v"
+ "&Layer\v"
+ ,
+ "&Output file\v"
+ "&Ausgabedatei\v"
+ ,
+ "&Browse\v"
+ "&Durchsuchen\v"
+ ,
+ "Save Outlines file\v"
+ "Konturdaten speichern\v"
+ ,
+ "+OK\v"
+ "+OK\v"
+ ,
+ "No device selected!\v"
+ "Kein Ausgabegerät ausgewählt!\v"
+ ,
+ "Please select a device.\v"
+ "Bitte wählen Sie ein Ausgabegerät.\v"
+ ,
+ "Illegal width: 0\v"
+ "Ungültige Breite: 0\v"
+ ,
+ "The width must be greater than zero.\v"
+ "Die Breite muß größer als Null sein.\v"
+ ,
+ "-Cancel\v"
+ "-Abbrechen\v"
+ ,
+ "About\v"
+ "Info\v"
+ };
+
+int Language = strstr(I18N[0], language()) / 3;
+
+string tr(string s)
+{
+ string t = lookup(I18N, s, Language, '\v');
+ return t ? t : s;
+}
+
+void Fatal(string Message, string Details)
+{
+ dlgMessageBox(usage + "
\n" + Details);
+}
+
+//
+// Parmameters
+//
+
+string DefaultSuffix = ".out";
+
+string Device;
+real Width = 0;
+int Layer = 0;
+string FileName;
+
+if (!board)
+ Fatal(tr("No board!"), tr("This program can only work in the board editor."));
+
+if (argv[1]) {
+ Device = argv[1];
+ if (argv[2]) {
+ Width = strtod(argv[2]);
+ if (Width <= 0)
+ Fatal(tr("Illegal width: ") + argv[2], tr("The width must be greater than zero."));
+ if (argv[3]) {
+ Layer = strtol(argv[3]);
+ if (Layer < 0 || Layer > 16)
+ Fatal(tr("Illegal layer: ") + argv[3], tr("The layer must be one of 1..16 or 0 to use the current layer."));
+ if (argv[4]) {
+ FileName = argv[4];
+ }
+ }
+ }
+ }
+
+if (!FileName)
+ board(B) FileName = filesetext(B.name, DefaultSuffix);
+
+//
+// The various output devices
+//
+
+enum { devScript = 1, devHPGL };
+string DeviceNames[] = { tr("Select a device"), "Script", "HPGL" };
+int SelectedDevice;
+
+void DeviceInit(void)
+{
+ // Do anything necessary to initialize the output device
+ switch (SelectedDevice) {
+ case devScript:
+ // TODO make the layer user definable?
+ printf("layer %d;\nset wire_bend 2; grid mm; change width %f;\n", Layer + 100, Width);
+ break;
+ case devHPGL:
+ break;
+ }
+}
+
+void DeviceDraw(int x1, int y1, int x2, int y2, int state)
+{
+ // Actually draw a line on the output device.
+ // 'state' is defined as
+ // 0 = this is the first line of a partial polygon
+ // 1 = this is a "normal" line (neither the first nor the last one)
+ // 2 = this is the last line of a partial polygon
+ switch (SelectedDevice) {
+ case devScript:
+ if (state == 0)
+ printf("wire (%f %f) (%f %f)", u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2));
+ else {
+ printf(" (%f %f)", u2mm(x2), u2mm(y2));
+ if (state == 2)
+ printf(";\n");
+ }
+ break;
+ case devHPGL:
+ if (state == 0)
+ printf("PU; PA %f %f; PD; PA %f %f;", u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2));
+ else {
+ printf(" PA %f %f", u2mm(x2), u2mm(y2));
+ if (state == 2)
+ printf("\n");
+ }
+ break;
+ }
+}
+
+void DeviceEnd(void)
+{
+ // Do anything necessary to end output to the device
+ switch (SelectedDevice) {
+ case devScript:
+ break;
+ case devHPGL:
+ printf("PU;\n");
+ break;
+ }
+}
+
+//
+// The actual outlines generator
+//
+
+string OutlinesSignalName = "_OUTLINES_";
+string Pass2 = "PASS_2";
+
+int InPass2 = argv[5] == Pass2;
+
+void GenerateOutlines(void)
+{
+ board(B) {
+ real f = 20, // mm frame
+ x1 = u2mm(B.area.x1) - f, y1 = u2mm(B.area.y1) - f,
+ x2 = u2mm(B.area.x2) + f, y2 = u2mm(B.area.y2) + f;
+ B.signals(S) {
+ if (S.name == OutlinesSignalName)
+ Fatal(tr("There is already a signal named ") + OutlinesSignalName + tr(" in this board!"), tr("Please make sure that there is no such signal in this board."));
+ }
+ string Cmd;
+ sprintf(Cmd, "grid mm;\n"
+ "window fit;\n"
+ "change isolate 0;\n"
+ "change rank 6;\n"
+ "change pour solid;\n"
+ "change orphans on;\n"
+ "layer %d;\n"
+ "polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n"
+ "ratsnest;\n"
+ "run '%s' '%s' '%f' '%d' '%s' '%s';",
+ Layer,
+ OutlinesSignalName, Width, x1, y1, x2, y1, x2, y2, x1, y2, x1, y1,
+ argv[0], Device, Width, Layer, FileName, Pass2);
+ exit(Cmd);
+ }
+}
+
+void WriteOutlines(void)
+{
+ board(B) {
+ output(FileName) {
+ string Cmd;
+ B.signals(S) {
+ if (S.name == OutlinesSignalName) {
+ S.polygons(P) {
+ int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN;
+ int x0, y0, first = 1;
+ int FrameWire;
+ int State;
+
+ P.wires(W) {
+ x1 = min(x1, W.x1);
+ x2 = max(x2, W.x1);
+ y1 = min(y1, W.y1);
+ y2 = max(y2, W.y1);
+ }
+ DeviceInit();
+ P.contours(W) {
+ if (first) {
+ // a new partial polygon is starting
+ x0 = W.x1;
+ y0 = W.y1;
+ FrameWire = (x1 == x0 || x2 == x0) && (y1 == y0 || y2 == y0);
+ State = 0;
+ first = 0;
+ }
+ else if (W.x2 == x0 && W.y2 == y0) {
+ // this was the last wire of the partial polygon,
+ // so the next wire (if any) will be the first wire
+ // of the next partial polygon
+ State = 2;
+ first = 1;
+ }
+ else
+ State = 1;
+ if (!FrameWire)
+ DeviceDraw(W.x1, W.y1, W.x2, W.y2, State);
+ }
+ DeviceEnd();
+ sprintf(Cmd, "delete (%f %f) (%f %f); window fit;\n", u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2));
+ }
+ break;
+ }
+ }
+ exit(Cmd);
+ }
+ }
+}
+
+//
+// Main program:
+//
+
+if (Device) {
+ int n;
+ while (DeviceNames[n]) {
+ if (strupr(DeviceNames[n]) == strupr(Device)) {
+ SelectedDevice = n;
+ break;
+ }
+ n++;
+ }
+ if (!SelectedDevice)
+ Fatal(tr("Illegal device: ") + Device, tr("Please select one of the known devices."));
+ }
+
+if (!InPass2) {
+ string Layers[];
+ int SelectedLayer = -1;
+ int ForceDialog = (!Device || !Width);
+
+ board(B) {
+ int n;
+ B.layers(L) {
+ if (L.number <= 16 && L.visible) {
+ if (Layer == L.number)
+ SelectedLayer = n;
+ sprintf(Layers[n++], "%d %s", L.number, L.name);
+ }
+ }
+ if (n == 0)
+ Fatal(tr("No signal layer active!"), tr("Please activate the signal layer to generate outlines for."));
+ if (!Layer) {
+ if (n > 1)
+ ForceDialog = 1;
+ SelectedLayer = 0;
+ }
+ if (SelectedLayer < 0) {
+ string s;
+ sprintf(s, "%d", Layer);
+ Fatal(tr("Invalid layer: ") + s, tr("The layer was not found or is not active."));
+ }
+ }
+
+ if (ForceDialog) {
+ dlgDialog(tr("Outlines Generator")) {
+ dlgGridLayout {
+ dlgCell(0, 0) dlgLabel("&Device");
+ dlgCell(0, 1) dlgComboBox(DeviceNames, SelectedDevice) {
+ // TODO should we generalize this?
+ if (FileName && SelectedDevice == devScript)
+ FileName = filesetext(FileName, ".scr");
+ }
+ dlgCell(1, 0) dlgLabel(tr("&Width"));
+ dlgCell(1, 1) dlgRealEdit(Width, 0, 10);
+ dlgCell(2, 0) dlgLabel(tr("&Layer"));
+ dlgCell(2, 1) dlgComboBox(Layers, SelectedLayer);
+ }
+ dlgHBoxLayout {
+ dlgLabel(tr("&Output file"));
+ dlgStringEdit(FileName);
+ dlgPushButton(tr("&Browse")) {
+ string fn = dlgFileSave(tr("Save Outlines file"), FileName);
+ if (fn)
+ FileName = fn;
+ }
+ }
+ dlgStretch(1);
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgPushButton(tr("+OK")) {
+ if (!SelectedDevice)
+ Error(tr("No device selected!"), tr("Please select a device."));
+ else if (!Width)
+ Error(tr("Illegal width: 0"), tr("The width must be greater than zero."));
+ else
+ dlgAccept();
+ }
+ dlgPushButton(tr("-Cancel")) { dlgReject(); exit(1); }
+ dlgPushButton(tr("About")) dlgMessageBox(usage);
+ }
+ };
+ }
+ Device = DeviceNames[SelectedDevice];
+ Layer = strtol(Layers[SelectedLayer]);
+ GenerateOutlines();
+ }
+else
+ WriteOutlines();
diff --git a/trunk/ulp/panelize.ulp b/trunk/ulp/panelize.ulp
new file mode 100644
index 00000000..486d5b19
--- /dev/null
+++ b/trunk/ulp/panelize.ulp
@@ -0,0 +1,131 @@
+#usage "Generate name layers to panelize board\n"
+ "
"
+ "Generates a command sequence which copies the name texts (support spin-flag) "
+ "of all elements of your layout into newly generated layers (125 and 126). "
+ "After running the ULP you can GROUP, CUT and PASTE your layout "
+ "to get an array of several boards. Make sure all layers are displayed before."
+ "
"
+ "The duplicated name texts in the new layers will not be changed. "
+ "Please notice that you have to deactivate layers 25 and 26 if you use "
+ "the CAM processor e.g. for generating gerber data. Instead, you have to activate "
+ "the new layers 125 and 126. Thus you get an identical silk screen for all "
+ "your layouts in this array."
+ "
"
+ "Texts must be SMASHed before we can duplicate them! "
+ "
"
+ "Author: support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+#require 4.1106;
+
+// 6.12.2004 Text with Spin-Flag support@cadsoft.de
+// 28.06.2006 accept Sigle-Quote on end of name of element support@cadsoft.de
+
+int offset = 100;
+string tcolor = "yellow";
+string bcolor = "magenta";
+int used_name_layers[];
+string used_name_[];
+
+string cmd_header;
+string cmd = "\nSET UNDO_LOG OFF;\nGRID MIL;\n"; // advisable for speed reasons
+string h;
+
+string check_single_quote(string s) { // 2006.06.28
+ int l = strlen(s);
+ if (s[l-1] == '\'') s+="'";
+ return s;
+}
+
+void test(void) {
+ string txt = "Used Layers for >NAME\n";
+ for (int n = 0; n < 256; n++) {
+ if(used_name_layers[n]) {
+ sprintf(h, "Layer %3d count %d\t%s\n", n, used_name_layers[n], used_name_[n]);
+ txt += h;
+ }
+ }
+ if (dlgMessageBox(txt, "OK", "Cancel") != 0) exit(-1);
+ return;
+}
+
+void header(void) {
+ for (int n = 0; n < 256; n++) {
+ if(used_name_layers[n]) {
+ sprintf(h, "layer %d _%s;\n", n + offset, used_name_[n]);
+ cmd_header += h;
+ if (n & 1) sprintf(h, "set color_layer %d %s;\n", n + offset, tcolor);
+ else sprintf(h, "set color_layer %d %s;\n", n + offset, bcolor);
+ cmd_header += h;
+ }
+ }
+}
+
+void Text(string Ename, int Tlayer, int Tx, int Ty, int Tsize, real Tangle, int Tratio, int Tmirror, int Tspin) {
+ sprintf(h, "Change Layer %d;\n", Tlayer + offset);
+ cmd += h;
+ sprintf(h, "Change Size %5.3f;\n", u2mil(Tsize));
+ cmd += h;
+ sprintf(h, "Change Ratio %d;\n", Tratio);
+ cmd += h;
+ string mirr, spin;
+ if (Tmirror) mirr = "M";
+ else mirr = "";
+ if (Tspin) spin = "S";
+ else spin = "";
+ sprintf(h, "Text '%s' %s%sR%.1f (%5.3f %5.3f);\n", check_single_quote(Ename), spin, mirr, Tangle, u2mil(Tx), u2mil(Ty));
+ cmd += h;
+ return;
+}
+
+
+
+if (board) {
+ board(B) {
+ B.layers(L) {
+ used_name_[L.number] = L.name;
+ }
+ header();
+ B.elements(E) { // smashed texts
+ E.texts(T) {
+ if (T.value == E.name) {
+ used_name_layers[T.layer]++;
+ Text(E.name, T.layer, T.x, T.y, T.size, T.angle, T.ratio, T.mirror, T.spin);
+ }
+ }
+ E.package.texts(T) { // unsmashed texts
+ if (T.value == E.name) {
+ used_name_layers[T.layer]++;
+ Text(E.name, T.layer, T.x, T.y, T.size, T.angle, T.ratio, T.mirror, T.spin);
+ }
+ }
+ }
+ }
+ // test();
+
+ cmd += "SET UNDO_LOG ON;\nGRID LAST;\n";
+ header();
+ cmd_header += cmd;
+ cmd = cmd_header;
+
+ // EditBox
+ int Result = dlgDialog("Descriptions") {
+ dlgHBoxLayout {
+ dlgVBoxLayout { dlgSpacing(500); }
+ dlgTextEdit(cmd);
+ }
+ dlgHBoxLayout {
+ dlgPushButton("+Execute") dlgAccept();
+ dlgSpacing(100);
+ dlgPushButton("-Cancel") dlgReject();
+ }
+ };
+ if (Result == 0) exit(0);
+ exit(cmd);
+}
+
+else {
+ dlgMessageBox("\n Start this ULP in a Board \n");
+ exit (0);
+}
diff --git a/trunk/ulp/part2html.ulp b/trunk/ulp/part2html.ulp
new file mode 100644
index 00000000..f7fe8a9c
--- /dev/null
+++ b/trunk/ulp/part2html.ulp
@@ -0,0 +1,58 @@
+#usage "Export an HTML partlist\n"
+ "
"
+ "Generates an HTML file of a board's partlist for publishing on an intranet."
+ "
"
+ "Author: Sean D. Alcorn (SYD) Extended by support@cadsoft.de"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+if (board) board(B) {
+ string fileName = dlgFileSave("Save File", filesetext(B.name, ".htm"), "*.htm");
+ if (fileName == "") exit(0);
+ output(fileName) {
+ printf("\n\n");
+ printf("
Copyright 2004-2013 by"
+ " John Johnson Software, LLC.
"
+ "
All Rights Reserved
"
+ "
Version 3.6.0.4
"
+ "
"
+ "
You have EAGLE version " + m_eagle_compatibility + "
"
+ "
");
+ if (program_is_setup()) {
+ dlgLabel("
Your current profile is based on the "
+ + CURRENT_PROFILE[DESCRIPTION] + " profile.
");
+ dlgLabel("
Please use the settings under the tabs to"
+ " customize the gcode that is generated for you.
");
+ }
+ else {
+ dlgLabel("
Welcome!
"
+ "
Since this is the first time you have run this setup"
+ " program, please select the profile that best suits your machine."
+ " Click the Accept button to save your changes.
");
+ }
+// dlgLabel("");
+ }
+
+
+ dlgTabWidget {
+
+ /***************************************************************
+ *
+ * G E N E R A T I O N O P T I O N S
+ *
+ ***************************************************************/
+
+ if (program_is_setup()) dlgTabPage("Generation Options") {
+ dlgHBoxLayout {
+ dlgStretch(20);
+ dlgVBoxLayout {
+ dlgGroup("Top Side") {
+ dlgCheckBox("Generate top outlines", GENERATE_TOP_OUTLINES);
+ dlgCheckBox("Generate top drills ", GENERATE_TOP_DRILL);
+ }
+ dlgStretch(1);
+ }
+ dlgVBoxLayout {
+ dlgGroup("Bottom Side") {
+ dlgCheckBox("Generate bottom outlines",
+ GENERATE_BOTTOM_OUTLINES);
+ dlgCheckBox("Generate bottom drills ",
+ GENERATE_BOTTOM_DRILL);
+ dlgCheckBox("Mirror ",
+ MIRROR_BOTTOM);
+ }
+ dlgStretch(1);
+ dlgLabel("");
+ dlgStretch(3);
+ }
+ dlgVBoxLayout {
+ dlgGroup("Board") {
+ dlgVBoxLayout {
+ dlgCheckBox("Show preview ", SHOW_PREVIEW);
+ dlgGridLayout {
+ dlgCell(0, 0) dlgCheckBox("Generate milling", GENERATE_MILLING);
+ dlgCell(0, 1) dlgLabel("Depth ");
+ dlgCell(0, 2) { dlgRealEdit(MILLING_DEPTH); dlgLabel(m_uom_suffix, YES); }
+
+ dlgCell(1, 0) dlgCheckBox("Generate text", GENERATE_TEXT);
+ dlgCell(1, 1) dlgLabel("Depth ");
+ dlgCell(1, 2) { dlgRealEdit(TEXT_DEPTH); dlgLabel(m_uom_suffix, YES); }
+ dlgCell(2, 0) dlgCheckBox("Spot drill holes", SPOT_DRILL);
+ dlgCell(2, 1) dlgLabel("Depth");
+ dlgCell(2, 2) { dlgRealEdit(SPOT_DRILL_DEPTH); dlgLabel(m_uom_suffix, YES); }
+ }
+ dlgGridLayout {
+ dlgCell(0, 0, 0, 1) dlgLabel("Isolation");
+ dlgCell(0, 1) {
+ dlgCheckBox("Single pass", SINGLE_PASS) {
+ if (SINGLE_PASS) {
+/* dlgMessageBox("You have selected the single pass option.\n" +
+ "The next time you run pcb-gcode-setup, the Maximum and Step Size " +
+ "options will be hidden. Only Minimum will be shown.\n" +
+ "To change back, just turn Single pass off, " +
+ "click Accept, and run pcb-gcode-setup again.\n" +
+ "The minimum, maximum, and step size options will be available again.");
+ */
+ m_maximum_label = "not used";
+ m_step_size_label = "not used";
+ }
+ else {
+ m_maximum_label = "Maximum";
+ m_step_size_label = "Step size";
+ }
+ }
+ }
+ dlgCell(1, 0) dlgLabel("Minimum");
+ dlgCell(1, 1) { dlgRealEdit(ISO_MIN);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(3, 0) dlgLabel(m_maximum_label, YES);
+ dlgCell(3, 1) { dlgRealEdit(ISO_MAX);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(4, 0) dlgLabel(m_step_size_label, YES);
+ dlgCell(4, 1) { dlgRealEdit(ISO_STEP);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ }
+ dlgSpacing(10);
+ dlgVBoxLayout {
+ dlgLabel("Etching Tool Size ");
+ dlgHBoxLayout { dlgRealEdit(DEFAULT_WIDTH);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ }
+ }
+ }
+ dlgStretch(1);
+ }
+ dlgStretch(20);
+ }
+ dlgHBoxLayout {
+ }
+ }
+
+ /***************************************************************
+ *
+ * M A C H I N E
+ *
+ ***************************************************************/
+ if (program_is_setup()) dlgTabPage("Machine") {
+ dlgHBoxLayout {
+ dlgStretch(20);
+ dlgLabel("");
+ dlgGroup("Z Axis") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Z High ");
+ dlgCell(1, 1) {
+ dlgRealEdit(DEFAULT_Z_HIGH);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(2, 0) dlgLabel("Z Up ");
+ dlgCell(2, 1) {
+ dlgRealEdit(DEFAULT_Z_UP);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(3, 0) dlgLabel("Z Down ");
+ dlgCell(3, 1) {
+ dlgRealEdit(DEFAULT_Z_DOWN);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(4, 0) dlgLabel("Drill Depth ");
+ dlgCell(4, 1) {
+ dlgRealEdit(DRILL_DEPTH);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(5, 0) dlgLabel("Drill Dwell ");
+ dlgCell(5, 1) dlgRealEdit(DRILL_DWELL, 0); // DO NOT CONVERT
+ }
+ }
+ dlgGroup("Tool Change") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Position X ");
+ dlgCell(1, 1) { dlgRealEdit(TOOL_CHANGE_POS_X);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(2, 0) dlgLabel("Position Y ");
+ dlgCell(2, 1) { dlgRealEdit(TOOL_CHANGE_POS_Y);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(3, 0) dlgLabel("Position Z ");
+ dlgCell(3, 1) { dlgRealEdit(TOOL_CHANGE_POS_Z);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ }
+ }
+ dlgStretch(20);
+ }
+ dlgHBoxLayout {
+ dlgStretch(20);
+ dlgGroup("Units") {
+ dlgRadioButton("Microns", OUTPUT_UNITS) {
+ convert_units(U_MICRONS);
+ }
+ dlgRadioButton("Millimeters", OUTPUT_UNITS) {
+ convert_units(U_MILLIMETERS);
+ }
+ dlgRadioButton("Mils", OUTPUT_UNITS) {
+ convert_units(U_MILS);
+ }
+ dlgRadioButton("Inches", OUTPUT_UNITS) {
+ convert_units(U_INCHES);
+ }
+ }
+ dlgGroup("Spindle") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Spin Up Time ");
+ dlgCell(1, 1) dlgRealEdit(SPINDLE_ON_TIME); // DO NOT CONVERT
+ }
+ }
+ dlgGroup("Feed Rates") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("X Y ");
+ dlgCell(1, 1) { dlgRealEdit(FEED_RATE);
+ dlgLabel(m_uom_suffix, YES); dlgLabel("/min");
+ }
+ dlgCell(2, 0) dlgLabel("Z ");
+ dlgCell(2, 1) { dlgRealEdit(FEED_RATE_Z);
+ dlgLabel(m_uom_suffix, YES); dlgLabel("/min");
+ }
+ }
+ }
+ dlgGroup("Misc") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Epsilon");
+ dlgCell(1, 1) { dlgRealEdit(EPSILON);
+ dlgLabel(m_uom_suffix, YES);
+ dlgPushButton("?") {
+ dlgMessageBox("If an X or Y move is less than this amount, do not "
+ "put a move in the g-code file. For instance, if one point is "
+ "only 0.00001\" away from another point, there is no need to "
+ "write the move to the g-code file, since the machine will not "
+ "move anyway. This helps make the g-code file smaller, and run faster.");
+ }
+ }
+ dlgCell(2, 0) dlgLabel("Default Drill Rack File");
+ dlgCell(2, 1) dlgStringEdit(DEFAULT_DRILL_FILE);
+ dlgCell(2, 2) {
+ dlgPushButton("...") {
+ DEFAULT_DRILL_FILE = dlgFileOpen("Find default drill rack file",
+ g_path + "/settings",
+ "Drill files (*.drl);;All files (*.*)");
+ }
+ dlgPushButton("?") {
+ dlgMessageBox(
+ "Please see docs/readme.html for full details. "
+ "pcb-gcode will look for (in order): "
+ "board.drl "
+ "The file you select here. "
+ "path_to_pcbgcode/settings/default.drl "
+ "If this setting is blank, and it does not find a file, "
+ "it will assume you do not want to use a rack file. "
+ "If this setting is not blank, and it cannot find one of the "
+ "files listed above, it will give you an error message."
+ );
+ }
+ }
+ }
+ }
+ dlgStretch(20);
+ }
+ }
+
+ /***************************************************************
+ *
+ * G C O D E S T Y L E
+ *
+ ***************************************************************/
+ dlgTabPage("GCode Style") {
+ dlgLabel("Please select your style of gcode below.");
+ dlgLabel("If you make changes to gcode-defaults.h to "
+ "work with your machine,");
+ dlgLabel(
+ "Please email the file to "
+ "pcbgcode@pcbgcode.org for possible inclusion "
+ "in the next release.");
+ dlgListView("File\tAuthor\tDescription",
+ pp_auth_desc, pp_selection);
+ }
+
+ /***************************************************************
+ *
+ * G C O D E O P T I O N S
+ *
+ ***************************************************************/
+ if (program_is_setup()) dlgTabPage("GCode Options") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgGroup("NC File Comments") {
+ dlgCheckBox("NC File Comment from Board",
+ NC_FILE_COMMENT_FROM_BOARD);
+ dlgCheckBox("Nc File Comment Date",
+ NC_FILE_COMMENT_DATE);
+ dlgCheckBox("Nc File Comment Machine Settings",
+ NC_FILE_COMMENT_MACHINE_SETTINGS);
+ dlgCheckBox("Nc File Comment Pcb Defaults Settings",
+ NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS);
+ }
+// dlgStretch(1);
+ }
+ dlgGroup("Other Options") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgCheckBox("Use user gcode (from user-gcode.h)", USER_GCODE);
+ dlgCheckBox("Debug Flag", g_debug_flag);
+ dlgCheckBox("Do tool change with zero step", DO_TOOL_CHANGE_WITH_ZERO_STEP);
+ dlgCheckBox("Flip board in Y instead of X", FLIP_BOARD_IN_Y);
+ }
+ dlgVBoxLayout {
+ dlgCheckBox("Compact gcode", COMPACT_GCODE);
+ dlgHBoxLayout {
+ dlgCheckBox("Use line numbers?", USE_LINE_NUMBERS);
+ dlgLabel(" Format "); dlgStringEdit(LINE_NUMBER_FORMAT);
+ }
+ dlgCheckBox("Use simple drill code ",
+ SIMPLE_DRILL_CODE);
+ }
+ }
+ // dlgStretch(1);
+ }
+ }
+ dlgHBoxLayout {
+ dlgGroup("File Naming") {
+ dlgGridLayout {
+ dlgCell(0, 0, 0, 1) {
+ dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE);
+ }
+ dlgCell(0, 2) {
+ dlgLabel("Extension "); dlgStringEdit(DEFAULT_EXTENSION);
+ dlgStretch(1);
+ }
+ dlgCell(2, 0) { dlgLabel("Word for 'etch'");
+ dlgStringEdit(ETCH_FILE_NAME);
+ }
+ dlgCell(2, 1) { dlgLabel("Word for 'drill'");
+ dlgStringEdit(DRILL_FILE_NAME);
+ }
+ dlgCell(2, 2) { dlgLabel("Word for 'mill'");
+ dlgStringEdit(MILL_FILE_NAME);
+ }
+ dlgCell(2, 3) { dlgLabel("Word for 'text'");
+ dlgStringEdit(TEXT_FILE_NAME); dlgStretch(1);
+ }
+ dlgCell(3, 0) { dlgLabel("Word for 'top'");
+ dlgStringEdit(TOP_FILE_NAME);
+ }
+ dlgCell(3, 1) { dlgLabel("Word for 'bottom'");
+ dlgStringEdit(BOT_FILE_NAME);
+ }
+ }
+ dlgHBoxLayout {
+ dlgGroup("Top (Component) Side Files") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Etching ");
+ dlgCell(1, 1) { dlgStringEdit(FILENAME_TOP_ETCH_FILE); }
+ dlgCell(2, 0) dlgLabel("Drill ");
+ dlgCell(2, 1) { dlgStringEdit(FILENAME_TOP_DRILL_FILE); }
+ dlgCell(3, 0) dlgLabel("Mill ");
+ dlgCell(3, 1) { dlgStringEdit(FILENAME_TOP_MILL_FILE); }
+ dlgCell(4, 0) dlgLabel("Text ");
+ dlgCell(4, 1) { dlgStringEdit(FILENAME_TOP_TEXT_FILE); }
+ }
+ }
+ dlgGroup("Bottom (Solder) Side Files") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Etching ");
+ dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE);
+ dlgCell(2, 0) dlgLabel("Drill ");
+ dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE);
+ dlgCell(3, 0) dlgLabel("Mill ");
+ dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE);
+ dlgCell(4, 0) dlgLabel("Text ");
+ dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_TEXT_FILE);
+ }
+ }
+// dlgStretch(1);
+ dlgVBoxLayout {
+ dlgPushButton("Test Filenames") {
+ FILENAME_TOP_ETCH_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_ETCH_FILE,
+ TOP, PH_TOP_OUT_WRITE);
+ FILENAME_TOP_DRILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_DRILL_FILE,
+ TOP, PH_TOP_DRILL);
+ FILENAME_TOP_MILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_MILL_FILE,
+ TOP, PH_MILL);
+ FILENAME_TOP_TEXT_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_TEXT_FILE,
+ TOP, PH_TEXT);
+ FILENAME_BOT_ETCH_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_ETCH_FILE,
+ BOTTOM, PH_BOTTOM_OUT_WRITE);
+ FILENAME_BOT_DRILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_DRILL_FILE,
+ BOTTOM, PH_BOTTOM_DRILL);
+ FILENAME_BOT_MILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_MILL_FILE,
+ BOTTOM, PH_MILL);
+ FILENAME_BOT_TEXT_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_TEXT_FILE,
+ BOTTOM, PH_TEXT);
+ FILENAME_TOP_ETCH_FILE_SAMPLE = substitute(
+ FILENAME_TOP_ETCH_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_TOP_DRILL_FILE_SAMPLE = substitute(
+ FILENAME_TOP_DRILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_TOP_MILL_FILE_SAMPLE = substitute(
+ FILENAME_TOP_MILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_TOP_TEXT_FILE_SAMPLE = substitute(
+ FILENAME_TOP_TEXT_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_ETCH_FILE_SAMPLE = substitute(
+ FILENAME_BOT_ETCH_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_DRILL_FILE_SAMPLE = substitute(
+ FILENAME_BOT_DRILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_MILL_FILE_SAMPLE = substitute(
+ FILENAME_BOT_MILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_TEXT_FILE_SAMPLE = substitute(
+ FILENAME_BOT_TEXT_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ temp_str = ";Test Filenames\n"
+ "Spaces in file paths have been "
+ "replaced with underscores _ to keep "
+ "the lines from wrapping.\n"
+ "Top:\n"
+ "Etch:\t" + FILENAME_TOP_ETCH_FILE_SAMPLE + "\n" +
+ "Drill:\t" + FILENAME_TOP_DRILL_FILE_SAMPLE + "\n" +
+ "Mill:\t" + FILENAME_TOP_MILL_FILE_SAMPLE + "\n" +
+ "Text:\t" + FILENAME_TOP_TEXT_FILE_SAMPLE + "\n" +
+ "\nBottom:\n"
+ "Etch:\t" + FILENAME_BOT_ETCH_FILE_SAMPLE + "\n" +
+ "Drill:\t" + FILENAME_BOT_DRILL_FILE_SAMPLE + "\n" +
+ "Mill:\t" + FILENAME_BOT_MILL_FILE_SAMPLE + "\n" +
+ "Text:\t" + FILENAME_BOT_TEXT_FILE_SAMPLE + "\n";
+ dlgMessageBox(temp_str);
+ }
+ dlgPushButton("Help") {
+ dlgMessageBox(filename_subs_help());
+ }
+// dlgStretch(1);
+ }
+ }
+ }
+ }
+
+ }
+ if (program_is_setup()) dlgTabPage("Plugins") {
+ #include "plugins/plugin_loader.h"
+ }
+
+ /***************************************************************
+ *
+ * O T H E R
+ *
+ ***************************************************************/
+ if (program_is_setup()) dlgTabPage("Other") {
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgVBoxLayout {
+ dlgStretch(1);
+ dlgGroup("Miscellaneous") {
+ dlgGridLayout {
+ dlgCell(0, 0, 0, 5) {
+ dlgLabel("All misc. options are deprecated.");
+ }
+ }
+ }
+ dlgPushButton("Reset to Factory Defaults") {
+ if (dlgMessageBox(
+ "This is going to change the following files"
+ " back to their default contents, erasing any changes"
+ " you may have made to them:
"
+ "
"
+ "
pcb-defaults.h
pcb-gcode-options.h
"
+ "
pcb-machine.h
user-gcode.h
"
+ "
"
+ "Is that something you want to do?
"
+ "If you aren't sure, click No.
",
+ "-Yes", "+No") == 0 /*Yes*/) {
+ restore_file_defaults();
+ exit("run pcb-gcode-setup");
+ }
+ }
+ dlgStretch(1);
+ }
+ dlgStretch(1);
+ }
+ }
+ }
+
+ dlgHBoxLayout {
+ dlgStretch(5);
+ dlgPushButton("+&Accept") dlgAccept();
+ if (program_is_setup()) {
+ dlgPushButton("Accept and make my &board") dlgAccept(2);
+ }
+ dlgPushButton("-Cancel") {
+ if (dlgMessageBox("Cancel your changes.
"
+ "Are you sure?", "Yes", "No") == 0) dlgReject();
+ }
+ }
+};
+
+// Accept Accept and make board
+if (Result == 1 || Result == 2) {
+
+ fileerror();
+ output(g_path + "/settings/pcb-defaults.h", "wt") {
+
+ int now = time();
+
+ printf(
+ "//\n// Default values for generating gcode from a PCB.\n//\n");
+ printf("// These settings were last changed with "
+ "pcb-gcode-setup: %s\n//\n", t2string(now));
+ printf("//\n// Changes you make in this file will be overwritten "
+ "if you use pcb-gcode-setup.\n//\n\n");
+
+ write_bool_param("SINGLE_PASS", SINGLE_PASS);
+ write_real_param("ISO_MIN", ISO_MIN);
+ write_real_param("ISO_MAX", ISO_MAX);
+ write_real_param("ISO_STEP", ISO_STEP);
+ printf("\n");
+
+ write_bool_param("GENERATE_TOP_OUTLINES", GENERATE_TOP_OUTLINES);
+ write_bool_param("GENERATE_TOP_DRILL", GENERATE_TOP_DRILL);
+ write_bool_param("GENERATE_TOP_FILL", GENERATE_TOP_FILL);
+ printf("\n");
+
+ write_bool_param("GENERATE_BOTTOM_OUTLINES",
+ GENERATE_BOTTOM_OUTLINES);
+ write_bool_param("GENERATE_BOTTOM_DRILL", GENERATE_BOTTOM_DRILL);
+ write_bool_param("GENERATE_BOTTOM_FILL", GENERATE_BOTTOM_FILL);
+ write_bool_param("MIRROR_BOTTOM",
+ MIRROR_BOTTOM);
+ write_bool_param("SIMPLE_DRILL_CODE", SIMPLE_DRILL_CODE);
+
+ printf("\n");
+
+ write_bool_param("GENERATE_MILLING", GENERATE_MILLING);
+ printf("\n");
+
+ write_bool_param("GENERATE_TEXT", GENERATE_TEXT);
+ printf("\n");
+
+ write_bool_param("SPOT_DRILL", SPOT_DRILL);
+ write_real_param("SPOT_DRILL_DEPTH", SPOT_DRILL_DEPTH);
+ printf("\n");
+
+ write_bool_param("DO_TOOL_CHANGE_WITH_ZERO_STEP",
+ DO_TOOL_CHANGE_WITH_ZERO_STEP);
+ printf("\n");
+
+ write_bool_param("FLIP_BOARD_IN_Y", FLIP_BOARD_IN_Y);
+ printf("\n");
+
+ // Place a // in front of units not being used
+ if (OUTPUT_UNITS != U_MICRONS) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_MICRONS");
+ if (OUTPUT_UNITS != U_MILLIMETERS) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_MILLIMETERS");
+ if (OUTPUT_UNITS != U_MILS) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_MILS");
+ if (OUTPUT_UNITS != U_INCHES) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_INCHES");
+ }
+ if(fileerror())
+ exit(1);
+
+ if(pp_selection > -1) {
+ if (dlgMessageBox(
+ "If you have made manual changes to gcode-defaults.h, they"
+ " will be overwritten by your new gcode style selection.
"
+ "This program generates g-code for 'mechanically etching' PC boards. "
+ "Using a CNC router or milling machine, you can make PC boards without using etching chemicals."
+ "It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board."
+ " See the readme.html file for more info.
"
+ "There are many options in the setup program. "
+ "To setup which files are generated, and how, use the following command: "
+ "run pcb-gcode --setup
"
+ "
"
+ "If you want to produce a set of files without changing options, you can run pcb-gcode directly."
+ "Usage is as follows: "
+ "run pcb-gcode [option] [file] "
+ "Where:\n"
+ "
"
+ "
Option
Function
"
+ "
--help
Show this help screen
"
+ "
--setup
Run the setup / configuration program
"
+ "
file
Is the optional root filename.\n
"
+ "
If not given, the board name is used as the root filename.
"
+ "
"
+ ""
+ ""
+ ""
+
+g_width = DEFAULT_WIDTH;
+
+// Filename to output to.
+string m_file_name = "";
+
+// Which side we're currently working on.
+g_side = TOP;
+
+// Tool currently being used.
+int m_current_tool = 0;
+
+// Amount to isolate traces.
+real m_isolate = 0.0;
+
+// Used to pass the pass info to the next pass of the program.
+int m_pass_num;
+
+// The layer being worked on.
+int m_layer;
+
+// Used to create command strings.
+string g_cmd;
+string g_cmd_temp;
+
+// Save the maximum and minimum coordinates.
+real m_max_x;
+real m_max_y;
+real m_min_x;
+real m_min_y;
+void save_extents(real x, real y)
+{
+ m_max_x = max(m_max_x, x);
+ m_max_y = max(m_max_y, y);
+ m_min_x = min(m_min_x, x);
+ m_min_y = min(m_min_y, y);
+}
+
+void preview()
+{
+ if (SHOW_PREVIEW) {
+ switch(get_os()) {
+ case OS_MACOSX:
+ system(g_path + "/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub");
+ break;
+ case OS_LINUX:
+ system(g_path + "/source/viewer.linux.sh");
+ break;
+ case OS_WINDOWS:
+ system(g_path + "/viewer/application.windows/viewer.exe");
+ dlgMessageBox("Close this window when you have finished with the preview");
+ break;
+ default:
+ Fatal("Oops!", "Can't figure out which OS you have.");
+ }
+ }
+}
+//
+// Determine the next phase, and set g_phase accordingly.
+//
+// Params: none
+// Return: none
+//
+void next_phase(void)
+{
+ if (g_phase == PH_TOP_OUT_GEN && GENERATE_TOP_OUTLINES != YES) {
+ g_phase += 2;
+ return;
+ }
+ if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) {
+ g_phase += 2;
+ return;
+ }
+
+ if (g_phase == PH_TOP_OUT_WRITE || g_phase == PH_BOTTOM_OUT_WRITE) {
+ if (m_isolate < ISO_MAX && !SINGLE_PASS) {
+ m_isolate += ISO_STEP;
+ m_pass_num++;
+ g_phase--;
+ }
+ else {
+ m_isolate = ISO_MIN;
+ m_pass_num = 0;
+ g_phase++;
+
+ preview();
+ }
+ }
+ else {
+ g_phase++;
+ }
+}
+
+//////////////////////////////////////////////////
+//
+// Hole drilling routines.
+//
+//////////////////////////////////////////////////
+
+//
+// Add a hole drilling command to the command string.
+//
+// Params:
+// Size Drill size.
+// x x coordinate.
+// y y coordinate.
+// Returns:
+// none
+// Changes:
+// the stack
+//
+void add_hole(int req_size, int x, int y)
+{
+ string tempstr;
+ int drill_size;
+
+ drill_size = get_drill_for(req_size);
+
+ sprintf(tempstr, "%06d\t%06d\t%06d", drill_size, x, y);
+ stack_push(tempstr);
+}
+
+/*
+ * Create a drill file for the desired side.
+ *
+ * Params:
+ * which_side Side to produce the file for.
+ * suffix Suffix to use for the file name (i.e. bd).
+ * Returns:
+ * none
+ * Changes:
+ * side
+*/
+void drill(int which_side, string suffix)
+{
+ int num_lines;
+ int i;
+ real last_size;
+ string drill_args[];
+ m_current_tool = 0;
+ real drill_size_mm;
+ real drill_size_inch;
+ real drill_size;
+ real drill_x;
+ real drill_y;
+ int drill_tool_num;
+
+ g_side = which_side;
+
+ //
+ // Build a stack with all the holes.
+ //
+ board(B) {
+ B.holes(H) add_hole(H.drill, H.x, H.y);
+ B.signals(S) S.vias(V) add_hole(V.drill, V.x, V.y);
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ add_hole(C.pad.drill, C.pad.x, C.pad.y);
+ }
+ }
+ E.package.holes(H) add_hole(H.drill, H.x, H.y);
+ }
+ // B.elements
+
+ // Sorts the drills by size, x and y.
+ stack_sort();
+
+ //
+ // Create the drill g-code file.
+ //
+ last_size = -1;
+ output(get_filename(), "wt") {
+ output_file_preamble();
+
+ //
+ // Create a tool table at the beginning of the file.
+ //
+ out(TOOL_CHANGE_TABLE_HEADER);
+ for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
+ if (i==END_OF_STACK) break;
+ strsplit(drill_args, stack_elem(i), '\t');
+ drill_size_inch = u2inch(my_strtol(drill_args[DRILL_SIZE]));
+ drill_size_mm = u2mm(my_strtol(drill_args[DRILL_SIZE]));
+ drill_size = my_strtol(drill_args[DRILL_SIZE]);
+
+ if (drill_size != last_size) {
+ ++m_current_tool;
+ drill_tool_num = get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool);
+ out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num,
+ drill_size_mm, drill_size_inch,
+ g_mins[drill_tool_num], g_maxs[drill_tool_num],
+ g_drill_sub_cnt[drill_tool_num]));
+ }
+ last_size = drill_size;
+ }
+ // for
+
+ // Set the mode for the user's UOM.
+ out(get_mode());
+ out(ABSOLUTE_MODE);
+
+ //
+ // Generate drill code.
+ //
+ m_current_tool = 0;
+ for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
+ strsplit(drill_args, stack_elem(i), '\t');
+ drill_size = units(my_strtol(drill_args[DRILL_SIZE]));
+ drill_x = scale_x(my_strtol(drill_args[DRILL_X]));
+ drill_y = scale_y(my_strtol(drill_args[DRILL_Y]));
+ save_extents(drill_x, drill_y);
+
+ if (drill_size == last_size) {
+ output_drill_hole(drill_x, drill_y, DRILL_DEPTH);
+ }
+ else {
+ m_current_tool++;
+ // Tool change routine
+ output_tool_change_begin();
+ out(SPINDLE_OFF);
+ rz(TOOL_CHANGE_POS_Z);
+ rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y);
+ out(fir(TOOL_CHANGE, get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool), drill_size));
+ output_tool_changed();
+
+ if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) {
+ output_tool_zero_begin();
+ fzr(0.000, FEED_RATE_Z);
+ // fixme: wondering about the following line
+ out(fir(TOOL_CHANGE, m_current_tool, drill_size));
+ output_tool_zero_end();
+ }
+
+ rz(DEFAULT_Z_UP);
+ out(fr(SPINDLE_ON, SPINDLE_ON_TIME));
+ output_tool_change_end();
+
+ output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH);
+ last_size = drill_size;
+ }
+ // if drill_size != last_size
+ }
+ // for
+
+ output_file_postamble();
+
+ // End of file
+ // change back to tool 1
+ out(fi(TOOL_CODE + EOL, 1));
+ end_gcode();
+ }
+ // output
+ }
+ // Board
+}
+// drill
+
+int m_first_spot_drill = YES;
+void spot_drill_hole(int x, int y)
+{
+ real drill_x;
+ real drill_y;
+
+ drill_x = scale_x(x);
+ drill_y = scale_y(y);
+ save_extents(drill_x, drill_y);
+
+ if (m_first_spot_drill) {
+ output_drill_first_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
+ m_first_spot_drill = NO;
+ }
+ else {
+ output_drill_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
+ }
+}
+
+void spot_drill(UL_BOARD B)
+{
+ if (SPOT_DRILL == NO) { return; }
+
+ B.holes(H) spot_drill_hole(H.x, H.y);
+ B.signals(S) S.vias(V) spot_drill_hole(V.x, V.y);
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ spot_drill_hole(C.pad.x, C.pad.y);
+ }
+ }
+ E.package.holes(H) spot_drill_hole(H.x, H.y);
+ }
+ // B.elements
+}
+
+string m_lines;
+string LINE_SEP = "\n";
+string COORD_SEP = ",";
+string COORD_FMT = "%8.5f";
+
+string coords(real x1, real y1, real x2, real y2)
+{
+ return frrrr(COORD_FMT + COORD_SEP + COORD_FMT + COORD_SEP +
+ COORD_FMT + COORD_SEP + COORD_FMT + LINE_SEP, x1, y1, x2, y2);
+}
+
+//
+// "Draw" on the output device, i.e. the gcode file.
+//
+// Params:
+// x1,y1 Start of the line.
+// x2,y2 End of the line.
+// state
+// z_down
+// Returns:
+// none
+//
+real m_arc_begin_x;
+real m_arc_begin_y;
+int pair_count = 0;
+int MAX_COORDS_PER_LINE = 4;
+void device_draw(int x1, int y1, int x2, int y2, int state, real z_down)
+{
+ real rx1, ry1, rx2, ry2;
+
+ rx1 = scale_x(x1);
+ ry1 = scale_y(y1);
+ rx2 = scale_x(x2);
+ ry2 = scale_y(y2);
+ save_extents(rx1, ry1);
+ save_extents(rx2, ry2);
+
+ // Output g-code based on the current state.
+ switch(state) {
+
+ // Start of a new line.
+ case ST_START_LINE:
+ user_track_begin(rx1, ry1, rx2, ry2);
+
+ m_lines += coords(rx1, ry1, rx2, ry2);
+
+ rz(DEFAULT_Z_UP);
+ rxy(rx1, ry1);
+ fzr(z_down, FEED_RATE_Z);
+ fxyr(rx2, ry2, FEED_RATE);
+ pair_count = 0;
+ break;
+
+ // A fill line.
+ case ST_FILL:
+ Fatal("Programmer Error", "The Fill functions are no longer supported.");
+ break;
+
+ // Continue a line.
+ // End a line.
+ case ST_CONTINUE_LINE:
+ user_track_continue(rx1, ry1, rx2, ry2);
+
+ m_lines += coords(rx1, ry1, rx2, ry2);
+
+ if (COMPACT_GCODE == YES) {
+ if (pair_count == 0) {
+ fxy(rx2, ry2);
+ }
+ else {
+ xy(rx2, ry2);
+ }
+ pair_count++;
+ }
+ else {
+ fxy(rx2, ry2);
+ }
+ break;
+
+ case ST_END_LINE:
+ user_track_end(rx1, ry1, rx2, ry2);
+
+ m_lines += coords(rx1, ry1, rx2, ry2);
+
+
+ if (COMPACT_GCODE == YES) {
+ xy(rx2, ry2);
+ pair_count = 0;
+ }
+ else {
+ fxy(rx2, ry2);
+ }
+ break;
+
+ // Drill a hole.
+ // todo is this valid?
+ case ST_DRILL:
+ printf("cause an error if used %d");
+ // printf("drill (%f, %f)\n", rx2, ry2);
+ break;
+
+ // Create an arc.
+ case ST_ARC_BEGIN:
+ user_arc_begin(rx1, ry1, rx2, ry2);
+ m_arc_begin_x = rx1;
+ m_arc_begin_y = ry1;
+ break;
+
+ // Finish an arc.
+ case ST_ARC_END:
+ user_arc_end(rx1, ry1, rx2, ry2);
+ real cx = rx2;
+ real cy = ry2;
+ real end_x = rx1;
+ real end_y = ry1;
+
+ if (1 /* USE_IJ_RELATIVE */) {
+ cx = rx2 - rx1;
+ cy = ry2 - ry1;
+ }
+
+ rz(DEFAULT_Z_UP);
+ rxy(end_x, end_y);
+ fzr(z_down, FEED_RATE_Z);
+ if (g_side == TOP || MIRROR_BOTTOM == YES) {
+ out(frrrr(CIRCLE_TOP, m_arc_begin_x, m_arc_begin_y, cx, cy));
+ }
+ else {
+ out(frrrr(CIRCLE_BOTTOM, m_arc_begin_x, m_arc_begin_y, cx, cy));
+ }
+ break;
+
+ }
+ // switch(state)
+}
+// device_draw
+
+
+//
+// Generate polygons for outline or fill.
+// This creates a series of commands for Eagle and puts them
+// in g_cmd to be passed when we exit from this phase of pcb-gcode.
+//
+// Params:
+// which_side The side to operate on.
+// Return:
+// none
+//
+void generate_outlines(int which_side)
+{
+ string cmd_temp = "";
+
+ g_cmd = "";
+
+ if (which_side == TOP)
+ m_layer = TOP_LAYER;
+ else
+ m_layer = BOTTOM_LAYER;
+
+ board(B) {
+ real f = BORDER_SIZE;
+ real x1 = units(B.area.x1) - f;
+ real y1 = units(B.area.y1) - f;
+ real x2 = units(B.area.x2) + f;
+ real y2 = units(B.area.y2) + f;
+
+ B.signals(S) {
+ if (S.name == OUTLINES_SIGNAL_NAME) {
+ sprintf(cmd_temp, "delete (%f %f) (%f %f);\n",
+ x1, y1, x2, y2);
+ g_cmd = g_cmd + cmd_temp;
+ }
+ }
+
+ sprintf(cmd_temp, "grid %s;\n"
+ "change isolate %f;\n"
+ "change rank 6;\n"
+ "change pour solid;\n"
+ "change width %f;\n"
+ "change orphans on;\n"
+ "layer %d;\n"
+ "polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n"
+ "ratsnest;\n"
+ ,
+ UNIT_OF_MEASURE,
+ m_isolate,
+ g_width,
+ m_layer,
+ OUTLINES_SIGNAL_NAME, g_width,
+ x1, y1, x2, y1, x2, y2, x1, y2, x1, y1
+ );
+ g_cmd = g_cmd + cmd_temp;
+ return;
+ }
+ // board(B)
+}
+// generate_outlines
+
+void out_lines(string path, string mode)
+{
+ output(path, mode) {
+ if (m_pass_num == 0) {
+ printf("# board=%s\n", elided_path(get_filename(), 30));
+ printf("# tool size=%f\n", g_width);
+ }
+ printf("# pass=%d\n", m_pass_num + 1);
+ printf(m_lines);
+ }
+}
+
+//
+// Write text from the Milling layer to a text engraving file.
+//
+// Params:
+// file_name Output filename.
+// Return:
+// none
+//
+void output_text_code(string file_name)
+{
+ int state;
+ int old_x, old_y;
+
+ board(B) {
+ output(get_filename(), "wt") {
+ user_file_opened(get_filename(), "wt");
+
+ output_file_preamble();
+
+ // Initialize the device (i.e. the output file).
+ begin_gcode();
+
+ // Process all the wires.
+ B.texts(T) T.wires(W) {
+ if ((T.mirror && g_side == BOTTOM) || (! T.mirror && g_side == TOP)) {
+ // If this is a text layer, check if we should continue
+ // a line, or start a new one.
+ if (W.layer == TEXT_LAYER) {
+ if (W.x1 == old_x && W.y1 == old_y) {
+ state = ST_CONTINUE_LINE;
+ }
+ else {
+ state = ST_START_LINE;
+ }
+
+ // if this is an arc, it is treated specially.
+ if (W.arc) {
+ device_draw( W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, ST_ARC_BEGIN, TEXT_DEPTH);
+ device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH);
+ save_extents(W.x1, W.y1);
+ save_extents(W.x2, W.y2);
+ state = ST_START_LINE;
+ }
+ else {
+ // Draw the line (i.e. output the gcode for the line).
+ device_draw(W.x1, W.y1, W.x2, W.y2, state, TEXT_DEPTH);
+ old_x = W.x2;
+ old_y = W.y2;
+ save_extents(W.x1, W.y1);
+ save_extents(W.x2, W.y2);
+ }
+ // if (W.arc)
+ }
+ // if (W.layer == TEXT_LAYER)
+ }
+ // if (top and bottom check)
+ }
+ // T.wires
+ output_file_postamble();
+ end_gcode();
+ user_file_closing();
+ }
+ // output
+ user_file_closed(get_filename(), "wt");
+ }
+ // board
+ g_width = abs(TEXT_DEPTH);
+ out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
+
+ preview();
+
+ m_lines = "";
+}
+// output_text_code
+
+
+//
+// Write layer data to mill files.
+//
+// Params:
+// file_name Output filename.
+// Return:
+// none
+//
+void output_mill_code(string file_name)
+{
+ int state;
+ int old_x, old_y;
+
+ board(B) {
+ output(get_filename(), "wt") {
+ user_file_opened(get_filename(), "wt");
+
+ output_file_preamble();
+
+ // Initialize the device (i.e. the output file).
+ begin_gcode();
+
+ // Process all the wires.
+ B.wires(W) W.pieces(P) {
+ // If this is a mill layer, check if we should continue
+ // a line, or start a new one.
+ if (P.layer == MILL_LAYER) {
+ if (P.x1 == old_x && P.y1 == old_y) {
+ state = ST_CONTINUE_LINE;
+ }
+ else {
+ state = ST_START_LINE;
+ }
+
+ // if this is an arc, it is treated specially.
+ if (P.arc) {
+ device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, MILLING_DEPTH);
+ device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH);
+ save_extents(P.x1, P.y1);
+ save_extents(P.x2, P.y2);
+ state = ST_START_LINE;
+ }
+ else {
+ // Draw the line (i.e. output the gcode for the line).
+ device_draw(P.x1, P.y1, P.x2, P.y2, state, MILLING_DEPTH);
+ old_x = P.x2;
+ old_y = P.y2;
+ save_extents(P.x1, P.y1);
+ save_extents(P.x2, P.y2);
+ }
+ // if (P.arc)
+ }
+ // if (P.layer == MILL_LAYER)
+ }
+ // pieces
+ output_file_postamble();
+ end_gcode();
+ user_file_closing();
+ }
+ // output
+ user_file_closed(get_filename(), "wt");
+ }
+ // board
+
+ g_width = abs(MILLING_DEPTH);
+ out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
+
+ preview();
+
+ m_lines = "";
+}
+// output_mill_code
+
+
+//
+// Write polygon lines to the file.
+//
+// Params:
+// which_side Side of the board to work on.
+// suffix Suffix of the file.
+// task
+// Return:
+// none
+//
+void write_outlines(int which_side, string suffix, int task)
+{
+ string mode;
+ int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN;
+ int x0, y0;
+ int first = 1;
+ int frame_wire;
+ int state;
+
+ if (m_pass_num == 0) {
+ mode = "wt";
+ }
+ else {
+ mode = "at";
+ }
+ g_side = which_side;
+ switch (which_side) {
+ case TOP:
+ m_layer = TOP_LAYER;
+ break;
+ case BOTTOM:
+ m_layer = BOTTOM_LAYER;
+ break;
+ case MILL:
+ m_layer = MILL_LAYER;
+ break;
+ case TEXT:
+ m_layer = TEXT_LAYER;
+ break;
+ default:
+ sprintf(g_debug, "Illegal which_side %d in write_outlines", which_side);
+ Fatal("Sorry...", g_debug);
+ }
+
+ if (m_layer == MILL_LAYER || m_layer == TEXT_LAYER) {
+ if (which_side == MILL) {
+ g_side = TOP;
+ output_mill_code(m_file_name + "mt" + DEFAULT_EXTENSION);
+ g_side = BOTTOM;
+ output_mill_code(m_file_name + "mb" + DEFAULT_EXTENSION);
+ return;
+ }
+ else {
+ g_side = TOP;
+ output_text_code(m_file_name + "tt" + DEFAULT_EXTENSION);
+ g_side = BOTTOM;
+ output_text_code(m_file_name + "tb" + DEFAULT_EXTENSION);
+ return;
+ }
+ }
+ // if m_layer == MILL_LAYER
+
+ output(get_filename(), mode) {
+ board(B) {
+ user_file_opened(get_filename(), mode);
+
+ int rubout_layer = -1;
+ B.layers(L) {
+ if (strstr(strlwr(L.name), "rubout") != -1) {
+ if (strstr(strlwr(L.name), "top") != -1 && which_side == TOP) {
+ rubout_layer = L.number;
+ }
+ else if (strstr(strlwr(L.name), "bot") != -1 && which_side == BOTTOM) {
+ rubout_layer = L.number;
+ }
+ }
+ }
+
+ if (rubout_layer != -1) {
+ B.wires(W) {
+ if (W.layer == rubout_layer) {
+ device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
+ device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN); // fixme needed?
+ }
+ }
+ }
+
+ B.signals(S) {
+ if (S.name == OUTLINES_SIGNAL_NAME) {
+ S.polygons(P) {
+ P.wires(W) {
+ x1 = min(x1, W.x1);
+ x2 = max(x2, W.x1);
+ y1 = min(y1, W.y1);
+ y2 = max(y2, W.y1);
+ }
+ if (m_pass_num == 0) {
+ output_file_preamble();
+ begin_gcode();
+ }
+ else {
+ output_between_outline_passes();
+ }
+
+ switch (task) {
+ case TASK_OUTLINES:
+ // P.contours jtj
+ P.contours(W) {
+ if (first) {
+ x0 = W.x1;
+ y0 = W.y1;
+ frame_wire = (x0 == x1 || x0 == x2) && (y0 == y1 || y0 == y2);
+ state = ST_START_LINE;
+ first = 0;
+ }
+ else if (W.x2 == x0 && W.y2 == y0) {
+ state = ST_END_LINE;
+ first = 1;
+ }
+ else {
+ state = ST_CONTINUE_LINE;
+ }
+
+ if (!frame_wire) {
+ device_draw(W.x1, W.y1, W.x2, W.y2, state, DEFAULT_Z_DOWN);
+ }
+ }
+ // P.contours(W)
+ break;
+
+ case TASK_FILL:
+ P.fillings(W) {
+ device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
+ }
+ break;
+ }
+ // switch(task)
+
+ if (m_isolate >= ISO_MAX || SINGLE_PASS || task == TASK_FILL) {
+ output_file_postamble();
+ rz(DEFAULT_Z_UP);
+ spot_drill(B);
+ end_gcode();
+ }
+
+ sprintf(g_cmd, "delete (%f %f) (%f %f);\n",
+ units(x1), units(y1), units(x2), units(y2)
+ );
+ }
+ // polygons
+ }
+ // if(S.name == OUTLINES_SIGNAL_NAME)
+ }
+ // signals
+ }
+ // board
+ user_file_closing();
+ }
+ // output
+ user_file_closed(get_filename(), mode);
+ out_lines(g_path + "/viewer/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode);
+
+}
+// write_outlines
+
+/* string get_phase_name(int phase)
+{
+ return PHASE_NAME[phase];
+}
+ */
+void gen_progress_menu(int phase)
+{
+ output(path_scr[0] + '/' + "source/pcb-gcode-prg.scr") {
+ printf("MENU \\\n");
+ for(int i = 1; i < PH_LAST_PHASE; i++) {
+ if (i == phase) {
+ printf("--%s-- \\\n", get_phase_name(i));
+ // " (for TextMate)
+ }
+ else {
+ printf(" %s \\\n", get_phase_name(i));
+ }
+ }
+ printf(";\n");
+ }
+}
+
+// Make sure a board is available to work on.
+// todo move towards bottom
+if (!board) {
+ Fatal("No board!", "Please run this program from the board editor");
+}
+
+//
+// Process command line arguments.
+//
+switch (OUTPUT_UNITS) {
+ case U_MICRONS:
+ UNIT_OF_MEASURE = "mic";
+ break;
+ case U_MILLIMETERS:
+ UNIT_OF_MEASURE = "mm";
+ break;
+ case U_MILS:
+ UNIT_OF_MEASURE = "mil";
+ break;
+ case U_INCHES:
+ UNIT_OF_MEASURE = "inch";
+ break;
+}
+
+if (argv[FILENAME_ARG] == "--setup") {
+ exit("run pcb-gcode-setup");
+}
+
+if (argv[FILENAME_ARG] == "--attr") {
+ string attrs;
+ board(B) {
+ B.attributes(A) {
+ attrs = attrs + A.name + "\t" + A.value + "\n";
+ }
+ }
+ dlgMessageBox(attrs);
+ exit(0);
+}
+
+if (argv[FILENAME_ARG] == "--help") {
+ int choice = dlgMessageBox(usage, "+Return to Eagle", "Run Setup Now");
+ switch (choice) {
+
+ // return to eagle
+ case 0:
+ exit(0);
+ break;
+
+ // Run setup now
+ case 1:
+ exit("run pcb-gcode-setup");
+ break;
+ }
+ exit(0);
+}
+
+// Be sure a filename is specified.
+if (argv[FILENAME_ARG]) {
+ m_file_name = argv[FILENAME_ARG];
+ if (filedir(m_file_name) == "") {
+ board(B) m_file_name = filedir(B.name) + m_file_name;
+ }
+}
+else {
+ board(B) m_file_name = filesetext(B.name, "");
+}
+
+if (FILENAMES_8_CHARACTERS) {
+ m_file_name = filedir(m_file_name) + strsub(filename(m_file_name), 0, 5);
+}
+
+// Use a default width if one is not given.
+if (argv[WIDTH_ARG]) {
+ g_width = strtod(argv[WIDTH_ARG]);
+}
+else {
+ g_width = DEFAULT_WIDTH;
+}
+
+// Get the isolate parameter or use the default.
+if (argv[ISO_ARG]) {
+ m_isolate = strtod(argv[ISO_ARG]);
+}
+else {
+ m_isolate = ISO_MIN;
+}
+
+// Get the pass number, or default to first pass (0).
+if (argv[PASS_ARG]) {
+ m_pass_num = strtol(argv[PASS_ARG]);
+}
+else {
+ m_pass_num = 0;
+}
+
+// Get the phase we are processing, or default to the first one.
+if (argv[PHASE_ARG]) {
+ g_phase = strtol(argv[PHASE_ARG]);
+}
+else {
+ g_phase = PH_TOP_OUT_GEN;
+}
+
+get_current_profile();
+if (g_phase == PH_TOP_OUT_GEN && m_pass_num == 0 && program_is_setup() == NO)
+{
+ exit("run pcb-gcode-setup");
+}
+
+//
+// Do what we need to for this phase.
+//
+switch (g_phase) {
+ case PH_TOP_OUT_GEN:
+ if (GENERATE_TOP_OUTLINES == YES)
+ generate_outlines(TOP);
+ break;
+ case PH_TOP_OUT_WRITE:
+ if (GENERATE_TOP_OUTLINES == YES)
+ write_outlines(TOP, "top", OUTLINES);
+ break;
+
+ case PH_TOP_FILL_GEN:
+ if (GENERATE_TOP_FILL == YES)
+ generate_outlines(TOP);
+ break;
+ case PH_TOP_FILL_WRITE:
+ if (GENERATE_TOP_FILL == YES)
+ write_outlines(TOP, "tf", FILL);
+ break;
+
+ case PH_BOTTOM_OUT_GEN:
+ if (GENERATE_BOTTOM_OUTLINES == YES)
+ generate_outlines(BOTTOM);
+ break;
+ case PH_BOTTOM_OUT_WRITE:
+ if (GENERATE_BOTTOM_OUTLINES == YES)
+ write_outlines(BOTTOM, "bot", OUTLINES);
+ break;
+
+ case PH_BOTTOM_FILL_GEN:
+ if (GENERATE_BOTTOM_FILL == YES)
+ generate_outlines(BOTTOM);
+ break;
+ case PH_BOTTOM_FILL_WRITE:
+ if (GENERATE_BOTTOM_FILL == YES)
+ write_outlines(BOTTOM, "bf", FILL);
+ break;
+
+ case PH_TOP_DRILL:
+ if (GENERATE_TOP_DRILL == YES)
+ drill(TOP, "td");
+ break;
+ case PH_BOTTOM_DRILL:
+ if (GENERATE_BOTTOM_DRILL == YES)
+ drill(BOTTOM, "bd");
+ break;
+
+ case PH_MILL:
+ if (GENERATE_MILLING == YES)
+ write_outlines(MILL, "mil", MILL_BOARD);
+ break;
+
+ case PH_TEXT:
+ if (GENERATE_TEXT == YES)
+ write_outlines(TEXT, "txt", MILL_TEXT);
+ break;
+
+ default:
+ sprintf(g_debug, "Illegal phase %d in main routine", g_phase);
+ Fatal("Sorry...", g_debug);
+}
+
+// Set things up for the next phase.
+next_phase();
+
+if (SHOW_PROGRESS == YES) {
+ gen_progress_menu(g_phase);
+}
+
+// If this is not the last phase, exit with a command line for
+// Eagle to process. The command includes running this program again.
+if (g_phase < PH_LAST_PHASE) {
+ sprintf(g_cmd,
+ "%s"
+ "window fit;\n"
+ "%s"
+ "run '%s' '%s' '%f' '%f' '%d' '%d';\n",
+ g_cmd,
+ (SHOW_PROGRESS) ? "script pcb-gcode-prg.scr;\n" : "",
+ argv[PROGRAM_NAME_ARG], m_file_name, g_width, m_isolate,
+ m_pass_num, g_phase
+ );
+ exit(g_cmd);
+}
+else {
+ g_cmd = "window fit;\n";
+ if (SHOW_PROGRESS) {
+ if (RESTORE_MENU_FILE != "") {
+ g_cmd = g_cmd + "script " + RESTORE_MENU_FILE + ";\n";
+ }
+ else {
+ g_cmd = g_cmd + "menu;\n";
+ }
+ }
+
+ exit(g_cmd);
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/pcbgcode.tmproj b/trunk/ulp/pcb-gcode-3.6.0.4/pcbgcode.tmproj
new file mode 100644
index 00000000..7ff8c204
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/pcbgcode.tmproj
@@ -0,0 +1,264 @@
+
+
+
+
+ currentDocument
+ rakefile.rb
+ documents
+
+
+ expanded
+
+ name
+ docs
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ docs
+
+
+ filename
+ pcb_gcode_is_setup
+ lastUsed
+ 2012-12-16T21:32:53Z
+
+
+ filename
+ pcb-gcode-setup.ulp
+ lastUsed
+ 2013-01-17T03:04:58Z
+
+
+ filename
+ pcb-gcode.ulp
+ lastUsed
+ 2013-01-17T03:05:09Z
+
+
+ filename
+ pcbgcode.tmproj
+ lastUsed
+ 2009-02-07T14:49:48Z
+
+
+ filename
+ plugin_headers.h
+ lastUsed
+ 2012-12-16T18:55:27Z
+
+
+ name
+ plugins
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ plugins
+
+
+ name
+ profiles
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ profiles
+
+
+ name
+ safe_options
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ safe_options
+
+
+ name
+ settings
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ settings
+
+
+ expanded
+
+ name
+ source
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ source
+
+
+ filename
+ storage.nv
+ lastUsed
+ 2009-01-03T00:27:28Z
+
+
+ name
+ viewer
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ viewer
+
+
+ expanded
+
+ name
+ make
+ regexFolderFilter
+ !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$
+ sourceDirectory
+ make
+
+
+ filename
+ rakefile.rb
+ lastUsed
+ 2013-01-17T03:13:04Z
+ selected
+
+
+
+ filename
+ README
+ lastUsed
+ 2013-01-02T22:44:23Z
+
+
+ fileHierarchyDrawerWidth
+ 296
+ metaData
+
+ README
+
+ caret
+
+ column
+ 28
+ line
+ 0
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 0
+
+ docs/changelog.txt
+
+ caret
+
+ column
+ 65
+ line
+ 3
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 0
+
+ make/write_convert_units.rb
+
+ caret
+
+ column
+ 32
+ line
+ 87
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 46
+
+ pcb-gcode-setup.ulp
+
+ caret
+
+ column
+ 31
+ line
+ 204
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 183
+
+ pcb-gcode.ulp
+
+ caret
+
+ column
+ 21
+ line
+ 23
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 2
+
+ rakefile.rb
+
+ caret
+
+ column
+ 76
+ line
+ 43
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 41
+
+ source/pcb-gcode.h
+
+ caret
+
+ column
+ 0
+ line
+ 190
+
+ columnSelection
+
+ firstVisibleColumn
+ 0
+ firstVisibleLine
+ 181
+ selectFrom
+
+ column
+ 23
+ line
+ 190
+
+ selectTo
+
+ column
+ 0
+ line
+ 190
+
+
+
+ openDocuments
+
+ pcb-gcode-setup.ulp
+ pcb-gcode.ulp
+ docs/changelog.txt
+ rakefile.rb
+ source/pcb-gcode.h
+ README
+ make/write_convert_units.rb
+
+ showFileHierarchyDrawer
+
+ windowFrame
+ {{339, 83}, {957, 795}}
+
+
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugin_headers.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugin_headers.h
new file mode 100644
index 00000000..87474841
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugin_headers.h
@@ -0,0 +1,4 @@
+#include "source/nonvolatile.h"
+
+#include "plugins/calculator.plugin.h"
+
\ No newline at end of file
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin
new file mode 100644
index 00000000..3d0645a5
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin
@@ -0,0 +1,75 @@
+dlgGroup("Calculator (RPN)") {
+ dlgGridLayout {
+ int row;
+ dlgCell(row, 0) { dlgLabel("Result"); }
+ dlgCell(row, 1, row, 3) {
+ dlgGroup("") { dlgLabel(m_result, 1); }
+ }
+ dlgCell(row, 4) dlgLabel(g_angle_mode_str, 1);
+ dlgCell(++row, 0) { dlgLabel("Entry"); }
+ dlgCell(row, 1, row, 3) dlgGroup("") { dlgLabel(m_entry, 1); }
+ dlgCell(++row, 0) dlgPushButton("7") calc_enter("7");
+ dlgCell(row, 1) dlgPushButton("8") calc_enter("8");
+ dlgCell(row, 2) dlgPushButton("9") calc_enter("9");
+ dlgCell(row, 3) dlgPushButton("/") calc(m_entry, OP_DIVIDE);
+ dlgCell(row, 4) dlgPushButton("M+") calc(m_entry, OP_MEMORY_PLUS);
+ dlgCell(row, 5) dlgPushButton("deg") calc(m_entry, OP_DEGREE);
+ dlgCell(row, 6) dlgPushButton("rad") calc(m_entry, OP_RADIAN);
+
+ dlgCell(++row, 0) dlgPushButton("4") calc_enter("4");
+ dlgCell(row, 1) dlgPushButton("5") calc_enter("5");
+ dlgCell(row, 2) dlgPushButton("6") calc_enter("6");
+ dlgCell(row, 3) dlgPushButton("*") calc(m_entry, OP_MULTIPLY);
+ dlgCell(row, 4) dlgPushButton("->M") calc(m_entry, OP_MEMORY_STORE);
+ dlgCell(row, 5) dlgPushButton("sin") calc(m_entry, OP_SINE);
+ dlgCell(row, 6) dlgPushButton("arc sin") calc(m_entry, OP_ARC_SINE);
+
+ dlgCell(++row, 0) dlgPushButton("1") calc_enter("1");
+ dlgCell(row, 1) dlgPushButton("2") calc_enter("2");
+ dlgCell(row, 2) dlgPushButton("3") calc_enter("3");
+ dlgCell(row, 3) dlgPushButton("--") calc(m_entry, OP_SUBTRACT);
+ dlgCell(row, 4) dlgPushButton("<-M") calc(m_entry, OP_MEMORY_RECALL);
+ dlgCell(row, 5) dlgPushButton("cos") calc(m_entry, OP_COSINE);
+ dlgCell(row, 6) dlgPushButton("arc cos") calc(m_entry, OP_ARC_COSINE);
+
+ dlgCell(++row, 0) dlgPushButton(".") calc_enter(".");
+ dlgCell(row, 1) dlgPushButton("0") calc_enter("0");
+ dlgCell(row, 2) dlgPushButton("C") calc(m_entry, OP_CLEAR);
+ dlgCell(row, 3) dlgPushButton("++") calc(m_entry, OP_ADD);
+ dlgCell(row, 4) dlgPushButton("0->M") calc(m_entry, OP_MEMORY_CLEAR);
+ dlgCell(row, 5) dlgPushButton("tan") calc(m_entry, OP_TANGENT);
+ dlgCell(row, 6) dlgPushButton("arc tan") calc(m_entry, OP_ARC_TANGENT);
+
+ dlgCell(++row, 2, row, 4) dlgPushButton("ENTER") {
+ set_accum(m_entry);
+ m_result = m_entry;
+ m_entry = "";
+ dlgRedisplay();
+ }
+
+ dlgCell(row, 6) dlgPushButton("Help") {
+ dlgMessageBox("
Help for the RPN Calculator
"
+ "RPN stands for Reverse Polish Notation. "
+ "The calculator has a number in the Result line. "
+ "You enter a number in the Entry line, then select an operation, "
+ "like add, subtract, etc. The answer of that operation will be "
+ "put into the Result line, ready for a new operation."
+ "Here is an example:"
+ "Let's say you have a part and you want to drill a hole on a circle "
+ "with a 5" radius, 37° counter-clockwise "
+ "from the center at X=1.2, Y=2.4. "
+ "Enter the following: "
+ "37 [sin] "
+ "5 [*] "
+ "1.2 [+] "
+ "The answer is 4.209. That is the Y coordinate "
+ "37 [cos] "
+ "5 [*] "
+ "2.4 [+] "
+ "The answer is 6.393, that is the X coordinate"
+ "I guess that is a complex example :-)"
+ );
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin.h
new file mode 100644
index 00000000..4f690d1b
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin.h
@@ -0,0 +1,297 @@
+/**********************************************************
+ *
+ * A basic calculator.
+ *
+ * Plugin Definitions
+ * NAME = calculator
+ * DESC = Basic calculator
+ * AUTHOR = John Johnson
+ * TAB_NAME = Plugins
+ **********************************************************/
+
+int UNARY_BEGIN = 0x80;
+int ANGLE_IN = 0x40;
+int ANGLE_OUT = 0x20;
+
+enum {
+ OP_INVALID,
+ OP_CLEAR,
+ OP_ENTER,
+ OP_ADD,
+ OP_SUBTRACT,
+ OP_DIVIDE,
+ OP_MULTIPLY,
+ OP_RADIAN,
+ OP_DEGREE
+};
+
+enum {
+ OP_MEMORY_PLUS = 0x80 /* UNARY_BEGIN */,
+ OP_MEMORY_STORE,
+ OP_MEMORY_RECALL,
+ OP_MEMORY_CLEAR
+};
+
+enum {
+ OP_SINE = 0xC0 /* UNARY_BEGIN + ANGLE_IN */,
+ OP_COSINE,
+ OP_TANGENT,
+ OP_ARC_SINE,
+ OP_ARC_COSINE,
+ OP_ARC_TANGENT
+};
+
+enum {
+ OP_INV_SINE = 0xA0 /* UNARY_BEGIN + ANGLE_OUT */,
+ OP_INV_COSINE,
+ OP_INV_TANGENT
+};
+
+enum {
+ ANG_INVALID,
+ ANG_RADIAN,
+ ANG_DEGREE
+ /* ANG_GRADIANS - sorry */
+};
+
+int m_angle_mode;
+string g_angle_mode_str;
+int g_memory;
+
+real accum;
+real depth;
+int passes;
+string nc_file;
+int unit_metric;
+real length;
+string result;
+
+string m_result = "0";
+string m_entry = "0";
+
+string format_number(real n)
+{
+ string tmp;
+
+ sprintf(tmp, "%f", n);
+ return tmp;
+
+}
+
+real set_accum(string s)
+{
+ accum = strtod(s);
+ return accum;
+}
+
+string set_result(real r)
+{
+ m_result = format_number(r);
+// set_nv_param("calc_result", m_result);
+ return m_result;
+}
+
+real set_angle_mode(int mode)
+{
+ real result;
+ string num;
+ int used_entry;
+
+ result = strtod(m_result);
+
+ if (m_entry != "") {
+ num = m_entry;
+ used_entry = 1;
+ }
+ else if (m_result != "") {
+ num = m_result;
+ }
+ else {
+ num = m_result;
+ }
+
+ if (m_angle_mode == ANG_DEGREE && mode == ANG_RADIAN) {
+ result = strtod(num) / 180 * PI;
+ }
+ else if (m_angle_mode == ANG_RADIAN && mode == ANG_DEGREE) {
+ result = strtod(num) / PI * 180;
+ }
+ m_angle_mode = mode;
+
+ switch (m_angle_mode) {
+ case ANG_RADIAN:
+ g_angle_mode_str = "rad";
+ break;
+ case ANG_DEGREE:
+ g_angle_mode_str = "deg";
+ break;
+ }
+
+// set_nv_param("calc_angle_mode", g_angle_mode_str);
+
+// if (used_entry) {
+ m_entry = format_number(result);
+// }
+// else {
+ set_result(result);
+// }*/
+ return result;
+}
+
+string get_mode_str()
+{
+ return (m_angle_mode == ANG_RADIAN) ? "rad" : "deg";
+}
+
+real rad(real n)
+{
+ return (m_angle_mode == ANG_RADIAN) ? n : n / 180 * PI;
+}
+
+real unrad(real n)
+{
+ return (m_angle_mode == ANG_RADIAN) ? n : n / PI * 180;
+}
+
+int is_unary(int op)
+{
+ return (op & UNARY_BEGIN) ? 1 : 0;
+}
+
+void set_memory(real n)
+{
+ string tmp;
+
+ g_memory = n;
+// set_nv_param("calc_memory", format_number(n));
+}
+
+real get_memory()
+{
+ return g_memory;
+}
+
+void clear_memory()
+{
+ g_memory = 0;
+}
+
+int m_entering;
+void calc_enter(string n)
+{
+ if (!m_entering) {
+ m_entry = n;
+ m_entering = 1;
+ }
+ else {
+ m_entry += n;
+ }
+}
+
+real calc(string a, int OPERATION)
+{
+ real ra;
+ int no_clear;
+
+ m_entering = 0;
+
+ ra = strtod(a);
+ if (m_entry == "" && m_result != "" && is_unary(OPERATION))
+ ra = strtod(m_result);
+
+ if (OPERATION & ANGLE_IN) {
+ ra = rad(ra);
+ }
+
+ switch(OPERATION) {
+ case OP_ENTER:
+ accum = ra;
+ set_result(accum);
+ break;
+ case OP_ADD:
+ accum = accum + ra;
+ break;
+ case OP_SUBTRACT:
+ accum = accum - ra;
+ break;
+ case OP_DIVIDE:
+ accum = accum / ra;
+ break;
+ case OP_MULTIPLY:
+ accum = accum * ra;
+ break;
+ case OP_DEGREE:
+ accum = set_angle_mode(ANG_DEGREE);
+ break;
+ case OP_RADIAN:
+ accum = set_angle_mode(ANG_RADIAN);
+ break;
+
+ case OP_MEMORY_PLUS:
+ set_memory(ra + get_memory());
+ accum = ra;
+ break;
+ case OP_MEMORY_STORE:
+ set_memory(ra);
+ accum = ra;
+ break;
+ case OP_MEMORY_RECALL:
+ m_entry = format_number(get_memory());
+ no_clear = 1;
+ accum = ra;
+ break;
+ case OP_MEMORY_CLEAR:
+ clear_memory();
+ accum = ra;
+ break;
+
+ case OP_COSINE:
+ accum = cos(ra);
+ break;
+ case OP_SINE:
+ accum = sin(ra);
+ break;
+ case OP_TANGENT:
+ accum = tan(ra);
+ break;
+
+ case OP_ARC_COSINE:
+ accum = acos(ra);
+ break;
+ case OP_ARC_SINE:
+ accum = asin(ra);
+ break;
+ case OP_ARC_TANGENT:
+ accum = atan(ra);
+ break;
+
+ case OP_CLEAR:
+ accum = 0;
+ break;
+ default:
+ dlgMessageBox("Invalid OPERATION");
+ }
+
+ if (OPERATION & ANGLE_OUT) {
+ accum = unrad(accum);
+ }
+
+ set_result(accum);
+ if (!no_clear) m_entry = "";
+ return accum;
+}
+
+/**********************************
+ * Initialization.
+ **********************************/
+
+set_angle_mode(ANG_DEGREE);
+
+
+//~ set_memory(strtod(get_nv_param("calc_memory", "0.0", 0 /* don't abort */)));
+//~ if (get_nv_param("calc_angle_mode", "deg", 0 /* don't abort */) == "deg")
+//~ set_angle_mode(ANG_DEGREE);
+//~ else
+//~ set_angle_mode(ANG_RADIAN);
+//~ set_result(strtod(get_nv_param("calc_result", "0.0", 0 /* don't abort */)));
+
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/filenames.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/filenames.plugin
new file mode 100644
index 00000000..db5ce481
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/filenames.plugin
@@ -0,0 +1,32 @@
+dlgGroup("File Naming") {
+ dlgHBoxLayout {
+ dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE);
+ }
+ dlgGroup("Top (Component) Side Files") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Etching ");
+ dlgCell(1, 1) dlgStringEdit(FILENAME_TOP_ETCH_FILE);
+ dlgCell(2, 0) dlgLabel("Drill ");
+ dlgCell(2, 1) dlgStringEdit(FILENAME_TOP_DRILL_FILE);
+ dlgCell(3, 0) dlgLabel("Mill ");
+ dlgCell(3, 1) dlgStringEdit(FILENAME_TOP_MILL_FILE);
+ dlgCell(4, 0) dlgLabel("Fill ");
+ dlgCell(4, 1) dlgStringEdit(FILENAME_TOP_FILL_FILE);
+ }
+ }
+ dlgGroup("Bottom (Solder) Side Files") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Etching ");
+ dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE);
+ dlgCell(2, 0) dlgLabel("Drill ");
+ dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE);
+ dlgCell(3, 0) dlgLabel("Mill ");
+ dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE);
+ dlgCell(4, 0) dlgLabel("Fill ");
+ dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_FILL_FILE);
+ }
+ }
+ dlgPushButton("Test Filenames") {
+ dlgMessageBox("Test");
+ }
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_headers.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_headers.h
new file mode 100644
index 00000000..3cc01ef2
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_headers.h
@@ -0,0 +1,4 @@
+#include "nonvolatile.h"
+
+#include "plugins/calculator.plugin.h"
+
\ No newline at end of file
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_loader.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_loader.h
new file mode 100644
index 00000000..b668c2ea
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_loader.h
@@ -0,0 +1,40 @@
+/*
+ * Generate g-code for milling PC boards.
+ *
+ * Copyright 2004-2009 by John Johnson Software, LLC.
+ * See readme.html for copyright information.
+ *
+ */
+
+// BEGIN_PLUGIN_INCLUDES
+dlgVBoxLayout {
+ dlgHBoxLayout {
+/* dlgVBoxLayout {
+ dlgGroup("Square X and Y (doesn't do anything)") {
+ #include "square_x_and_y.plugin"
+ }
+ dlgStretch(1);
+ }
+ dlgVBoxLayout {
+ dlgGroup("Square Z") {
+ #include "square_z.plugin"
+ }
+ dlgStretch(1);
+ }
+ dlgVBoxLayout {
+ dlgGroup("Filenames") {
+ #include "filenames.plugin"
+ }
+ dlgStretch(1);
+ }*/
+ }
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgVBoxLayout {
+ #include "calculator.plugin"
+ }
+ dlgStretch(1);
+ }
+ dlgStretch(1);
+}
+// END_PLUGIN_INCLUDES
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_x_and_y.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_x_and_y.plugin
new file mode 100644
index 00000000..a06135d5
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_x_and_y.plugin
@@ -0,0 +1,37 @@
+//Square X Y/Helps you square the X and Y axes of your machine./john
+
+/**********************************************************
+ *
+ * Diagnostic to help people square their machines in
+ * the X and Y axes.
+ *
+ * Plugin Definitions
+ * NAME = square X and Y
+ * DESC = Helps a user square their machine.
+ * AUTHOR = John Johnson
+ * TAB_NAME = Plugins
+ **********************************************************/
+real depth;
+int passes;
+string nc_file;
+int unit_metric;
+real length;
+string result;
+
+dlgGridLayout {
+ dlgCell(0, 0, 0, 3) {
+ dlgCheckBox("Use Metric", unit_metric) { dlgRedisplay(); }
+ }
+ dlgCell(1, 0) { dlgLabel("Length"); dlgRealEdit(length); }
+ dlgCell(2, 0) { dlgLabel("Passes"); dlgIntEdit(passes); }
+ dlgCell(3, 0) { dlgLabel("Depth"); dlgRealEdit(depth); }
+ dlgCell(4, 0) { dlgLabel("NC File"); dlgStringEdit(nc_file);
+ dlgPushButton("...") {
+ nc_file = dlgFileSave("Save gcode as...");
+ }
+ }
+ dlgCell(1,1) {
+ sprintf(result, "tan(45) = %f", tan(PI / 4));
+ dlgLabel(result, 1);
+ }
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_z.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_z.plugin
new file mode 100644
index 00000000..7bacb7a6
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_z.plugin
@@ -0,0 +1,15 @@
+//Square X Y/Helps you square the X and Y axes of your machine./john
+
+/**********************************************************
+ *
+ * Diagnostic to help people square their machines in
+ * the X and Y axes.
+ *
+ * Plugin Definitions
+ * NAME = square X and Y
+ * DESC = Helps a user square their machine.
+ * AUTHOR = John Johnson
+ * TAB_NAME = Plugins
+ **********************************************************/
+
+dlgLabel("Nice layout here");
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/emc.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/emc.pp
new file mode 100644
index 00000000..15156481
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/emc.pp
@@ -0,0 +1,125 @@
+//
+// Options for pcb-gcode.ulp.
+// Often used options are at the top of the file.
+// Copied to gcode-defaults.h by the setup program.
+//
+// author=John Johnson
+// description=EMC
+//
+
+int FILENAMES_8_CHARACTERS = NO;
+
+//
+// Comments.
+//
+string COMMENT_BEGIN = "(";
+string COMMENT_END = ")";
+
+//
+// Format strings for coordinates, etc.
+//
+string FORMAT = "%-6.4f "; /* coordinate format */
+string FR_FORMAT = "F%-5.2f "; /* feedrate format */
+string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT;
+string EOL = "\n"; /* standard line ending */
+string PARAM = "P"; /* some use P, some # for parameters */
+//
+// Modes
+//
+string INCH_MODE = "G20" + EOL;
+string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL;
+string METRIC_MODE = "G21" + EOL;
+string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL;
+string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL;
+string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL;
+string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL;
+
+//
+// G codes
+//
+string RAPID = "G00 ";
+string FEED = "G01 ";
+string ARC_CW = "G02 ";
+string ARC_CCW = "G03 ";
+string DWELL = "G04 " + PARAM + "%f" + EOL;
+
+//
+// M codes
+//
+string SPINDLE_ON = "M03" + EOL + DWELL;
+string SPINDLE_OFF = "M05" + EOL;
+string END_PROGRAM = "M02" + EOL;
+string OPERATOR_PAUSE = "M06 ";
+
+//
+// Coordinates
+//
+string MOVE_X = "X" + FORMAT;
+string MOVE_Y = "Y" + FORMAT;
+string MOVE_XY = "X" + FORMAT + "Y" + FORMAT;
+string MOVE_Z = "Z" + FORMAT;
+string MOVE_XYZ = MOVE_XY + MOVE_Z;
+
+//
+// Rapids
+//
+string RAPID_MOVE_X = RAPID + MOVE_X;
+string RAPID_MOVE_Y = RAPID + MOVE_Y;
+string RAPID_MOVE_XY = RAPID + MOVE_XY;
+string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0";
+string RAPID_MOVE_Z = RAPID + MOVE_Z;
+string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ;
+
+//
+// Feeds
+//
+string FEED_MOVE_X = FEED + MOVE_X;
+string FEED_MOVE_Y = FEED + MOVE_Y;
+string FEED_MOVE_XY = FEED + MOVE_XY;
+string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT;
+string FEED_MOVE_Z = FEED + MOVE_Z;
+string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT;
+string FEED_MOVE_XYZ = FEED + MOVE_XYZ;
+
+//
+// Drilling holes
+//
+// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell
+//
+string DRILL_CODE = "G82 ";
+string RELEASE_PLANE = "R" + FORMAT;
+string DWELL_TIME = PARAM + "%f";
+string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL;
+string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL;
+
+//
+// Tool change
+//
+string TOOL_CODE = "T%02d ";
+string TOOL_MM_FORMAT = "%1.3fmm";
+string TOOL_INCH_FORMAT = "%1.4fin";
+string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + COMMENT_BEGIN + FORMAT + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN +
+ " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count)
+{
+ string formatted;
+
+ sprintf(formatted, COMMENT_BEGIN + " " +
+ TOOL_CODE + "| " + TOOL_MM_FORMAT + " " +
+ TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " +
+ TOOL_INCH_FORMAT + " | " +
+ " %4d" + " " +
+ COMMENT_END + EOL,
+ tool_number, size_mm, size_inch, min_drill, max_drill, count);
+ return(formatted);
+}
+
+//
+// Circles / Arcs
+//
+string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL;
+string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL;
+
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/generic.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/generic.pp
new file mode 100644
index 00000000..5982cb04
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/generic.pp
@@ -0,0 +1,130 @@
+//
+// Options for pcb-gcode.ulp.
+// Often used options are at the top of the file.
+// Copied to gcode-defaults.h by the setup program.
+//
+// author=John Johnson
+// description=Tries to be very compatible
+//
+
+int FILENAMES_8_CHARACTERS = NO;
+
+//
+// Comments.
+//
+string COMMENT_BEGIN = "(";
+string COMMENT_END = ")";
+
+//
+// Format strings for coordinates, etc.
+//
+string FORMAT = "%-6.4f "; /* coordinate format */
+string FR_FORMAT = "F%-5.2f "; /* feedrate format */
+string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT;
+string EOL = "\n"; /* standard line ending */
+string PARAM = "P"; /* some use P, some # for parameters */
+//
+// Modes
+//
+string INCH_MODE = "G20" + EOL;
+string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL;
+string METRIC_MODE = "G21" + EOL;
+string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL;
+string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL;
+string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL;
+string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL;
+
+//
+// G codes
+//
+string RAPID = "G00 ";
+string FEED = "G01 ";
+string ARC_CW = "G02 ";
+string ARC_CCW = "G03 ";
+string DWELL = "G04 " + PARAM + "%f" + EOL;
+
+//
+// M codes
+//
+string SPINDLE_ON = "M03" + EOL + DWELL;
+string SPINDLE_OFF = "M05" + EOL;
+string END_PROGRAM = "M02" + EOL;
+string OPERATOR_PAUSE = "M06 ";
+
+//
+// Coordinates
+//
+string MOVE_X = "X" + FORMAT;
+string MOVE_Y = "Y" + FORMAT;
+string MOVE_XY = "X" + FORMAT + "Y" + FORMAT;
+string MOVE_Z = "Z" + FORMAT;
+string MOVE_XYZ = MOVE_XY + MOVE_Z;
+
+//
+// Rapids
+//
+string RAPID_MOVE_X = RAPID + MOVE_X;
+string RAPID_MOVE_Y = RAPID + MOVE_Y;
+string RAPID_MOVE_XY = RAPID + MOVE_XY;
+string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0";
+string RAPID_MOVE_Z = RAPID + MOVE_Z;
+string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ;
+
+//
+// Feeds
+//
+string FEED_MOVE_X = FEED + MOVE_X;
+string FEED_MOVE_Y = FEED + MOVE_Y;
+string FEED_MOVE_XY = FEED + MOVE_XY;
+string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT;
+string FEED_MOVE_Z = FEED + MOVE_Z;
+string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT;
+string FEED_MOVE_XYZ = FEED + MOVE_XYZ;
+
+//
+// Drilling holes
+//
+// Not using G82 so it will be very generic.
+//
+string DRILL_CODE = ";( G82 not used )";
+string RELEASE_PLANE = "R" + FORMAT;
+string DWELL_TIME = PARAM + "%f";
+
+string DRILL_FIRST_HOLE = RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + EOL
+ + RAPID + MOVE_XY + EOL
+ + FEED + MOVE_Z + FR_FORMAT + EOL
+ + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL
+ + COMMENT_BEGIN + RELEASE_PLANE + " " + DWELL_TIME + COMMENT_END + EOL;
+
+string DRILL_HOLE = COMMENT_BEGIN + RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + COMMENT_END + EOL
+ + RAPID + MOVE_XY + EOL
+ + FEED + "Z" + real_to_string(DRILL_DEPTH) + EOL
+ + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL;
+
+//
+// Tool change
+//
+string TOOL_CODE = "T%02d ";
+string TOOL_MM_FORMAT = "%1.3fmm";
+string TOOL_INCH_FORMAT = "%1.4fin";
+string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL;
+
+string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN +
+ " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count)
+{
+ string formatted;
+
+ sprintf(formatted, COMMENT_BEGIN + " " + TOOL_CODE + " " + TOOL_MM_FORMAT + " " +
+ TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + COMMENT_END + EOL,
+ tool_number, size_mm, size_inch, min_drill, max_drill);
+ return(formatted);
+}
+
+//
+// Circles / Arcs
+//
+string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL;
+string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL;
+
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/isel.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/isel.pp
new file mode 100644
index 00000000..44f6ec94
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/isel.pp
@@ -0,0 +1,124 @@
+//
+// Options for pcb-gcode.ulp.
+// Often used options are at the top of the file.
+// Copied to gcode-defaults.h by the setup program.
+//
+// author=John Johnson
+// description=iSel
+//
+
+int FILENAMES_8_CHARACTERS = NO;
+
+//
+// Comments.
+//
+string COMMENT_BEGIN = "(";
+string COMMENT_END = ")";
+
+//
+// Format strings for coordinates, etc.
+//
+string FORMAT = "%-6.0f "; /* coordinate format */
+string FR_FORMAT = "F%-5.0f "; /* feedrate format */
+string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT;
+string EOL = "\n"; /* standard line ending */
+string PARAM = "#"; /* some use P, some # for parameters */
+//
+// Modes
+//
+string INCH_MODE = "G20" + EOL;
+string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL;
+string METRIC_MODE = "G21" + EOL;
+string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL;
+string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL;
+string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL;
+string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL;
+
+//
+// G codes
+//
+string RAPID = "FASTABS ";
+string FEED = "MOVEABS ";
+string ARC_CW = "G02 ";
+string ARC_CCW = "G03 ";
+string DWELL = "G04 " + PARAM + "%f" + EOL;
+
+//
+// M codes
+//
+string SPINDLE_ON = "SPINDLE ON" + EOL + DWELL;
+string SPINDLE_OFF = "SPINDLE OFF" + EOL;
+string END_PROGRAM = "PROGEND" + EOL;
+string OPERATOR_PAUSE = "M06 ";
+
+//
+// Coordinates
+//
+string MOVE_X = "X" + FORMAT;
+string MOVE_Y = "Y" + FORMAT;
+string MOVE_XY = "X" + FORMAT + "Y" + FORMAT;
+string MOVE_Z = "Z" + FORMAT;
+string MOVE_XYZ = MOVE_XY + MOVE_Z;
+
+//
+// Rapids
+//
+string RAPID_MOVE_X = RAPID + MOVE_X;
+string RAPID_MOVE_Y = RAPID + MOVE_Y;
+string RAPID_MOVE_XY = RAPID + MOVE_XY;
+string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0";
+string RAPID_MOVE_Z = RAPID + MOVE_Z;
+string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ;
+
+//
+// Feeds
+//
+string FEED_MOVE_X = FEED + MOVE_X;
+string FEED_MOVE_Y = FEED + MOVE_Y;
+string FEED_MOVE_XY = FEED + MOVE_XY;
+string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT;
+string FEED_MOVE_Z = FEED + MOVE_Z;
+string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT;
+string FEED_MOVE_XYZ = FEED + MOVE_XYZ;
+
+//
+// Drilling holes
+//
+// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell
+//
+string DRILL_CODE = "G82 ";
+string RELEASE_PLANE = "R" + FORMAT;
+string DWELL_TIME = PARAM + "%f";
+string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL;
+string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL;
+
+//
+// Tool change
+//
+string TOOL_CODE = "T%02d ";
+string TOOL_MM_FORMAT = "%1.3fmm";
+string TOOL_INCH_FORMAT = "%1.4fin";
+string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL;
+
+string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN +
+ " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count)
+{
+ string formatted;
+
+ sprintf(formatted, COMMENT_BEGIN + " " +
+ TOOL_CODE + "| " + TOOL_MM_FORMAT + " " +
+ TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " +
+ TOOL_INCH_FORMAT + " | " +
+ " %4d" + " " +
+ COMMENT_END + EOL,
+ tool_number, size_mm, size_inch, min_drill, max_drill, count);
+ return(formatted);
+}
+
+//
+// Circles / Arcs
+//
+string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL;
+string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/mach.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/mach.pp
new file mode 100644
index 00000000..fdef4222
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/mach.pp
@@ -0,0 +1,126 @@
+//
+// Options for pcb-gcode.ulp.
+// Often used options are at the top of the file.
+// Copied to gcode-defaults.h by the setup program.
+
+//
+// author=John Johnson
+// description=Mach3 - EMC for Windows
+//
+
+int FILENAMES_8_CHARACTERS = NO;
+
+//
+// Comments.
+//
+string COMMENT_BEGIN = "(";
+string COMMENT_END = ")";
+
+//
+// Format strings for coordinates, etc.
+//
+string EOL = "\n"; /* standard line ending */
+string PARAM = "P"; /* some use P, some # for parameters */
+string FORMAT = "%-7.4f "; /* coordinate format */
+string FR_FORMAT = "F%-5.0f "; /* feedrate format */
+string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT;
+
+//
+// Modes
+//
+string INCH_MODE = "G20" + EOL;
+string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL;
+string METRIC_MODE = "G21" + EOL;
+string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL;
+string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL;
+string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL;
+string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL;
+
+//
+// G codes
+//
+string RAPID = "G00 ";
+string FEED = "G01 ";
+string ARC_CW = "G02 ";
+string ARC_CCW = "G03 ";
+string DWELL = "G04 " + PARAM + "%f" + EOL;
+
+//
+// M codes
+//
+string SPINDLE_ON = "M03" + EOL + DWELL;
+string SPINDLE_OFF = "M05" + EOL;
+string END_PROGRAM = "M02" + EOL;
+string OPERATOR_PAUSE = "M06 ";
+
+//
+// Coordinates
+//
+string MOVE_X = "X" + FORMAT;
+string MOVE_Y = "Y" + FORMAT;
+string MOVE_XY = "X" + FORMAT + "Y" + FORMAT;
+string MOVE_Z = "Z" + FORMAT;
+string MOVE_XYZ = MOVE_XY + MOVE_Z;
+
+//
+// Rapids
+//
+string RAPID_MOVE_X = RAPID + MOVE_X;
+string RAPID_MOVE_Y = RAPID + MOVE_Y;
+string RAPID_MOVE_XY = RAPID + MOVE_XY;
+string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0";
+string RAPID_MOVE_Z = RAPID + MOVE_Z;
+string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ;
+
+//
+// Feeds
+//
+string FEED_MOVE_X = FEED + MOVE_X;
+string FEED_MOVE_Y = FEED + MOVE_Y;
+string FEED_MOVE_XY = FEED + MOVE_XY;
+string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT;
+string FEED_MOVE_Z = FEED + MOVE_Z;
+string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT;
+string FEED_MOVE_XYZ = FEED + MOVE_XYZ;
+
+//
+// Drilling holes
+//
+// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell
+//
+string DRILL_CODE = "G82 ";
+string RELEASE_PLANE = "R" + FORMAT;
+string DWELL_TIME = PARAM + "%f";
+string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL;
+string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL;
+
+//
+// Tool change
+//
+string TOOL_CODE = "T%02d ";
+string TOOL_MM_FORMAT = "%1.3fmm";
+string TOOL_INCH_FORMAT = "%1.4fin";
+string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL;
+
+string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN +
+ " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count)
+{
+ string formatted;
+
+ sprintf(formatted, COMMENT_BEGIN + " " +
+ TOOL_CODE + "| " + TOOL_MM_FORMAT + " " +
+ TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " +
+ TOOL_INCH_FORMAT + " | " +
+ " %4d" + " " +
+ COMMENT_END + EOL,
+ tool_number, size_mm, size_inch, min_drill, max_drill, count);
+ return(formatted);
+}
+
+//
+// Circles / Arcs
+//
+string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL;
+string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/turbocnc.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/turbocnc.pp
new file mode 100644
index 00000000..b18e69dc
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/turbocnc.pp
@@ -0,0 +1,126 @@
+//
+// Options for pcb-gcode.ulp.
+// Often used options are at the top of the file.
+// Copied to gcode-defaults.h by the setup program.
+
+//
+// author=Art Eckstein
+// description=TurboCNC
+//
+
+int FILENAMES_8_CHARACTERS = YES;
+
+//
+// Comments.
+//
+string COMMENT_BEGIN = "(";
+string COMMENT_END = ")";
+
+//
+// Format strings for coordinates, etc.
+//
+string FORMAT = "%-6.4f "; /* coordinate format */
+string FR_FORMAT = "F%-5.2f "; /* feedrate format */
+string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT;
+string EOL = "\n"; /* standard line ending */
+string PARAM = "P"; /* some use P, some # for parameters */
+//
+// Modes
+//
+string INCH_MODE = "G20" + EOL;
+string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL;
+string METRIC_MODE = "G21" + EOL;
+string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL;
+string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL;
+string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL;
+string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL;
+
+//
+// G codes
+//
+string RAPID = "G00 ";
+string FEED = "G01 ";
+string ARC_CW = "G02 ";
+string ARC_CCW = "G03 ";
+string DWELL = "G04 " + PARAM + "%f" + EOL;
+
+//
+// M codes
+//
+string SPINDLE_ON = "M03" + EOL + DWELL;
+string SPINDLE_OFF = "M05" + EOL;
+string END_PROGRAM = "M02" + EOL;
+string OPERATOR_PAUSE = "M06 ";
+
+//
+// Coordinates
+//
+string MOVE_X = "X" + FORMAT;
+string MOVE_Y = "Y" + FORMAT;
+string MOVE_XY = "X" + FORMAT + "Y" + FORMAT;
+string MOVE_Z = "Z" + FORMAT;
+string MOVE_XYZ = MOVE_XY + MOVE_Z;
+
+//
+// Rapids
+//
+string RAPID_MOVE_X = RAPID + MOVE_X;
+string RAPID_MOVE_Y = RAPID + MOVE_Y;
+string RAPID_MOVE_XY = RAPID + MOVE_XY;
+string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0";
+string RAPID_MOVE_Z = RAPID + MOVE_Z;
+string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ;
+
+//
+// Feeds
+//
+string FEED_MOVE_X = FEED + MOVE_X;
+string FEED_MOVE_Y = FEED + MOVE_Y;
+string FEED_MOVE_XY = FEED + MOVE_XY;
+string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT;
+string FEED_MOVE_Z = FEED + MOVE_Z;
+string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT;
+string FEED_MOVE_XYZ = FEED + MOVE_XYZ;
+
+//
+// Drilling holes
+//
+// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell
+//
+string DRILL_CODE = "G82 ";
+string RELEASE_PLANE = "R" + FORMAT;
+string DWELL_TIME = PARAM + "%f";
+string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL;
+string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL;
+
+//
+// Tool change
+//
+string TOOL_CODE = "T%02d ";
+string TOOL_MM_FORMAT = "%1.3fmm";
+string TOOL_INCH_FORMAT = "%1.4fin";
+string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL;
+
+string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN +
+ " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count)
+{
+ string formatted;
+
+ sprintf(formatted, COMMENT_BEGIN + " " +
+ TOOL_CODE + "| " + TOOL_MM_FORMAT + " " +
+ TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " +
+ TOOL_INCH_FORMAT + " | " +
+ " %4d" + " " +
+ COMMENT_END + EOL,
+ tool_number, size_mm, size_inch, min_drill, max_drill, count);
+ return(formatted);
+}
+
+//
+// Circles / Arcs
+//
+string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL;
+string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL;
+
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/rakefile.rb b/trunk/ulp/pcb-gcode-3.6.0.4/rakefile.rb
new file mode 100644
index 00000000..4d88ca6b
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/rakefile.rb
@@ -0,0 +1,82 @@
+# _*_ Mode: Ruby -*-
+#
+# Rakefile for pcb-gcode.
+#
+require 'pp'
+require 'rake/clean'
+
+# this will be improved later
+PCB_GCODE_VERSION = "3.6.0.4"
+
+RELEASE_FILE = "~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip"
+
+ignore_files = ['pcb_gcode_is_setup', '*.old', 'storage.nv',
+ 'make/*', 'make', 'make/',
+ '*.b#*', '*.s#*', '*.l#*',
+ '*.DS_Store', 'optomize_me.txt',
+ '*.svn*',
+ 'docs/pcbgcode.aux', 'docs/pcbgcode.glo', 'docs/pcbgcode.gls', 'docs/pcbgcode.idx',
+ 'docs/pcbgcode.ilg', 'docs/pcbgcode.ind', 'docs/pcbgcode.lof', 'docs/pcbgcode.log',
+ 'docs/pcbgcode.lot', 'docs/pcbgcode.out', 'docs/pcbgcode.toc',
+ 'docs/figs/*'
+]
+
+desc "Build the docs/pcbgcode.pdf file."
+file 'docs/pcbgcode.pdf' => 'docs/pcbgcode.tex' do |t|
+ system "cd docs && pdflatex pcbgcode"
+ system "cd docs && makeindex pcbgcode"
+ system "cd docs && pdflatex pcbgcode"
+ system "cd docs && pdflatex pcbgcode"
+end
+
+desc "Create the .zip file to be released."
+task :release_file do
+ zip_cmd = "rm ../pcb-gcode-#{PCB_GCODE_VERSION}.zip"
+ system(zip_cmd)
+ zip_cmd = "zip -r ../pcb-gcode-#{PCB_GCODE_VERSION}.zip *"
+ zip_cmd += ' -x '
+ zip_cmd += ignore_files.join(' -x ')
+ system(zip_cmd)
+ zip_cmd = "unzip ../pcb-gcode-#{PCB_GCODE_VERSION} -d ../pcb-gcode-#{PCB_GCODE_VERSION}"
+ system(zip_cmd)
+ zip_cmd = "rm ~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip"
+ system(zip_cmd)
+ zip_cmd = "cd .. && zip -r ~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip pcb-gcode-#{PCB_GCODE_VERSION}"
+ system(zip_cmd)
+end
+
+desc "Copy current settings/* files to the safe_options folder."
+task :safe_options do
+ SAFE_OPTIONS = ['pcb-defaults', 'pcb-machine', 'pcb-gcode-options', 'user-gcode']
+ SAFE_OPTIONS.each do |name|
+ cp 'settings/' + name + '.h', 'safe_options/' + name + '.release.h'
+ end
+end
+
+desc "Recreate data folders for viewers. Usually after re-exporting from Processing."
+task :fix_viewers do
+ system("cp -R viewer/data viewer/applet")
+ system("cp -R viewer/data viewer/application.linux/")
+ system("cp -R viewer/data viewer/application.macosx/")
+ system("cp -R viewer/data viewer/application.windows/")
+end
+
+desc "Write the convert units function in pcb-gcode-setup.ulp."
+task :write_convert_units do
+ system("make/write_convert_units.rb")
+end
+
+desc "Be sure the build isn't happening from a working svn directory."
+task :check_svn do
+ if File.exist?('.svn')
+ abort("Cannot build with .svn files present.")
+ end
+end
+
+CLOBBER.include('docs/pcbgcode.aux', 'docs/pcbgcode.glo', 'docs/pcbgcode.gls', 'docs/pcbgcode.idx',
+ 'docs/pcbgcode.ilg', 'docs/pcbgcode.ind', 'docs/pcbgcode.lof', 'docs/pcbgcode.log',
+ 'docs/pcbgcode.lot', 'docs/pcbgcode.out', 'docs/pcbgcode.toc'
+)
+
+task :default => [:check_svn, 'docs/pcbgcode.pdf', :fix_viewers, :safe_options, :write_convert_units, :release_file] do
+end
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.h
new file mode 100644
index 00000000..f532f869
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.h
@@ -0,0 +1,38 @@
+//
+// Default values for generating gcode from a PCB.
+//
+// These settings were last changed with pcb-gcode-setup: 2/8/09 5:28 PM
+//
+//
+// Changes you make in this file will be overwritten if you use pcb-gcode-setup.
+//
+
+real ISO_MIN = 0.001000;
+real ISO_MAX = 0.020000;
+real ISO_STEP = 0.005000;
+
+int GENERATE_TOP_OUTLINES = NO;
+int GENERATE_TOP_DRILL = NO;
+int GENERATE_TOP_FILL = NO;
+
+int GENERATE_BOTTOM_OUTLINES = YES;
+int GENERATE_BOTTOM_DRILL = YES;
+int GENERATE_BOTTOM_FILL = NO;
+int MIRROR_BOTTOM = NO;
+int SIMPLE_DRILL_CODE = YES;
+
+int GENERATE_MILLING = NO;
+
+int GENERATE_TEXT = NO;
+
+int SPOT_DRILL = YES;
+real SPOT_DRILL_DEPTH = -0.011000;
+
+int DO_TOOL_CHANGE_WITH_ZERO_STEP = NO;
+
+int FLIP_BOARD_IN_Y = NO;
+
+//int OUTPUT_UNITS = U_MICRONS;
+//int OUTPUT_UNITS = U_MILLIMETERS;
+//int OUTPUT_UNITS = U_MILS;
+int OUTPUT_UNITS = U_INCHES;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.release.h
new file mode 100644
index 00000000..80fcc9e1
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.release.h
@@ -0,0 +1,39 @@
+//
+// Default values for generating gcode from a PCB.
+//
+// These settings were last changed with pcb-gcode-setup: 12/28/12 11:21 PM
+//
+//
+// Changes you make in this file will be overwritten if you use pcb-gcode-setup.
+//
+
+int SINGLE_PASS = NO;
+real ISO_MIN = 0.001000;
+real ISO_MAX = 0.020000;
+real ISO_STEP = 0.005000;
+
+int GENERATE_TOP_OUTLINES = NO;
+int GENERATE_TOP_DRILL = NO;
+int GENERATE_TOP_FILL = NO;
+
+int GENERATE_BOTTOM_OUTLINES = YES;
+int GENERATE_BOTTOM_DRILL = YES;
+int GENERATE_BOTTOM_FILL = NO;
+int MIRROR_BOTTOM = NO;
+int SIMPLE_DRILL_CODE = NO;
+
+int GENERATE_MILLING = NO;
+
+int GENERATE_TEXT = NO;
+
+int SPOT_DRILL = YES;
+real SPOT_DRILL_DEPTH = -0.011000;
+
+int DO_TOOL_CHANGE_WITH_ZERO_STEP = YES;
+
+int FLIP_BOARD_IN_Y = NO;
+
+//int OUTPUT_UNITS = U_MICRONS;
+//int OUTPUT_UNITS = U_MILLIMETERS;
+//int OUTPUT_UNITS = U_MILS;
+int OUTPUT_UNITS = U_INCHES;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.h
new file mode 100644
index 00000000..e07e6cb5
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.h
@@ -0,0 +1,34 @@
+//
+// General Options // Your edits to this file will be overwritten by the setup program.
+//
+int SHOW_PROGRESS = NO;
+string RESTORE_MENU_FILE = "pcb-gcode-menu.scr";
+int NC_FILE_COMMENT_FROM_BOARD = YES;
+int NC_FILE_COMMENT_DATE = YES;
+int NC_FILE_COMMENT_MACHINE_SETTINGS = NO;
+int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = NO;
+int USER_GCODE = NO;
+int g_debug_flag = NO;
+int COMPACT_GCODE = NO;
+int USE_LINE_NUMBERS = NO;
+string LINE_NUMBER_FORMAT = "N%05d ";
+int SHOW_PREVIEW = YES;
+string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME";
+string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_FILL_FILE = "";
+string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_FILL_FILE = "";
+string ETCH_FILE_NAME = "etch";
+string DRILL_FILE_NAME = "drill";
+string MILL_FILE_NAME = "mill";
+string TEXT_FILE_NAME = "text";
+string TOP_FILE_NAME = "top";
+string BOT_FILE_NAME = "bot";
+string DEFAULT_EXTENSION = "tap";
+string DEFAULT_DRILL_FILE = "";
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.release.h
new file mode 100644
index 00000000..a173fe4c
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.release.h
@@ -0,0 +1,34 @@
+//
+// General Options // Your edits to this file will be overwritten by the setup program.
+//
+int SHOW_PROGRESS = NO;
+string RESTORE_MENU_FILE = "pcb-gcode-menu.scr";
+int NC_FILE_COMMENT_FROM_BOARD = YES;
+int NC_FILE_COMMENT_DATE = YES;
+int NC_FILE_COMMENT_MACHINE_SETTINGS = YES;
+int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = YES;
+int USER_GCODE = NO;
+int g_debug_flag = YES;
+int COMPACT_GCODE = NO;
+int USE_LINE_NUMBERS = NO;
+string LINE_NUMBER_FORMAT = "N%05d ";
+int SHOW_PREVIEW = YES;
+string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME";
+string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_FILL_FILE = "";
+string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_FILL_FILE = "";
+string ETCH_FILE_NAME = "etch";
+string DRILL_FILE_NAME = "drill";
+string MILL_FILE_NAME = "mill";
+string TEXT_FILE_NAME = "text";
+string TOP_FILE_NAME = "top";
+string BOT_FILE_NAME = "bot";
+string DEFAULT_EXTENSION = "tap";
+string DEFAULT_DRILL_FILE = "";
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.h
new file mode 100644
index 00000000..e8b8e040
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.h
@@ -0,0 +1,24 @@
+//
+// For ease of use, and to avoid overwritting your settings,
+// use pcb-gcode-setup to make changes to these settings.
+//
+
+real DEFAULT_Z_HIGH = 0.500000;
+real DEFAULT_Z_UP = 0.100000;
+real DEFAULT_Z_DOWN = -0.007000;
+real DRILL_DEPTH = -0.032000;
+real DRILL_DWELL = 1.000000;
+real SPINDLE_ON_TIME = 3.000000;
+real MILLING_DEPTH = -0.010000;
+real TEXT_DEPTH = -0.005000;
+real TOOL_CHANGE_POS_X = 0.000000;
+real TOOL_CHANGE_POS_Y = 0.000000;
+real TOOL_CHANGE_POS_Z = 0.000000;
+real FEED_RATE = 20.000000;
+real FEED_RATE_Z = 10.000000;
+real DEFAULT_WIDTH = 0.007000;
+real X_OFFSET = 0.000000;
+real Y_OFFSET = 0.000000;
+real X_HOME = 0.000000;
+real Y_HOME = 0.000000;
+real EPSILON = 0.000100;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.release.h
new file mode 100644
index 00000000..309340e2
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.release.h
@@ -0,0 +1,24 @@
+//
+// For ease of use, and to avoid overwritting your settings,
+// use pcb-gcode-setup to make changes to these settings.
+//
+
+real DEFAULT_Z_HIGH = 0.500000;
+real DEFAULT_Z_UP = 0.100000;
+real DEFAULT_Z_DOWN = -0.007000;
+real DRILL_DEPTH = -0.032000;
+real DRILL_DWELL = 1.000000;
+real SPINDLE_ON_TIME = 3.000000;
+real MILLING_DEPTH = -0.010000;
+real TEXT_DEPTH = -0.005000;
+real TOOL_CHANGE_POS_X = 0.500000;
+real TOOL_CHANGE_POS_Y = 0.600000;
+real TOOL_CHANGE_POS_Z = 1.000000;
+real FEED_RATE = 20.000000;
+real FEED_RATE_Z = 10.000000;
+real DEFAULT_WIDTH = 0.007000;
+real X_OFFSET = 0.000000;
+real Y_OFFSET = 0.000000;
+real X_HOME = 0.000000;
+real Y_HOME = 0.000000;
+real EPSILON = 0.000100;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.h
new file mode 100644
index 00000000..564cfe5c
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.h
@@ -0,0 +1,236 @@
+//
+// Define your own gcode sequences in this file.
+//
+// The settings are listed from most general, to most specific. The settings
+// at the top of this file go into every file created, while the settings
+// at the end of this file have to do with tool changes only.
+//
+// Note that each line ends with \n this is Geek Speak for newline.
+// In other words, it's like hitting the Enter key at the end of a line.
+// Notice also that the lines have a ; at the end.
+//
+// See the bottom of this file for an example of using multiple lines.
+//
+
+// Inserted into bottom, top or all files.
+string FILE_BEGIN[] = { "", "", "", "" };
+string FILE_END[] = { "", "", "", "" };
+
+FILE_BEGIN[ALL] = "(Beginning of every file)\n";
+FILE_END[ALL] = "(End of every file)\n";
+
+FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n";
+FILE_END[BOTTOM] = "(End of every bottom file)\n";
+
+FILE_BEGIN[TOP] = "(Beginning of every top file)\n";
+FILE_END[TOP] = "(End of every top file)\n";
+
+// Inserted into outline files (track milling).
+string OUTLINE_BEGIN[] = { "", "", "", "" };
+string OUTLINE_BETWEEN[] = { "", "", "", "" };
+string OUTLINE_END[] = { "", "", "", "" };
+
+OUTLINE_BEGIN[ALL] = "(Outline Begin)\n";
+OUTLINE_BETWEEN[ALL] = "(Between Passes)\n";
+OUTLINE_END[ALL] = "(Outline End)\n";
+
+OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n";
+OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n";
+OUTLINE_END[BOTTOM] = "(Bottom outline End)\n";
+
+OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n";
+OUTLINE_BETWEEN[TOP] = "(Top between passes)\n";
+OUTLINE_END[TOP] = "(Top outline End)\n";
+
+// Inserted into drill files.
+string DRILL_BEGIN[] = { "", "", "", "" };
+string DRILL_END[] = { "", "", "", "" };
+
+DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n";
+DRILL_END[ALL] = "(End of all Drill Files)\n";
+
+DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n";
+DRILL_END[BOTTOM] = "(Bottom Drill End)\n";
+
+DRILL_BEGIN[TOP] = "(Top Drill Begin)\n";
+DRILL_END[TOP] = "(Top Drill End)\n";
+
+// Inserted into fill files.
+string FILL_BEGIN[] = { "", "", "", "" };
+string FILL_END[] = { "", "", "", "" };
+
+FILL_BEGIN[ALL] = "(Fill Begin)\n";
+FILL_END[ALL] = "(Fill End)\n";
+
+FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n";
+FILL_END[BOTTOM] = "(Bottom Fill End)\n";
+
+FILL_BEGIN[TOP] = "(Top Fill Begin)\n";
+FILL_END[TOP] = "(Top Fill End)\n";
+
+// Inserted into milling files.
+string MILL_BEGIN[] = { "", "", "", "" };
+string MILL_END[] = { "", "", "", "" };
+
+MILL_BEGIN[ALL] = "(MILL Begin)\n";
+MILL_END[ALL] = "(MILL End)\n";
+
+MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n";
+MILL_END[BOTTOM] = "(Bottom MILL End)\n";
+
+MILL_BEGIN[TOP] = "(Top MILL Begin)\n";
+MILL_END[TOP] = "(Top MILL End)\n";
+
+// Tool change code.
+string TOOL_CHANGE_BEGIN[] = { "", "", "", "" };
+string TOOL_CHANGED[] = { "", "", "", "" };
+string TOOL_ZERO_BEGIN[] = { "", "", "", "" };
+string TOOL_ZERO_END[] = { "", "", "", "" };
+string TOOL_CHANGE_END[] = { "", "", "", "" };
+
+TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n";
+TOOL_CHANGED[ALL] = "(Tool changed)\n";
+TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n";
+TOOL_ZERO_END[ALL] = "(Tool zero end)\n";
+TOOL_CHANGE_END[ALL] = "(Tool Change End)\n";
+
+TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n";
+TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n";
+TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n";
+TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n";
+TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n";
+
+TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n";
+TOOL_CHANGED[TOP] = "(Top Tool changed)\n";
+TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n";
+TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n";
+TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n";
+
+//
+// An example of using more than one line of gcode.
+// Note that only the last line has a ; at the end.
+//
+string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this
+THIS_ISNT_USED[BOTTOM] = "G20\n"
+ "G90\n"
+ "G01 Z0\n"
+ "G00 X0 Y0\n"
+ "M06 T2 ; 0.060\n"
+ "G04 P5\n";
+
+/*
+ * The functions below should make it easier for folks outputing their own code, etc.
+ *
+ */
+
+/*
+ * Called after the gcode file has been opened.
+ * Mode can be
+ * "wt" (write a text file) when the file is first opened.
+ * "at" (append a text file) if the file is added to.
+ *
+ * You might want to check g_side to see which "side" you are working on.
+ * g_side can be TOP, BOTTOM or MILL.
+ *
+ */
+void user_file_opened(string name, string mode)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * Just before the gcode file is closed.
+ *
+ */
+void user_file_closing()
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * Just after the gcode file is closed.
+ * See user_file_opened for information on the mode parameter.
+ *
+ */
+void user_file_closed(string name, string mode)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The beginning of the outline of a track.
+ *
+ */
+void user_track_begin(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * An intermediate point on the outline of a track.
+ *
+ */
+int user_coord_cnt;
+void user_track_continue(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The end of the outline of a track.
+ *
+ */
+void user_track_end(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The beginning of an arc.
+ *
+ */
+void user_arc_begin(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The end of an arc.
+ *
+ */
+void user_arc_end(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.release.h
new file mode 100644
index 00000000..564cfe5c
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.release.h
@@ -0,0 +1,236 @@
+//
+// Define your own gcode sequences in this file.
+//
+// The settings are listed from most general, to most specific. The settings
+// at the top of this file go into every file created, while the settings
+// at the end of this file have to do with tool changes only.
+//
+// Note that each line ends with \n this is Geek Speak for newline.
+// In other words, it's like hitting the Enter key at the end of a line.
+// Notice also that the lines have a ; at the end.
+//
+// See the bottom of this file for an example of using multiple lines.
+//
+
+// Inserted into bottom, top or all files.
+string FILE_BEGIN[] = { "", "", "", "" };
+string FILE_END[] = { "", "", "", "" };
+
+FILE_BEGIN[ALL] = "(Beginning of every file)\n";
+FILE_END[ALL] = "(End of every file)\n";
+
+FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n";
+FILE_END[BOTTOM] = "(End of every bottom file)\n";
+
+FILE_BEGIN[TOP] = "(Beginning of every top file)\n";
+FILE_END[TOP] = "(End of every top file)\n";
+
+// Inserted into outline files (track milling).
+string OUTLINE_BEGIN[] = { "", "", "", "" };
+string OUTLINE_BETWEEN[] = { "", "", "", "" };
+string OUTLINE_END[] = { "", "", "", "" };
+
+OUTLINE_BEGIN[ALL] = "(Outline Begin)\n";
+OUTLINE_BETWEEN[ALL] = "(Between Passes)\n";
+OUTLINE_END[ALL] = "(Outline End)\n";
+
+OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n";
+OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n";
+OUTLINE_END[BOTTOM] = "(Bottom outline End)\n";
+
+OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n";
+OUTLINE_BETWEEN[TOP] = "(Top between passes)\n";
+OUTLINE_END[TOP] = "(Top outline End)\n";
+
+// Inserted into drill files.
+string DRILL_BEGIN[] = { "", "", "", "" };
+string DRILL_END[] = { "", "", "", "" };
+
+DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n";
+DRILL_END[ALL] = "(End of all Drill Files)\n";
+
+DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n";
+DRILL_END[BOTTOM] = "(Bottom Drill End)\n";
+
+DRILL_BEGIN[TOP] = "(Top Drill Begin)\n";
+DRILL_END[TOP] = "(Top Drill End)\n";
+
+// Inserted into fill files.
+string FILL_BEGIN[] = { "", "", "", "" };
+string FILL_END[] = { "", "", "", "" };
+
+FILL_BEGIN[ALL] = "(Fill Begin)\n";
+FILL_END[ALL] = "(Fill End)\n";
+
+FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n";
+FILL_END[BOTTOM] = "(Bottom Fill End)\n";
+
+FILL_BEGIN[TOP] = "(Top Fill Begin)\n";
+FILL_END[TOP] = "(Top Fill End)\n";
+
+// Inserted into milling files.
+string MILL_BEGIN[] = { "", "", "", "" };
+string MILL_END[] = { "", "", "", "" };
+
+MILL_BEGIN[ALL] = "(MILL Begin)\n";
+MILL_END[ALL] = "(MILL End)\n";
+
+MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n";
+MILL_END[BOTTOM] = "(Bottom MILL End)\n";
+
+MILL_BEGIN[TOP] = "(Top MILL Begin)\n";
+MILL_END[TOP] = "(Top MILL End)\n";
+
+// Tool change code.
+string TOOL_CHANGE_BEGIN[] = { "", "", "", "" };
+string TOOL_CHANGED[] = { "", "", "", "" };
+string TOOL_ZERO_BEGIN[] = { "", "", "", "" };
+string TOOL_ZERO_END[] = { "", "", "", "" };
+string TOOL_CHANGE_END[] = { "", "", "", "" };
+
+TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n";
+TOOL_CHANGED[ALL] = "(Tool changed)\n";
+TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n";
+TOOL_ZERO_END[ALL] = "(Tool zero end)\n";
+TOOL_CHANGE_END[ALL] = "(Tool Change End)\n";
+
+TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n";
+TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n";
+TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n";
+TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n";
+TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n";
+
+TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n";
+TOOL_CHANGED[TOP] = "(Top Tool changed)\n";
+TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n";
+TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n";
+TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n";
+
+//
+// An example of using more than one line of gcode.
+// Note that only the last line has a ; at the end.
+//
+string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this
+THIS_ISNT_USED[BOTTOM] = "G20\n"
+ "G90\n"
+ "G01 Z0\n"
+ "G00 X0 Y0\n"
+ "M06 T2 ; 0.060\n"
+ "G04 P5\n";
+
+/*
+ * The functions below should make it easier for folks outputing their own code, etc.
+ *
+ */
+
+/*
+ * Called after the gcode file has been opened.
+ * Mode can be
+ * "wt" (write a text file) when the file is first opened.
+ * "at" (append a text file) if the file is added to.
+ *
+ * You might want to check g_side to see which "side" you are working on.
+ * g_side can be TOP, BOTTOM or MILL.
+ *
+ */
+void user_file_opened(string name, string mode)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * Just before the gcode file is closed.
+ *
+ */
+void user_file_closing()
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * Just after the gcode file is closed.
+ * See user_file_opened for information on the mode parameter.
+ *
+ */
+void user_file_closed(string name, string mode)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The beginning of the outline of a track.
+ *
+ */
+void user_track_begin(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * An intermediate point on the outline of a track.
+ *
+ */
+int user_coord_cnt;
+void user_track_continue(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The end of the outline of a track.
+ *
+ */
+void user_track_end(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The beginning of an arc.
+ *
+ */
+void user_arc_begin(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The end of an arc.
+ *
+ */
+void user_arc_end(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/default.drl.txt b/trunk/ulp/pcb-gcode-3.6.0.4/settings/default.drl.txt
new file mode 100644
index 00000000..537f1f02
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/default.drl.txt
@@ -0,0 +1,27 @@
+# -*- Mode: Eagle -*-
+#
+# Sample drill rack file.
+#
+# drill_size is the size of the drill bit.
+# minimum is the smallest hole the bit will be used for.
+# maximum is the largest hole the bit will be used for.
+#
+# Each value can have a "unit of measure" added to it,
+# such as 0.500mm . If you do not provide the unit of measure,
+# values over 0.250 are considered millimeters, and
+# values under 0.250 are considered inches. For example:
+# 0.400 would be considered 0.400 mm.
+# 0.125 would be considered 0.125 inches.
+#
+# Please note that you must use a TAB character
+# between each setting on a line.
+#
+# Tip: Set the TAB size of your editor to 12 characters.
+#
+tool drill_size minimum maximum length
+T01 0.500mm 0.000in 0.025in 1.5in
+T02 0.032in 0.025in 0.035in 1.5in
+T03 0.040in 0.035in 0.039in 1.5in
+T04 0.050in 0.045in 0.055in 1.5in
+T05 0.062in 0.055in 0.070in 1.5in
+T06 0.125in 0.100in 0.125in 1.5in
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/gcode-defaults.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/gcode-defaults.h
new file mode 100644
index 00000000..fdef4222
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/gcode-defaults.h
@@ -0,0 +1,126 @@
+//
+// Options for pcb-gcode.ulp.
+// Often used options are at the top of the file.
+// Copied to gcode-defaults.h by the setup program.
+
+//
+// author=John Johnson
+// description=Mach3 - EMC for Windows
+//
+
+int FILENAMES_8_CHARACTERS = NO;
+
+//
+// Comments.
+//
+string COMMENT_BEGIN = "(";
+string COMMENT_END = ")";
+
+//
+// Format strings for coordinates, etc.
+//
+string EOL = "\n"; /* standard line ending */
+string PARAM = "P"; /* some use P, some # for parameters */
+string FORMAT = "%-7.4f "; /* coordinate format */
+string FR_FORMAT = "F%-5.0f "; /* feedrate format */
+string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT;
+
+//
+// Modes
+//
+string INCH_MODE = "G20" + EOL;
+string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL;
+string METRIC_MODE = "G21" + EOL;
+string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL;
+string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL;
+string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL;
+string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL;
+
+//
+// G codes
+//
+string RAPID = "G00 ";
+string FEED = "G01 ";
+string ARC_CW = "G02 ";
+string ARC_CCW = "G03 ";
+string DWELL = "G04 " + PARAM + "%f" + EOL;
+
+//
+// M codes
+//
+string SPINDLE_ON = "M03" + EOL + DWELL;
+string SPINDLE_OFF = "M05" + EOL;
+string END_PROGRAM = "M02" + EOL;
+string OPERATOR_PAUSE = "M06 ";
+
+//
+// Coordinates
+//
+string MOVE_X = "X" + FORMAT;
+string MOVE_Y = "Y" + FORMAT;
+string MOVE_XY = "X" + FORMAT + "Y" + FORMAT;
+string MOVE_Z = "Z" + FORMAT;
+string MOVE_XYZ = MOVE_XY + MOVE_Z;
+
+//
+// Rapids
+//
+string RAPID_MOVE_X = RAPID + MOVE_X;
+string RAPID_MOVE_Y = RAPID + MOVE_Y;
+string RAPID_MOVE_XY = RAPID + MOVE_XY;
+string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0";
+string RAPID_MOVE_Z = RAPID + MOVE_Z;
+string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ;
+
+//
+// Feeds
+//
+string FEED_MOVE_X = FEED + MOVE_X;
+string FEED_MOVE_Y = FEED + MOVE_Y;
+string FEED_MOVE_XY = FEED + MOVE_XY;
+string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT;
+string FEED_MOVE_Z = FEED + MOVE_Z;
+string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT;
+string FEED_MOVE_XYZ = FEED + MOVE_XYZ;
+
+//
+// Drilling holes
+//
+// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell
+//
+string DRILL_CODE = "G82 ";
+string RELEASE_PLANE = "R" + FORMAT;
+string DWELL_TIME = PARAM + "%f";
+string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL;
+string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL;
+
+//
+// Tool change
+//
+string TOOL_CODE = "T%02d ";
+string TOOL_MM_FORMAT = "%1.3fmm";
+string TOOL_INCH_FORMAT = "%1.4fin";
+string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL;
+
+string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN +
+ " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL;
+
+string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count)
+{
+ string formatted;
+
+ sprintf(formatted, COMMENT_BEGIN + " " +
+ TOOL_CODE + "| " + TOOL_MM_FORMAT + " " +
+ TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " +
+ TOOL_INCH_FORMAT + " | " +
+ " %4d" + " " +
+ COMMENT_END + EOL,
+ tool_number, size_mm, size_inch, min_drill, max_drill, count);
+ return(formatted);
+}
+
+//
+// Circles / Arcs
+//
+string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL;
+string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-defaults.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-defaults.h
new file mode 100644
index 00000000..80fcc9e1
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-defaults.h
@@ -0,0 +1,39 @@
+//
+// Default values for generating gcode from a PCB.
+//
+// These settings were last changed with pcb-gcode-setup: 12/28/12 11:21 PM
+//
+//
+// Changes you make in this file will be overwritten if you use pcb-gcode-setup.
+//
+
+int SINGLE_PASS = NO;
+real ISO_MIN = 0.001000;
+real ISO_MAX = 0.020000;
+real ISO_STEP = 0.005000;
+
+int GENERATE_TOP_OUTLINES = NO;
+int GENERATE_TOP_DRILL = NO;
+int GENERATE_TOP_FILL = NO;
+
+int GENERATE_BOTTOM_OUTLINES = YES;
+int GENERATE_BOTTOM_DRILL = YES;
+int GENERATE_BOTTOM_FILL = NO;
+int MIRROR_BOTTOM = NO;
+int SIMPLE_DRILL_CODE = NO;
+
+int GENERATE_MILLING = NO;
+
+int GENERATE_TEXT = NO;
+
+int SPOT_DRILL = YES;
+real SPOT_DRILL_DEPTH = -0.011000;
+
+int DO_TOOL_CHANGE_WITH_ZERO_STEP = YES;
+
+int FLIP_BOARD_IN_Y = NO;
+
+//int OUTPUT_UNITS = U_MICRONS;
+//int OUTPUT_UNITS = U_MILLIMETERS;
+//int OUTPUT_UNITS = U_MILS;
+int OUTPUT_UNITS = U_INCHES;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-gcode-options.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-gcode-options.h
new file mode 100644
index 00000000..a173fe4c
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-gcode-options.h
@@ -0,0 +1,34 @@
+//
+// General Options // Your edits to this file will be overwritten by the setup program.
+//
+int SHOW_PROGRESS = NO;
+string RESTORE_MENU_FILE = "pcb-gcode-menu.scr";
+int NC_FILE_COMMENT_FROM_BOARD = YES;
+int NC_FILE_COMMENT_DATE = YES;
+int NC_FILE_COMMENT_MACHINE_SETTINGS = YES;
+int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = YES;
+int USER_GCODE = NO;
+int g_debug_flag = YES;
+int COMPACT_GCODE = NO;
+int USE_LINE_NUMBERS = NO;
+string LINE_NUMBER_FORMAT = "N%05d ";
+int SHOW_PREVIEW = YES;
+string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME";
+string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_TOP_FILL_FILE = "";
+string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT";
+string FILENAME_BOT_FILL_FILE = "";
+string ETCH_FILE_NAME = "etch";
+string DRILL_FILE_NAME = "drill";
+string MILL_FILE_NAME = "mill";
+string TEXT_FILE_NAME = "text";
+string TOP_FILE_NAME = "top";
+string BOT_FILE_NAME = "bot";
+string DEFAULT_EXTENSION = "tap";
+string DEFAULT_DRILL_FILE = "";
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-machine.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-machine.h
new file mode 100644
index 00000000..309340e2
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-machine.h
@@ -0,0 +1,24 @@
+//
+// For ease of use, and to avoid overwritting your settings,
+// use pcb-gcode-setup to make changes to these settings.
+//
+
+real DEFAULT_Z_HIGH = 0.500000;
+real DEFAULT_Z_UP = 0.100000;
+real DEFAULT_Z_DOWN = -0.007000;
+real DRILL_DEPTH = -0.032000;
+real DRILL_DWELL = 1.000000;
+real SPINDLE_ON_TIME = 3.000000;
+real MILLING_DEPTH = -0.010000;
+real TEXT_DEPTH = -0.005000;
+real TOOL_CHANGE_POS_X = 0.500000;
+real TOOL_CHANGE_POS_Y = 0.600000;
+real TOOL_CHANGE_POS_Z = 1.000000;
+real FEED_RATE = 20.000000;
+real FEED_RATE_Z = 10.000000;
+real DEFAULT_WIDTH = 0.007000;
+real X_OFFSET = 0.000000;
+real Y_OFFSET = 0.000000;
+real X_HOME = 0.000000;
+real Y_HOME = 0.000000;
+real EPSILON = 0.000100;
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/user-gcode.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/user-gcode.h
new file mode 100644
index 00000000..564cfe5c
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/user-gcode.h
@@ -0,0 +1,236 @@
+//
+// Define your own gcode sequences in this file.
+//
+// The settings are listed from most general, to most specific. The settings
+// at the top of this file go into every file created, while the settings
+// at the end of this file have to do with tool changes only.
+//
+// Note that each line ends with \n this is Geek Speak for newline.
+// In other words, it's like hitting the Enter key at the end of a line.
+// Notice also that the lines have a ; at the end.
+//
+// See the bottom of this file for an example of using multiple lines.
+//
+
+// Inserted into bottom, top or all files.
+string FILE_BEGIN[] = { "", "", "", "" };
+string FILE_END[] = { "", "", "", "" };
+
+FILE_BEGIN[ALL] = "(Beginning of every file)\n";
+FILE_END[ALL] = "(End of every file)\n";
+
+FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n";
+FILE_END[BOTTOM] = "(End of every bottom file)\n";
+
+FILE_BEGIN[TOP] = "(Beginning of every top file)\n";
+FILE_END[TOP] = "(End of every top file)\n";
+
+// Inserted into outline files (track milling).
+string OUTLINE_BEGIN[] = { "", "", "", "" };
+string OUTLINE_BETWEEN[] = { "", "", "", "" };
+string OUTLINE_END[] = { "", "", "", "" };
+
+OUTLINE_BEGIN[ALL] = "(Outline Begin)\n";
+OUTLINE_BETWEEN[ALL] = "(Between Passes)\n";
+OUTLINE_END[ALL] = "(Outline End)\n";
+
+OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n";
+OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n";
+OUTLINE_END[BOTTOM] = "(Bottom outline End)\n";
+
+OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n";
+OUTLINE_BETWEEN[TOP] = "(Top between passes)\n";
+OUTLINE_END[TOP] = "(Top outline End)\n";
+
+// Inserted into drill files.
+string DRILL_BEGIN[] = { "", "", "", "" };
+string DRILL_END[] = { "", "", "", "" };
+
+DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n";
+DRILL_END[ALL] = "(End of all Drill Files)\n";
+
+DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n";
+DRILL_END[BOTTOM] = "(Bottom Drill End)\n";
+
+DRILL_BEGIN[TOP] = "(Top Drill Begin)\n";
+DRILL_END[TOP] = "(Top Drill End)\n";
+
+// Inserted into fill files.
+string FILL_BEGIN[] = { "", "", "", "" };
+string FILL_END[] = { "", "", "", "" };
+
+FILL_BEGIN[ALL] = "(Fill Begin)\n";
+FILL_END[ALL] = "(Fill End)\n";
+
+FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n";
+FILL_END[BOTTOM] = "(Bottom Fill End)\n";
+
+FILL_BEGIN[TOP] = "(Top Fill Begin)\n";
+FILL_END[TOP] = "(Top Fill End)\n";
+
+// Inserted into milling files.
+string MILL_BEGIN[] = { "", "", "", "" };
+string MILL_END[] = { "", "", "", "" };
+
+MILL_BEGIN[ALL] = "(MILL Begin)\n";
+MILL_END[ALL] = "(MILL End)\n";
+
+MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n";
+MILL_END[BOTTOM] = "(Bottom MILL End)\n";
+
+MILL_BEGIN[TOP] = "(Top MILL Begin)\n";
+MILL_END[TOP] = "(Top MILL End)\n";
+
+// Tool change code.
+string TOOL_CHANGE_BEGIN[] = { "", "", "", "" };
+string TOOL_CHANGED[] = { "", "", "", "" };
+string TOOL_ZERO_BEGIN[] = { "", "", "", "" };
+string TOOL_ZERO_END[] = { "", "", "", "" };
+string TOOL_CHANGE_END[] = { "", "", "", "" };
+
+TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n";
+TOOL_CHANGED[ALL] = "(Tool changed)\n";
+TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n";
+TOOL_ZERO_END[ALL] = "(Tool zero end)\n";
+TOOL_CHANGE_END[ALL] = "(Tool Change End)\n";
+
+TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n";
+TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n";
+TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n";
+TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n";
+TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n";
+
+TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n";
+TOOL_CHANGED[TOP] = "(Top Tool changed)\n";
+TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n";
+TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n";
+TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n";
+
+//
+// An example of using more than one line of gcode.
+// Note that only the last line has a ; at the end.
+//
+string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this
+THIS_ISNT_USED[BOTTOM] = "G20\n"
+ "G90\n"
+ "G01 Z0\n"
+ "G00 X0 Y0\n"
+ "M06 T2 ; 0.060\n"
+ "G04 P5\n";
+
+/*
+ * The functions below should make it easier for folks outputing their own code, etc.
+ *
+ */
+
+/*
+ * Called after the gcode file has been opened.
+ * Mode can be
+ * "wt" (write a text file) when the file is first opened.
+ * "at" (append a text file) if the file is added to.
+ *
+ * You might want to check g_side to see which "side" you are working on.
+ * g_side can be TOP, BOTTOM or MILL.
+ *
+ */
+void user_file_opened(string name, string mode)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * Just before the gcode file is closed.
+ *
+ */
+void user_file_closing()
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * Just after the gcode file is closed.
+ * See user_file_opened for information on the mode parameter.
+ *
+ */
+void user_file_closed(string name, string mode)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The beginning of the outline of a track.
+ *
+ */
+void user_track_begin(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * An intermediate point on the outline of a track.
+ *
+ */
+int user_coord_cnt;
+void user_track_continue(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The end of the outline of a track.
+ *
+ */
+void user_track_end(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The beginning of an arc.
+ *
+ */
+void user_arc_begin(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
+
+/*
+ * The end of an arc.
+ *
+ */
+void user_arc_end(real start_x, real start_y, real end_x, real end_y)
+{
+ if (USER_GCODE == NO) {
+ return;
+ }
+
+ // your code here
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/drill.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/drill.h
new file mode 100644
index 00000000..9d31bb0f
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/drill.h
@@ -0,0 +1,193 @@
+// -*- Mode: Eagle -*-
+//
+// Drill routines.
+//
+
+#include "nonvolatile.h"
+
+string TOOL_FLD = "tool";
+string DRILL_FLD = "drill_size";
+string MIN_FLD = "minimum";
+string MAX_FLD = "maximum";
+string LENGTH_FLD = "length";
+char DRILL_SEP = '\t';
+string g_rack[];
+int g_num_drills;
+int g_drill_sub_cnt[];
+real g_mins[];
+real g_maxs[];
+
+int m_shut_up;
+int m_last_match;
+int m_have_rack = false;
+string m_rack_file_name = "?";
+
+if (get_nv_param("drill_shut_up", "NO", NO) == "YES") {
+ m_shut_up = YES;
+}
+else {
+ m_shut_up = NO;
+}
+
+void message(string msg)
+{
+ if(m_shut_up)
+ return;
+
+ msg = "Rack file: " + elided_path(m_rack_file_name, 30) + ":\n" + msg;
+
+ switch(dlgMessageBox(msg, "Ok", "Shut up already", "Never ask again")) {
+ case 1:
+ m_shut_up = 1;
+ break;
+ case 2:
+ m_shut_up = 1;
+ set_nv_param("drill_shut_up", "YES");
+ break;
+ }
+}
+
+void read_rack_file(string drill_file)
+{
+ string VALID_DRILL_CHARS = "#+-.0123456789imntT\t";
+
+ string drill_raw[];
+ int num_raw_drills;
+ string key;
+ string temp;
+ string drill_text;
+ int i;
+
+ /*
+ * Remove comment lines from the rack file.
+ *
+ */
+ g_num_drills = 0;
+ num_raw_drills = fileread(drill_raw, drill_file);
+ string first_char;
+ for (i=0; i 0 && DRILL_SIZES_INCHES[i] > inches) {
+ i--;
+ }
+ return i;
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/filecopy.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/filecopy.h
new file mode 100644
index 00000000..7fe5b47b
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/filecopy.h
@@ -0,0 +1,26 @@
+// -*- Mode: Eagle -*-
+void filecopy(string from_name, string to_name)
+{
+ string contents[];
+ int num_lines;
+
+ fileerror();
+ num_lines = fileread(contents, from_name);
+
+ if(fileerror()) {
+ dlgMessageBox("Error: Could not open " + from_name
+ + " for copying to " + to_name);
+ exit(1);
+ }
+
+ output(to_name) {
+ for (int i=0; i < num_lines; i++) {
+ printf("%s\n", contents[i]);
+ }
+ }
+ if(fileerror()) {
+ dlgMessageBox("Error: Could not write the contents of "
+ + from_name + " to " + to_name);
+ exit(1);
+ }
+}
diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/filename_subs.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/filename_subs.h
new file mode 100644
index 00000000..5e3906f1
--- /dev/null
+++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/filename_subs.h
@@ -0,0 +1,161 @@
+// -*- Mode: Eagle -*-
+
+string FILENAME_SUBS;
+
+//
+// Values to substitute in file names.
+//
+string setup_subs_side_phase(int l_side, int l_phase)
+{
+ string side;
+ string file;
+ string tmp;
+ int i;
+
+ side = (l_side == TOP) ? TOP_FILE_NAME : BOT_FILE_NAME;
+ switch (l_phase) {
+ case PH_TOP_OUT_GEN:
+ case PH_TOP_OUT_WRITE:
+ case PH_BOTTOM_OUT_GEN:
+ case PH_BOTTOM_OUT_WRITE:
+ file = ETCH_FILE_NAME;
+ break;
+ case PH_TOP_DRILL:
+ case PH_BOTTOM_DRILL:
+ file = DRILL_FILE_NAME;
+ break;
+ case PH_MILL:
+ file = MILL_FILE_NAME;
+ break;
+ case PH_TEXT:
+ file = TEXT_FILE_NAME;
+ break;
+ default:
+ file = "invalid";
+ }
+// dlgMessageBox("file = " + ETCH_FILE_NAME);
+// file = PHASE_NAME[l_phase];
+ FILENAME_SUBS = "";
+ i = 0;
+ while (path_epf[i] != "") {
+ sprintf(tmp, "$PROJECT_PATH[%d]", i);
+ FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_epf[i]));
+ sprintf(tmp, "$ULP_PATH[%d]", i);
+ FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_ulp[i]));
+ sprintf(tmp, "$CAM_PATH[%d]", i);
+ FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_cam[i]));
+ i++;
+ }
+ FILENAME_SUBS += key_value_record("$PATH", remove_last_slash(g_path)) +
+ key_value_record("$BOARD_PATH", remove_last_slash(filedir(BOARD_NAME))) +
+ key_value_record("$BOARD_NAME", filesetext(filename(BOARD_NAME), "")) +
+ key_value_record("$BOARD_FILE_PATH", filesetext(BOARD_NAME, "")) +
+ key_value_record("$SIDE", side) +
+ key_value_record("$FILE", file) +
+ key_value_record("$EXT", DEFAULT_EXTENSION)
+ ;
+ return FILENAME_SUBS;
+}
+
+string filename_subs_help()
+{
+ return "
Filename Variables
"
+ "
"
+ "
$PROJECT_PATH[n]
"
+ "
Project paths as set in the Control Panel. "
+ "n begins at zero for the first entry.
"
+ "
$ULP_PATH[n]
"
+ "
As above, but for User Language Program paths.
"
+ "
$CAM_PATH[n]
"
+ "
As above, but for CAM Jobs paths.
"
+ "
$BOARD_PATH
Path to the board file.
"
+ "
$BOARD_NAME
The file name of the board with the extension (.brd) removed.
"
+ "
$BOARD_FILE_PATH
Path and name of the board with the extension (.brd) removed.
"
+ "
$SIDE
Side of the board being generated. By default 'bot' or 'top'.
"
+ "
$FILE
File of the board being generated. By default 'etch', 'drill' and 'mill' or 'text'.
"
+ "
$EXT
The extension you set under the GCode Options tab.
"
+ "
"
+ "Paths do not end with a /. "
+ "Example: "
+ "Assume the board we are working on is: "
+ "/home/john/eagle/my_stuff/enabtmr.brd "
+ "and we use these settings: "
+ "Filename Base: $BOARD_PATH/$BOARD_NAME "
+ "Top (Component) Side Files"
+ "
Copyright 2004-2013 by"
+ " John Johnson Software, LLC.
"
+ "
All Rights Reserved
"
+ "
Version 3.6.0.4
"
+ "
"
+ "
You have EAGLE version " + m_eagle_compatibility + "
"
+ "
");
+ if (program_is_setup()) {
+ dlgLabel("
Your current profile is based on the "
+ + CURRENT_PROFILE[DESCRIPTION] + " profile.
");
+ dlgLabel("
Please use the settings under the tabs to"
+ " customize the gcode that is generated for you.
");
+ }
+ else {
+ dlgLabel("
Welcome!
"
+ "
Since this is the first time you have run this setup"
+ " program, please select the profile that best suits your machine."
+ " Click the Accept button to save your changes.
");
+ }
+// dlgLabel("");
+ }
+
+
+ dlgTabWidget {
+
+ /***************************************************************
+ *
+ * G E N E R A T I O N O P T I O N S
+ *
+ ***************************************************************/
+
+ if (program_is_setup()) dlgTabPage("Generation Options") {
+ dlgHBoxLayout {
+ dlgStretch(20);
+ dlgVBoxLayout {
+ dlgGroup("Top Side") {
+ dlgCheckBox("Generate top outlines", GENERATE_TOP_OUTLINES);
+ dlgCheckBox("Generate top drills ", GENERATE_TOP_DRILL);
+ }
+ dlgStretch(1);
+ }
+ dlgVBoxLayout {
+ dlgGroup("Bottom Side") {
+ dlgCheckBox("Generate bottom outlines",
+ GENERATE_BOTTOM_OUTLINES);
+ dlgCheckBox("Generate bottom drills ",
+ GENERATE_BOTTOM_DRILL);
+ dlgCheckBox("Mirror ",
+ MIRROR_BOTTOM);
+ }
+ dlgStretch(1);
+ dlgLabel("");
+ dlgStretch(3);
+ }
+ dlgVBoxLayout {
+ dlgGroup("Board") {
+ dlgVBoxLayout {
+ dlgCheckBox("Show preview ", SHOW_PREVIEW);
+ dlgGridLayout {
+ dlgCell(0, 0) dlgCheckBox("Generate milling", GENERATE_MILLING);
+ dlgCell(0, 1) dlgLabel("Depth ");
+ dlgCell(0, 2) { dlgRealEdit(MILLING_DEPTH); dlgLabel(m_uom_suffix, YES); }
+
+ dlgCell(1, 0) dlgCheckBox("Generate text", GENERATE_TEXT);
+ dlgCell(1, 1) dlgLabel("Depth ");
+ dlgCell(1, 2) { dlgRealEdit(TEXT_DEPTH); dlgLabel(m_uom_suffix, YES); }
+ dlgCell(2, 0) dlgCheckBox("Spot drill holes", SPOT_DRILL);
+ dlgCell(2, 1) dlgLabel("Depth");
+ dlgCell(2, 2) { dlgRealEdit(SPOT_DRILL_DEPTH); dlgLabel(m_uom_suffix, YES); }
+ }
+ dlgGridLayout {
+ dlgCell(0, 0, 0, 1) dlgLabel("Isolation");
+ dlgCell(0, 1) {
+ dlgCheckBox("Single pass", SINGLE_PASS) {
+ if (SINGLE_PASS) {
+/* dlgMessageBox("You have selected the single pass option.\n" +
+ "The next time you run pcb-gcode-setup, the Maximum and Step Size " +
+ "options will be hidden. Only Minimum will be shown.\n" +
+ "To change back, just turn Single pass off, " +
+ "click Accept, and run pcb-gcode-setup again.\n" +
+ "The minimum, maximum, and step size options will be available again.");
+ */
+ m_maximum_label = "not used";
+ m_step_size_label = "not used";
+ }
+ else {
+ m_maximum_label = "Maximum";
+ m_step_size_label = "Step size";
+ }
+ }
+ }
+ dlgCell(1, 0) dlgLabel("Minimum");
+ dlgCell(1, 1) { dlgRealEdit(ISO_MIN);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(3, 0) dlgLabel(m_maximum_label, YES);
+ dlgCell(3, 1) { dlgRealEdit(ISO_MAX);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(4, 0) dlgLabel(m_step_size_label, YES);
+ dlgCell(4, 1) { dlgRealEdit(ISO_STEP);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ }
+ dlgSpacing(10);
+ dlgVBoxLayout {
+ dlgLabel("Etching Tool Size ");
+ dlgHBoxLayout { dlgRealEdit(DEFAULT_WIDTH);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ }
+ }
+ }
+ dlgStretch(1);
+ }
+ dlgStretch(20);
+ }
+ dlgHBoxLayout {
+ }
+ }
+
+ /***************************************************************
+ *
+ * M A C H I N E
+ *
+ ***************************************************************/
+ if (program_is_setup()) dlgTabPage("Machine") {
+ dlgHBoxLayout {
+ dlgStretch(20);
+ dlgLabel("");
+ dlgGroup("Z Axis") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Z High ");
+ dlgCell(1, 1) {
+ dlgRealEdit(DEFAULT_Z_HIGH);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(2, 0) dlgLabel("Z Up ");
+ dlgCell(2, 1) {
+ dlgRealEdit(DEFAULT_Z_UP);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(3, 0) dlgLabel("Z Down ");
+ dlgCell(3, 1) {
+ dlgRealEdit(DEFAULT_Z_DOWN);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(4, 0) dlgLabel("Drill Depth ");
+ dlgCell(4, 1) {
+ dlgRealEdit(DRILL_DEPTH);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(5, 0) dlgLabel("Drill Dwell ");
+ dlgCell(5, 1) dlgRealEdit(DRILL_DWELL, 0); // DO NOT CONVERT
+ }
+ }
+ dlgGroup("Tool Change") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Position X ");
+ dlgCell(1, 1) { dlgRealEdit(TOOL_CHANGE_POS_X);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(2, 0) dlgLabel("Position Y ");
+ dlgCell(2, 1) { dlgRealEdit(TOOL_CHANGE_POS_Y);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ dlgCell(3, 0) dlgLabel("Position Z ");
+ dlgCell(3, 1) { dlgRealEdit(TOOL_CHANGE_POS_Z);
+ dlgLabel(m_uom_suffix, YES);
+ }
+ }
+ }
+ dlgStretch(20);
+ }
+ dlgHBoxLayout {
+ dlgStretch(20);
+ dlgGroup("Units") {
+ dlgRadioButton("Microns", OUTPUT_UNITS) {
+ convert_units(U_MICRONS);
+ }
+ dlgRadioButton("Millimeters", OUTPUT_UNITS) {
+ convert_units(U_MILLIMETERS);
+ }
+ dlgRadioButton("Mils", OUTPUT_UNITS) {
+ convert_units(U_MILS);
+ }
+ dlgRadioButton("Inches", OUTPUT_UNITS) {
+ convert_units(U_INCHES);
+ }
+ }
+ dlgGroup("Spindle") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Spin Up Time ");
+ dlgCell(1, 1) dlgRealEdit(SPINDLE_ON_TIME); // DO NOT CONVERT
+ }
+ }
+ dlgGroup("Feed Rates") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("X Y ");
+ dlgCell(1, 1) { dlgRealEdit(FEED_RATE);
+ dlgLabel(m_uom_suffix, YES); dlgLabel("/min");
+ }
+ dlgCell(2, 0) dlgLabel("Z ");
+ dlgCell(2, 1) { dlgRealEdit(FEED_RATE_Z);
+ dlgLabel(m_uom_suffix, YES); dlgLabel("/min");
+ }
+ }
+ }
+ dlgGroup("Misc") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Epsilon");
+ dlgCell(1, 1) { dlgRealEdit(EPSILON);
+ dlgLabel(m_uom_suffix, YES);
+ dlgPushButton("?") {
+ dlgMessageBox("If an X or Y move is less than this amount, do not "
+ "put a move in the g-code file. For instance, if one point is "
+ "only 0.00001\" away from another point, there is no need to "
+ "write the move to the g-code file, since the machine will not "
+ "move anyway. This helps make the g-code file smaller, and run faster.");
+ }
+ }
+ dlgCell(2, 0) dlgLabel("Default Drill Rack File");
+ dlgCell(2, 1) dlgStringEdit(DEFAULT_DRILL_FILE);
+ dlgCell(2, 2) {
+ dlgPushButton("...") {
+ DEFAULT_DRILL_FILE = dlgFileOpen("Find default drill rack file",
+ g_path + "/settings",
+ "Drill files (*.drl);;All files (*.*)");
+ }
+ dlgPushButton("?") {
+ dlgMessageBox(
+ "Please see docs/readme.html for full details. "
+ "pcb-gcode will look for (in order): "
+ "board.drl "
+ "The file you select here. "
+ "path_to_pcbgcode/settings/default.drl "
+ "If this setting is blank, and it does not find a file, "
+ "it will assume you do not want to use a rack file. "
+ "If this setting is not blank, and it cannot find one of the "
+ "files listed above, it will give you an error message."
+ );
+ }
+ }
+ }
+ }
+ dlgStretch(20);
+ }
+ }
+
+ /***************************************************************
+ *
+ * G C O D E S T Y L E
+ *
+ ***************************************************************/
+ dlgTabPage("GCode Style") {
+ dlgLabel("Please select your style of gcode below.");
+ dlgLabel("If you make changes to gcode-defaults.h to "
+ "work with your machine,");
+ dlgLabel(
+ "Please email the file to "
+ "pcbgcode@pcbgcode.org for possible inclusion "
+ "in the next release.");
+ dlgListView("File\tAuthor\tDescription",
+ pp_auth_desc, pp_selection);
+ }
+
+ /***************************************************************
+ *
+ * G C O D E O P T I O N S
+ *
+ ***************************************************************/
+ if (program_is_setup()) dlgTabPage("GCode Options") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgGroup("NC File Comments") {
+ dlgCheckBox("NC File Comment from Board",
+ NC_FILE_COMMENT_FROM_BOARD);
+ dlgCheckBox("Nc File Comment Date",
+ NC_FILE_COMMENT_DATE);
+ dlgCheckBox("Nc File Comment Machine Settings",
+ NC_FILE_COMMENT_MACHINE_SETTINGS);
+ dlgCheckBox("Nc File Comment Pcb Defaults Settings",
+ NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS);
+ }
+// dlgStretch(1);
+ }
+ dlgGroup("Other Options") {
+ dlgHBoxLayout {
+ dlgVBoxLayout {
+ dlgCheckBox("Use user gcode (from user-gcode.h)", USER_GCODE);
+ dlgCheckBox("Debug Flag", g_debug_flag);
+ dlgCheckBox("Do tool change with zero step", DO_TOOL_CHANGE_WITH_ZERO_STEP);
+ dlgCheckBox("Flip board in Y instead of X", FLIP_BOARD_IN_Y);
+ }
+ dlgVBoxLayout {
+ dlgCheckBox("Compact gcode", COMPACT_GCODE);
+ dlgHBoxLayout {
+ dlgCheckBox("Use line numbers?", USE_LINE_NUMBERS);
+ dlgLabel(" Format "); dlgStringEdit(LINE_NUMBER_FORMAT);
+ }
+ dlgCheckBox("Use simple drill code ",
+ SIMPLE_DRILL_CODE);
+ }
+ }
+ // dlgStretch(1);
+ }
+ }
+ dlgHBoxLayout {
+ dlgGroup("File Naming") {
+ dlgGridLayout {
+ dlgCell(0, 0, 0, 1) {
+ dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE);
+ }
+ dlgCell(0, 2) {
+ dlgLabel("Extension "); dlgStringEdit(DEFAULT_EXTENSION);
+ dlgStretch(1);
+ }
+ dlgCell(2, 0) { dlgLabel("Word for 'etch'");
+ dlgStringEdit(ETCH_FILE_NAME);
+ }
+ dlgCell(2, 1) { dlgLabel("Word for 'drill'");
+ dlgStringEdit(DRILL_FILE_NAME);
+ }
+ dlgCell(2, 2) { dlgLabel("Word for 'mill'");
+ dlgStringEdit(MILL_FILE_NAME);
+ }
+ dlgCell(2, 3) { dlgLabel("Word for 'text'");
+ dlgStringEdit(TEXT_FILE_NAME); dlgStretch(1);
+ }
+ dlgCell(3, 0) { dlgLabel("Word for 'top'");
+ dlgStringEdit(TOP_FILE_NAME);
+ }
+ dlgCell(3, 1) { dlgLabel("Word for 'bottom'");
+ dlgStringEdit(BOT_FILE_NAME);
+ }
+ }
+ dlgHBoxLayout {
+ dlgGroup("Top (Component) Side Files") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Etching ");
+ dlgCell(1, 1) { dlgStringEdit(FILENAME_TOP_ETCH_FILE); }
+ dlgCell(2, 0) dlgLabel("Drill ");
+ dlgCell(2, 1) { dlgStringEdit(FILENAME_TOP_DRILL_FILE); }
+ dlgCell(3, 0) dlgLabel("Mill ");
+ dlgCell(3, 1) { dlgStringEdit(FILENAME_TOP_MILL_FILE); }
+ dlgCell(4, 0) dlgLabel("Text ");
+ dlgCell(4, 1) { dlgStringEdit(FILENAME_TOP_TEXT_FILE); }
+ }
+ }
+ dlgGroup("Bottom (Solder) Side Files") {
+ dlgGridLayout {
+ dlgCell(1, 0) dlgLabel("Etching ");
+ dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE);
+ dlgCell(2, 0) dlgLabel("Drill ");
+ dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE);
+ dlgCell(3, 0) dlgLabel("Mill ");
+ dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE);
+ dlgCell(4, 0) dlgLabel("Text ");
+ dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_TEXT_FILE);
+ }
+ }
+// dlgStretch(1);
+ dlgVBoxLayout {
+ dlgPushButton("Test Filenames") {
+ FILENAME_TOP_ETCH_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_ETCH_FILE,
+ TOP, PH_TOP_OUT_WRITE);
+ FILENAME_TOP_DRILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_DRILL_FILE,
+ TOP, PH_TOP_DRILL);
+ FILENAME_TOP_MILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_MILL_FILE,
+ TOP, PH_MILL);
+ FILENAME_TOP_TEXT_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_TOP_TEXT_FILE,
+ TOP, PH_TEXT);
+ FILENAME_BOT_ETCH_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_ETCH_FILE,
+ BOTTOM, PH_BOTTOM_OUT_WRITE);
+ FILENAME_BOT_DRILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_DRILL_FILE,
+ BOTTOM, PH_BOTTOM_DRILL);
+ FILENAME_BOT_MILL_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_MILL_FILE,
+ BOTTOM, PH_MILL);
+ FILENAME_BOT_TEXT_FILE_SAMPLE = sub_side_phase(
+ FILENAME_BASE + FILENAME_BOT_TEXT_FILE,
+ BOTTOM, PH_TEXT);
+ FILENAME_TOP_ETCH_FILE_SAMPLE = substitute(
+ FILENAME_TOP_ETCH_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_TOP_DRILL_FILE_SAMPLE = substitute(
+ FILENAME_TOP_DRILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_TOP_MILL_FILE_SAMPLE = substitute(
+ FILENAME_TOP_MILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_TOP_TEXT_FILE_SAMPLE = substitute(
+ FILENAME_TOP_TEXT_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_ETCH_FILE_SAMPLE = substitute(
+ FILENAME_BOT_ETCH_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_DRILL_FILE_SAMPLE = substitute(
+ FILENAME_BOT_DRILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_MILL_FILE_SAMPLE = substitute(
+ FILENAME_BOT_MILL_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ FILENAME_BOT_TEXT_FILE_SAMPLE = substitute(
+ FILENAME_BOT_TEXT_FILE_SAMPLE,
+ key_value_record(" ", "_"));
+ temp_str = ";Test Filenames\n"
+ "Spaces in file paths have been "
+ "replaced with underscores _ to keep "
+ "the lines from wrapping.\n"
+ "Top:\n"
+ "Etch:\t" + FILENAME_TOP_ETCH_FILE_SAMPLE + "\n" +
+ "Drill:\t" + FILENAME_TOP_DRILL_FILE_SAMPLE + "\n" +
+ "Mill:\t" + FILENAME_TOP_MILL_FILE_SAMPLE + "\n" +
+ "Text:\t" + FILENAME_TOP_TEXT_FILE_SAMPLE + "\n" +
+ "\nBottom:\n"
+ "Etch:\t" + FILENAME_BOT_ETCH_FILE_SAMPLE + "\n" +
+ "Drill:\t" + FILENAME_BOT_DRILL_FILE_SAMPLE + "\n" +
+ "Mill:\t" + FILENAME_BOT_MILL_FILE_SAMPLE + "\n" +
+ "Text:\t" + FILENAME_BOT_TEXT_FILE_SAMPLE + "\n";
+ dlgMessageBox(temp_str);
+ }
+ dlgPushButton("Help") {
+ dlgMessageBox(filename_subs_help());
+ }
+// dlgStretch(1);
+ }
+ }
+ }
+ }
+
+ }
+ if (program_is_setup()) dlgTabPage("Plugins") {
+ #include "plugins/plugin_loader.h"
+ }
+
+ /***************************************************************
+ *
+ * O T H E R
+ *
+ ***************************************************************/
+ if (program_is_setup()) dlgTabPage("Other") {
+ dlgHBoxLayout {
+ dlgStretch(1);
+ dlgVBoxLayout {
+ dlgStretch(1);
+ dlgGroup("Miscellaneous") {
+ dlgGridLayout {
+ dlgCell(0, 0, 0, 5) {
+ dlgLabel("All misc. options are deprecated.");
+ }
+ }
+ }
+ dlgPushButton("Reset to Factory Defaults") {
+ if (dlgMessageBox(
+ "This is going to change the following files"
+ " back to their default contents, erasing any changes"
+ " you may have made to them:
"
+ "
"
+ "
pcb-defaults.h
pcb-gcode-options.h
"
+ "
pcb-machine.h
user-gcode.h
"
+ "
"
+ "Is that something you want to do?
"
+ "If you aren't sure, click No.
",
+ "-Yes", "+No") == 0 /*Yes*/) {
+ restore_file_defaults();
+ exit("run pcb-gcode-setup");
+ }
+ }
+ dlgStretch(1);
+ }
+ dlgStretch(1);
+ }
+ }
+ }
+
+ dlgHBoxLayout {
+ dlgStretch(5);
+ dlgPushButton("+&Accept") dlgAccept();
+ if (program_is_setup()) {
+ dlgPushButton("Accept and make my &board") dlgAccept(2);
+ }
+ dlgPushButton("-Cancel") {
+ if (dlgMessageBox("Cancel your changes.
"
+ "Are you sure?", "Yes", "No") == 0) dlgReject();
+ }
+ }
+};
+
+// Accept Accept and make board
+if (Result == 1 || Result == 2) {
+
+ fileerror();
+ output(g_path + "/settings/pcb-defaults.h", "wt") {
+
+ int now = time();
+
+ printf(
+ "//\n// Default values for generating gcode from a PCB.\n//\n");
+ printf("// These settings were last changed with "
+ "pcb-gcode-setup: %s\n//\n", t2string(now));
+ printf("//\n// Changes you make in this file will be overwritten "
+ "if you use pcb-gcode-setup.\n//\n\n");
+
+ write_bool_param("SINGLE_PASS", SINGLE_PASS);
+ write_real_param("ISO_MIN", ISO_MIN);
+ write_real_param("ISO_MAX", ISO_MAX);
+ write_real_param("ISO_STEP", ISO_STEP);
+ printf("\n");
+
+ write_bool_param("GENERATE_TOP_OUTLINES", GENERATE_TOP_OUTLINES);
+ write_bool_param("GENERATE_TOP_DRILL", GENERATE_TOP_DRILL);
+ write_bool_param("GENERATE_TOP_FILL", GENERATE_TOP_FILL);
+ printf("\n");
+
+ write_bool_param("GENERATE_BOTTOM_OUTLINES",
+ GENERATE_BOTTOM_OUTLINES);
+ write_bool_param("GENERATE_BOTTOM_DRILL", GENERATE_BOTTOM_DRILL);
+ write_bool_param("GENERATE_BOTTOM_FILL", GENERATE_BOTTOM_FILL);
+ write_bool_param("MIRROR_BOTTOM",
+ MIRROR_BOTTOM);
+ write_bool_param("SIMPLE_DRILL_CODE", SIMPLE_DRILL_CODE);
+
+ printf("\n");
+
+ write_bool_param("GENERATE_MILLING", GENERATE_MILLING);
+ printf("\n");
+
+ write_bool_param("GENERATE_TEXT", GENERATE_TEXT);
+ printf("\n");
+
+ write_bool_param("SPOT_DRILL", SPOT_DRILL);
+ write_real_param("SPOT_DRILL_DEPTH", SPOT_DRILL_DEPTH);
+ printf("\n");
+
+ write_bool_param("DO_TOOL_CHANGE_WITH_ZERO_STEP",
+ DO_TOOL_CHANGE_WITH_ZERO_STEP);
+ printf("\n");
+
+ write_bool_param("FLIP_BOARD_IN_Y", FLIP_BOARD_IN_Y);
+ printf("\n");
+
+ // Place a // in front of units not being used
+ if (OUTPUT_UNITS != U_MICRONS) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_MICRONS");
+ if (OUTPUT_UNITS != U_MILLIMETERS) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_MILLIMETERS");
+ if (OUTPUT_UNITS != U_MILS) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_MILS");
+ if (OUTPUT_UNITS != U_INCHES) printf("//");
+ write_int_defined("OUTPUT_UNITS", "U_INCHES");
+ }
+ if(fileerror())
+ exit(1);
+
+ if(pp_selection > -1) {
+ if (dlgMessageBox(
+ "If you have made manual changes to gcode-defaults.h, they"
+ " will be overwritten by your new gcode style selection.
"
+ "This program generates g-code for 'mechanically etching' PC boards. "
+ "Using a CNC router or milling machine, you can make PC boards without using etching chemicals."
+ "It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board."
+ " See the readme.html file for more info.
"
+ "There are many options in the setup program. "
+ "To setup which files are generated, and how, use the following command: "
+ "run pcb-gcode --setup
"
+ "
"
+ "If you want to produce a set of files without changing options, you can run pcb-gcode directly."
+ "Usage is as follows: "
+ "run pcb-gcode [option] [file] "
+ "Where:\n"
+ "
"
+ "
Option
Function
"
+ "
--help
Show this help screen
"
+ "
--setup
Run the setup / configuration program
"
+ "
file
Is the optional root filename.\n
"
+ "
If not given, the board name is used as the root filename.
"
+ "
"
+ ""
+ ""
+ ""
+
+g_width = DEFAULT_WIDTH;
+
+// Filename to output to.
+string m_file_name = "";
+
+// Which side we're currently working on.
+g_side = TOP;
+
+// Tool currently being used.
+int m_current_tool = 0;
+
+// Amount to isolate traces.
+real m_isolate = 0.0;
+
+// Used to pass the pass info to the next pass of the program.
+int m_pass_num;
+
+// The layer being worked on.
+int m_layer;
+
+// Used to create command strings.
+string g_cmd;
+string g_cmd_temp;
+
+// Save the maximum and minimum coordinates.
+real m_max_x;
+real m_max_y;
+real m_min_x;
+real m_min_y;
+void save_extents(real x, real y)
+{
+ m_max_x = max(m_max_x, x);
+ m_max_y = max(m_max_y, y);
+ m_min_x = min(m_min_x, x);
+ m_min_y = min(m_min_y, y);
+}
+
+void preview()
+{
+ if (SHOW_PREVIEW) {
+ switch(get_os()) {
+ case OS_MACOSX:
+ system(g_path + "/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub");
+ break;
+ case OS_LINUX:
+ system(g_path + "/source/viewer.linux.sh");
+ break;
+ case OS_WINDOWS:
+ system(g_path + "/viewer/application.windows/viewer.exe");
+ dlgMessageBox("Close this window when you have finished with the preview");
+ break;
+ default:
+ Fatal("Oops!", "Can't figure out which OS you have.");
+ }
+ }
+}
+//
+// Determine the next phase, and set g_phase accordingly.
+//
+// Params: none
+// Return: none
+//
+void next_phase(void)
+{
+ if (g_phase == PH_TOP_OUT_GEN && GENERATE_TOP_OUTLINES != YES) {
+ g_phase += 2;
+ return;
+ }
+ if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) {
+ g_phase += 2;
+ return;
+ }
+
+ if (g_phase == PH_TOP_OUT_WRITE || g_phase == PH_BOTTOM_OUT_WRITE) {
+ if (m_isolate < ISO_MAX && !SINGLE_PASS) {
+ m_isolate += ISO_STEP;
+ m_pass_num++;
+ g_phase--;
+ }
+ else {
+ m_isolate = ISO_MIN;
+ m_pass_num = 0;
+ g_phase++;
+
+ preview();
+ }
+ }
+ else {
+ g_phase++;
+ }
+}
+
+//////////////////////////////////////////////////
+//
+// Hole drilling routines.
+//
+//////////////////////////////////////////////////
+
+//
+// Add a hole drilling command to the command string.
+//
+// Params:
+// Size Drill size.
+// x x coordinate.
+// y y coordinate.
+// Returns:
+// none
+// Changes:
+// the stack
+//
+void add_hole(int req_size, int x, int y)
+{
+ string tempstr;
+ int drill_size;
+
+ drill_size = get_drill_for(req_size);
+
+ sprintf(tempstr, "%06d\t%06d\t%06d", drill_size, x, y);
+ stack_push(tempstr);
+}
+
+/*
+ * Create a drill file for the desired side.
+ *
+ * Params:
+ * which_side Side to produce the file for.
+ * suffix Suffix to use for the file name (i.e. bd).
+ * Returns:
+ * none
+ * Changes:
+ * side
+*/
+void drill(int which_side, string suffix)
+{
+ int num_lines;
+ int i;
+ real last_size;
+ string drill_args[];
+ m_current_tool = 0;
+ real drill_size_mm;
+ real drill_size_inch;
+ real drill_size;
+ real drill_x;
+ real drill_y;
+ int drill_tool_num;
+
+ g_side = which_side;
+
+ //
+ // Build a stack with all the holes.
+ //
+ board(B) {
+ B.holes(H) add_hole(H.drill, H.x, H.y);
+ B.signals(S) S.vias(V) add_hole(V.drill, V.x, V.y);
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ add_hole(C.pad.drill, C.pad.x, C.pad.y);
+ }
+ }
+ E.package.holes(H) add_hole(H.drill, H.x, H.y);
+ }
+ // B.elements
+
+ // Sorts the drills by size, x and y.
+ stack_sort();
+
+ //
+ // Create the drill g-code file.
+ //
+ last_size = -1;
+ output(get_filename(), "wt") {
+ output_file_preamble();
+
+ //
+ // Create a tool table at the beginning of the file.
+ //
+ out(TOOL_CHANGE_TABLE_HEADER);
+ for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
+ if (i==END_OF_STACK) break;
+ strsplit(drill_args, stack_elem(i), '\t');
+ drill_size_inch = u2inch(my_strtol(drill_args[DRILL_SIZE]));
+ drill_size_mm = u2mm(my_strtol(drill_args[DRILL_SIZE]));
+ drill_size = my_strtol(drill_args[DRILL_SIZE]);
+
+ if (drill_size != last_size) {
+ ++m_current_tool;
+ drill_tool_num = get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool);
+ out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num,
+ drill_size_mm, drill_size_inch,
+ g_mins[drill_tool_num], g_maxs[drill_tool_num],
+ g_drill_sub_cnt[drill_tool_num]));
+ }
+ last_size = drill_size;
+ }
+ // for
+
+ // Set the mode for the user's UOM.
+ out(get_mode());
+ out(ABSOLUTE_MODE);
+
+ //
+ // Generate drill code.
+ //
+ m_current_tool = 0;
+ for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
+ strsplit(drill_args, stack_elem(i), '\t');
+ drill_size = units(my_strtol(drill_args[DRILL_SIZE]));
+ drill_x = scale_x(my_strtol(drill_args[DRILL_X]));
+ drill_y = scale_y(my_strtol(drill_args[DRILL_Y]));
+ save_extents(drill_x, drill_y);
+
+ if (drill_size == last_size) {
+ output_drill_hole(drill_x, drill_y, DRILL_DEPTH);
+ }
+ else {
+ m_current_tool++;
+ // Tool change routine
+ output_tool_change_begin();
+ out(SPINDLE_OFF);
+ rz(TOOL_CHANGE_POS_Z);
+ rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y);
+ out(fir(TOOL_CHANGE, get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool), drill_size));
+ output_tool_changed();
+
+ if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) {
+ output_tool_zero_begin();
+ fzr(0.000, FEED_RATE_Z);
+ // fixme: wondering about the following line
+ out(fir(TOOL_CHANGE, m_current_tool, drill_size));
+ output_tool_zero_end();
+ }
+
+ rz(DEFAULT_Z_UP);
+ out(fr(SPINDLE_ON, SPINDLE_ON_TIME));
+ output_tool_change_end();
+
+ output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH);
+ last_size = drill_size;
+ }
+ // if drill_size != last_size
+ }
+ // for
+
+ output_file_postamble();
+
+ // End of file
+ // change back to tool 1
+ out(fi(TOOL_CODE + EOL, 1));
+ end_gcode();
+ }
+ // output
+ }
+ // Board
+}
+// drill
+
+int m_first_spot_drill = YES;
+void spot_drill_hole(int x, int y)
+{
+ real drill_x;
+ real drill_y;
+
+ drill_x = scale_x(x);
+ drill_y = scale_y(y);
+ save_extents(drill_x, drill_y);
+
+ if (m_first_spot_drill) {
+ output_drill_first_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
+ m_first_spot_drill = NO;
+ }
+ else {
+ output_drill_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
+ }
+}
+
+void spot_drill(UL_BOARD B)
+{
+ if (SPOT_DRILL == NO) { return; }
+
+ B.holes(H) spot_drill_hole(H.x, H.y);
+ B.signals(S) S.vias(V) spot_drill_hole(V.x, V.y);
+ B.elements(E) {
+ E.package.contacts(C) {
+ if (C.pad) {
+ spot_drill_hole(C.pad.x, C.pad.y);
+ }
+ }
+ E.package.holes(H) spot_drill_hole(H.x, H.y);
+ }
+ // B.elements
+}
+
+string m_lines;
+string LINE_SEP = "\n";
+string COORD_SEP = ",";
+string COORD_FMT = "%8.5f";
+
+string coords(real x1, real y1, real x2, real y2)
+{
+ return frrrr(COORD_FMT + COORD_SEP + COORD_FMT + COORD_SEP +
+ COORD_FMT + COORD_SEP + COORD_FMT + LINE_SEP, x1, y1, x2, y2);
+}
+
+//
+// "Draw" on the output device, i.e. the gcode file.
+//
+// Params:
+// x1,y1 Start of the line.
+// x2,y2 End of the line.
+// state
+// z_down
+// Returns:
+// none
+//
+real m_arc_begin_x;
+real m_arc_begin_y;
+int pair_count = 0;
+int MAX_COORDS_PER_LINE = 4;
+void device_draw(int x1, int y1, int x2, int y2, int state, real z_down)
+{
+ real rx1, ry1, rx2, ry2;
+
+ rx1 = scale_x(x1);
+ ry1 = scale_y(y1);
+ rx2 = scale_x(x2);
+ ry2 = scale_y(y2);
+ save_extents(rx1, ry1);
+ save_extents(rx2, ry2);
+
+ // Output g-code based on the current state.
+ switch(state) {
+
+ // Start of a new line.
+ case ST_START_LINE:
+ user_track_begin(rx1, ry1, rx2, ry2);
+
+ m_lines += coords(rx1, ry1, rx2, ry2);
+
+ rz(DEFAULT_Z_UP);
+ rxy(rx1, ry1);
+ fzr(z_down, FEED_RATE_Z);
+ fxyr(rx2, ry2, FEED_RATE);
+ pair_count = 0;
+ break;
+
+ // A fill line.
+ case ST_FILL:
+ Fatal("Programmer Error", "The Fill functions are no longer supported.");
+ break;
+
+ // Continue a line.
+ // End a line.
+ case ST_CONTINUE_LINE:
+ user_track_continue(rx1, ry1, rx2, ry2);
+
+ m_lines += coords(rx1, ry1, rx2, ry2);
+
+ if (COMPACT_GCODE == YES) {
+ if (pair_count == 0) {
+ fxy(rx2, ry2);
+ }
+ else {
+ xy(rx2, ry2);
+ }
+ pair_count++;
+ }
+ else {
+ fxy(rx2, ry2);
+ }
+ break;
+
+ case ST_END_LINE:
+ user_track_end(rx1, ry1, rx2, ry2);
+
+ m_lines += coords(rx1, ry1, rx2, ry2);
+
+
+ if (COMPACT_GCODE == YES) {
+ xy(rx2, ry2);
+ pair_count = 0;
+ }
+ else {
+ fxy(rx2, ry2);
+ }
+ break;
+
+ // Drill a hole.
+ // todo is this valid?
+ case ST_DRILL:
+ printf("cause an error if used %d");
+ // printf("drill (%f, %f)\n", rx2, ry2);
+ break;
+
+ // Create an arc.
+ case ST_ARC_BEGIN:
+ user_arc_begin(rx1, ry1, rx2, ry2);
+ m_arc_begin_x = rx1;
+ m_arc_begin_y = ry1;
+ break;
+
+ // Finish an arc.
+ case ST_ARC_END:
+ user_arc_end(rx1, ry1, rx2, ry2);
+ real cx = rx2;
+ real cy = ry2;
+ real end_x = rx1;
+ real end_y = ry1;
+
+ if (1 /* USE_IJ_RELATIVE */) {
+ cx = rx2 - rx1;
+ cy = ry2 - ry1;
+ }
+
+ rz(DEFAULT_Z_UP);
+ rxy(end_x, end_y);
+ fzr(z_down, FEED_RATE_Z);
+ if (g_side == TOP || MIRROR_BOTTOM == YES) {
+ out(frrrr(CIRCLE_TOP, m_arc_begin_x, m_arc_begin_y, cx, cy));
+ }
+ else {
+ out(frrrr(CIRCLE_BOTTOM, m_arc_begin_x, m_arc_begin_y, cx, cy));
+ }
+ break;
+
+ }
+ // switch(state)
+}
+// device_draw
+
+
+//
+// Generate polygons for outline or fill.
+// This creates a series of commands for Eagle and puts them
+// in g_cmd to be passed when we exit from this phase of pcb-gcode.
+//
+// Params:
+// which_side The side to operate on.
+// Return:
+// none
+//
+void generate_outlines(int which_side)
+{
+ string cmd_temp = "";
+
+ g_cmd = "";
+
+ if (which_side == TOP)
+ m_layer = TOP_LAYER;
+ else
+ m_layer = BOTTOM_LAYER;
+
+ board(B) {
+ real f = BORDER_SIZE;
+ real x1 = units(B.area.x1) - f;
+ real y1 = units(B.area.y1) - f;
+ real x2 = units(B.area.x2) + f;
+ real y2 = units(B.area.y2) + f;
+
+ B.signals(S) {
+ if (S.name == OUTLINES_SIGNAL_NAME) {
+ sprintf(cmd_temp, "delete (%f %f) (%f %f);\n",
+ x1, y1, x2, y2);
+ g_cmd = g_cmd + cmd_temp;
+ }
+ }
+
+ sprintf(cmd_temp, "grid %s;\n"
+ "change isolate %f;\n"
+ "change rank 6;\n"
+ "change pour solid;\n"
+ "change width %f;\n"
+ "change orphans on;\n"
+ "layer %d;\n"
+ "polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n"
+ "ratsnest;\n"
+ ,
+ UNIT_OF_MEASURE,
+ m_isolate,
+ g_width,
+ m_layer,
+ OUTLINES_SIGNAL_NAME, g_width,
+ x1, y1, x2, y1, x2, y2, x1, y2, x1, y1
+ );
+ g_cmd = g_cmd + cmd_temp;
+ return;
+ }
+ // board(B)
+}
+// generate_outlines
+
+void out_lines(string path, string mode)
+{
+ output(path, mode) {
+ if (m_pass_num == 0) {
+ printf("# board=%s\n", elided_path(get_filename(), 30));
+ printf("# tool size=%f\n", g_width);
+ }
+ printf("# pass=%d\n", m_pass_num + 1);
+ printf(m_lines);
+ }
+}
+
+//
+// Write text from the Milling layer to a text engraving file.
+//
+// Params:
+// file_name Output filename.
+// Return:
+// none
+//
+void output_text_code(string file_name)
+{
+ int state;
+ int old_x, old_y;
+
+ board(B) {
+ output(get_filename(), "wt") {
+ user_file_opened(get_filename(), "wt");
+
+ output_file_preamble();
+
+ // Initialize the device (i.e. the output file).
+ begin_gcode();
+
+ // Process all the wires.
+ B.texts(T) T.wires(W) {
+ if ((T.mirror && g_side == BOTTOM) || (! T.mirror && g_side == TOP)) {
+ // If this is a text layer, check if we should continue
+ // a line, or start a new one.
+ if (W.layer == TEXT_LAYER) {
+ if (W.x1 == old_x && W.y1 == old_y) {
+ state = ST_CONTINUE_LINE;
+ }
+ else {
+ state = ST_START_LINE;
+ }
+
+ // if this is an arc, it is treated specially.
+ if (W.arc) {
+ device_draw( W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, ST_ARC_BEGIN, TEXT_DEPTH);
+ device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH);
+ save_extents(W.x1, W.y1);
+ save_extents(W.x2, W.y2);
+ state = ST_START_LINE;
+ }
+ else {
+ // Draw the line (i.e. output the gcode for the line).
+ device_draw(W.x1, W.y1, W.x2, W.y2, state, TEXT_DEPTH);
+ old_x = W.x2;
+ old_y = W.y2;
+ save_extents(W.x1, W.y1);
+ save_extents(W.x2, W.y2);
+ }
+ // if (W.arc)
+ }
+ // if (W.layer == TEXT_LAYER)
+ }
+ // if (top and bottom check)
+ }
+ // T.wires
+ output_file_postamble();
+ end_gcode();
+ user_file_closing();
+ }
+ // output
+ user_file_closed(get_filename(), "wt");
+ }
+ // board
+ g_width = abs(TEXT_DEPTH);
+ out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
+
+ preview();
+
+ m_lines = "";
+}
+// output_text_code
+
+
+//
+// Write layer data to mill files.
+//
+// Params:
+// file_name Output filename.
+// Return:
+// none
+//
+void output_mill_code(string file_name)
+{
+ int state;
+ int old_x, old_y;
+
+ board(B) {
+ output(get_filename(), "wt") {
+ user_file_opened(get_filename(), "wt");
+
+ output_file_preamble();
+
+ // Initialize the device (i.e. the output file).
+ begin_gcode();
+
+ // Process all the wires.
+ B.wires(W) W.pieces(P) {
+ // If this is a mill layer, check if we should continue
+ // a line, or start a new one.
+ if (P.layer == MILL_LAYER) {
+ if (P.x1 == old_x && P.y1 == old_y) {
+ state = ST_CONTINUE_LINE;
+ }
+ else {
+ state = ST_START_LINE;
+ }
+
+ // if this is an arc, it is treated specially.
+ if (P.arc) {
+ device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, MILLING_DEPTH);
+ device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH);
+ save_extents(P.x1, P.y1);
+ save_extents(P.x2, P.y2);
+ state = ST_START_LINE;
+ }
+ else {
+ // Draw the line (i.e. output the gcode for the line).
+ device_draw(P.x1, P.y1, P.x2, P.y2, state, MILLING_DEPTH);
+ old_x = P.x2;
+ old_y = P.y2;
+ save_extents(P.x1, P.y1);
+ save_extents(P.x2, P.y2);
+ }
+ // if (P.arc)
+ }
+ // if (P.layer == MILL_LAYER)
+ }
+ // pieces
+ output_file_postamble();
+ end_gcode();
+ user_file_closing();
+ }
+ // output
+ user_file_closed(get_filename(), "wt");
+ }
+ // board
+
+ g_width = abs(MILLING_DEPTH);
+ out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
+ out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
+
+ preview();
+
+ m_lines = "";
+}
+// output_mill_code
+
+
+//
+// Write polygon lines to the file.
+//
+// Params:
+// which_side Side of the board to work on.
+// suffix Suffix of the file.
+// task
+// Return:
+// none
+//
+void write_outlines(int which_side, string suffix, int task)
+{
+ string mode;
+ int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN;
+ int x0, y0;
+ int first = 1;
+ int frame_wire;
+ int state;
+
+ if (m_pass_num == 0) {
+ mode = "wt";
+ }
+ else {
+ mode = "at";
+ }
+ g_side = which_side;
+ switch (which_side) {
+ case TOP:
+ m_layer = TOP_LAYER;
+ break;
+ case BOTTOM:
+ m_layer = BOTTOM_LAYER;
+ break;
+ case MILL:
+ m_layer = MILL_LAYER;
+ break;
+ case TEXT:
+ m_layer = TEXT_LAYER;
+ break;
+ default:
+ sprintf(g_debug, "Illegal which_side %d in write_outlines", which_side);
+ Fatal("Sorry...", g_debug);
+ }
+
+ if (m_layer == MILL_LAYER || m_layer == TEXT_LAYER) {
+ if (which_side == MILL) {
+ g_side = TOP;
+ output_mill_code(m_file_name + "mt" + DEFAULT_EXTENSION);
+ g_side = BOTTOM;
+ output_mill_code(m_file_name + "mb" + DEFAULT_EXTENSION);
+ return;
+ }
+ else {
+ g_side = TOP;
+ output_text_code(m_file_name + "tt" + DEFAULT_EXTENSION);
+ g_side = BOTTOM;
+ output_text_code(m_file_name + "tb" + DEFAULT_EXTENSION);
+ return;
+ }
+ }
+ // if m_layer == MILL_LAYER
+
+ output(get_filename(), mode) {
+ board(B) {
+ user_file_opened(get_filename(), mode);
+
+ int rubout_layer = -1;
+ B.layers(L) {
+ if (strstr(strlwr(L.name), "rubout") != -1) {
+ if (strstr(strlwr(L.name), "top") != -1 && which_side == TOP) {
+ rubout_layer = L.number;
+ }
+ else if (strstr(strlwr(L.name), "bot") != -1 && which_side == BOTTOM) {
+ rubout_layer = L.number;
+ }
+ }
+ }
+
+ if (rubout_layer != -1) {
+ B.wires(W) {
+ if (W.layer == rubout_layer) {
+ device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
+ device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN); // fixme needed?
+ }
+ }
+ }
+
+ B.signals(S) {
+ if (S.name == OUTLINES_SIGNAL_NAME) {
+ S.polygons(P) {
+ P.wires(W) {
+ x1 = min(x1, W.x1);
+ x2 = max(x2, W.x1);
+ y1 = min(y1, W.y1);
+ y2 = max(y2, W.y1);
+ }
+ if (m_pass_num == 0) {
+ output_file_preamble();
+ begin_gcode();
+ }
+ else {
+ output_between_outline_passes();
+ }
+
+ switch (task) {
+ case TASK_OUTLINES:
+ // P.contours jtj
+ P.contours(W) {
+ if (first) {
+ x0 = W.x1;
+ y0 = W.y1;
+ frame_wire = (x0 == x1 || x0 == x2) && (y0 == y1 || y0 == y2);
+ state = ST_START_LINE;
+ first = 0;
+ }
+ else if (W.x2 == x0 && W.y2 == y0) {
+ state = ST_END_LINE;
+ first = 1;
+ }
+ else {
+ state = ST_CONTINUE_LINE;
+ }
+
+ if (!frame_wire) {
+ device_draw(W.x1, W.y1, W.x2, W.y2, state, DEFAULT_Z_DOWN);
+ }
+ }
+ // P.contours(W)
+ break;
+
+ case TASK_FILL:
+ P.fillings(W) {
+ device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
+ }
+ break;
+ }
+ // switch(task)
+
+ if (m_isolate >= ISO_MAX || SINGLE_PASS || task == TASK_FILL) {
+ output_file_postamble();
+ rz(DEFAULT_Z_UP);
+ spot_drill(B);
+ end_gcode();
+ }
+
+ sprintf(g_cmd, "delete (%f %f) (%f %f);\n",
+ units(x1), units(y1), units(x2), units(y2)
+ );
+ }
+ // polygons
+ }
+ // if(S.name == OUTLINES_SIGNAL_NAME)
+ }
+ // signals
+ }
+ // board
+ user_file_closing();
+ }
+ // output
+ user_file_closed(get_filename(), mode);
+ out_lines(g_path + "/viewer/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode);
+ out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode);
+
+}
+// write_outlines
+
+/* string get_phase_name(int phase)
+{
+ return PHASE_NAME[phase];
+}
+ */
+void gen_progress_menu(int phase)
+{
+ output(path_scr[0] + '/' + "source/pcb-gcode-prg.scr") {
+ printf("MENU \\\n");
+ for(int i = 1; i < PH_LAST_PHASE; i++) {
+ if (i == phase) {
+ printf("--%s-- \\\n", get_phase_name(i));
+ // " (for TextMate)
+ }
+ else {
+ printf(" %s \\\n", get_phase_name(i));
+ }
+ }
+ printf(";\n");
+ }
+}
+
+// Make sure a board is available to work on.
+// todo move towards bottom
+if (!board) {
+ Fatal("No board!", "Please run this program from the board editor");
+}
+
+//
+// Process command line arguments.
+//
+switch (OUTPUT_UNITS) {
+ case U_MICRONS:
+ UNIT_OF_MEASURE = "mic";
+ break;
+ case U_MILLIMETERS:
+ UNIT_OF_MEASURE = "mm";
+ break;
+ case U_MILS:
+ UNIT_OF_MEASURE = "mil";
+ break;
+ case U_INCHES:
+ UNIT_OF_MEASURE = "inch";
+ break;
+}
+
+if (argv[FILENAME_ARG] == "--setup") {
+ exit("run pcb-gcode-setup");
+}
+
+if (argv[FILENAME_ARG] == "--attr") {
+ string attrs;
+ board(B) {
+ B.attributes(A) {
+ attrs = attrs + A.name + "\t" + A.value + "\n";
+ }
+ }
+ dlgMessageBox(attrs);
+ exit(0);
+}
+
+if (argv[FILENAME_ARG] == "--help") {
+ int choice = dlgMessageBox(usage, "+Return to Eagle", "Run Setup Now");
+ switch (choice) {
+
+ // return to eagle
+ case 0:
+ exit(0);
+ break;
+
+ // Run setup now
+ case 1:
+ exit("run pcb-gcode-setup");
+ break;
+ }
+ exit(0);
+}
+
+// Be sure a filename is specified.
+if (argv[FILENAME_ARG]) {
+ m_file_name = argv[FILENAME_ARG];
+ if (filedir(m_file_name) == "") {
+ board(B) m_file_name = filedir(B.name) + m_file_name;
+ }
+}
+else {
+ board(B) m_file_name = filesetext(B.name, "");
+}
+
+if (FILENAMES_8_CHARACTERS) {
+ m_file_name = filedir(m_file_name) + strsub(filename(m_file_name), 0, 5);
+}
+
+// Use a default width if one is not given.
+if (argv[WIDTH_ARG]) {
+ g_width = strtod(argv[WIDTH_ARG]);
+}
+else {
+ g_width = DEFAULT_WIDTH;
+}
+
+// Get the isolate parameter or use the default.
+if (argv[ISO_ARG]) {
+ m_isolate = strtod(argv[ISO_ARG]);
+}
+else {
+ m_isolate = ISO_MIN;
+}
+
+// Get the pass number, or default to first pass (0).
+if (argv[PASS_ARG]) {
+ m_pass_num = strtol(argv[PASS_ARG]);
+}
+else {
+ m_pass_num = 0;
+}
+
+// Get the phase we are processing, or default to the first one.
+if (argv[PHASE_ARG]) {
+ g_phase = strtol(argv[PHASE_ARG]);
+}
+else {
+ g_phase = PH_TOP_OUT_GEN;
+}
+
+get_current_profile();
+if (g_phase == PH_TOP_OUT_GEN && m_pass_num == 0 && program_is_setup() == NO)
+{
+ exit("run pcb-gcode-setup");
+}
+
+//
+// Do what we need to for this phase.
+//
+switch (g_phase) {
+ case PH_TOP_OUT_GEN:
+ if (GENERATE_TOP_OUTLINES == YES)
+ generate_outlines(TOP);
+ break;
+ case PH_TOP_OUT_WRITE:
+ if (GENERATE_TOP_OUTLINES == YES)
+ write_outlines(TOP, "top", OUTLINES);
+ break;
+
+ case PH_TOP_FILL_GEN:
+ if (GENERATE_TOP_FILL == YES)
+ generate_outlines(TOP);
+ break;
+ case PH_TOP_FILL_WRITE:
+ if (GENERATE_TOP_FILL == YES)
+ write_outlines(TOP, "tf", FILL);
+ break;
+
+ case PH_BOTTOM_OUT_GEN:
+ if (GENERATE_BOTTOM_OUTLINES == YES)
+ generate_outlines(BOTTOM);
+ break;
+ case PH_BOTTOM_OUT_WRITE:
+ if (GENERATE_BOTTOM_OUTLINES == YES)
+ write_outlines(BOTTOM, "bot", OUTLINES);
+ break;
+
+ case PH_BOTTOM_FILL_GEN:
+ if (GENERATE_BOTTOM_FILL == YES)
+ generate_outlines(BOTTOM);
+ break;
+ case PH_BOTTOM_FILL_WRITE:
+ if (GENERATE_BOTTOM_FILL == YES)
+ write_outlines(BOTTOM, "bf", FILL);
+ break;
+
+ case PH_TOP_DRILL:
+ if (GENERATE_TOP_DRILL == YES)
+ drill(TOP, "td");
+ break;
+ case PH_BOTTOM_DRILL:
+ if (GENERATE_BOTTOM_DRILL == YES)
+ drill(BOTTOM, "bd");
+ break;
+
+ case PH_MILL:
+ if (GENERATE_MILLING == YES)
+ write_outlines(MILL, "mil", MILL_BOARD);
+ break;
+
+ case PH_TEXT:
+ if (GENERATE_TEXT == YES)
+ write_outlines(TEXT, "txt", MILL_TEXT);
+ break;
+
+ default:
+ sprintf(g_debug, "Illegal phase %d in main routine", g_phase);
+ Fatal("Sorry...", g_debug);
+}
+
+// Set things up for the next phase.
+next_phase();
+
+if (SHOW_PROGRESS == YES) {
+ gen_progress_menu(g_phase);
+}
+
+// If this is not the last phase, exit with a command line for
+// Eagle to process. The command includes running this program again.
+if (g_phase < PH_LAST_PHASE) {
+ sprintf(g_cmd,
+ "%s"
+ "window fit;\n"
+ "%s"
+ "run '%s' '%s' '%f' '%f' '%d' '%d';\n",
+ g_cmd,
+ (SHOW_PROGRESS) ? "script pcb-gcode-prg.scr;\n" : "",
+ argv[PROGRAM_NAME_ARG], m_file_name, g_width, m_isolate,
+ m_pass_num, g_phase
+ );
+ exit(g_cmd);
+}
+else {
+ g_cmd = "window fit;\n";
+ if (SHOW_PROGRESS) {
+ if (RESTORE_MENU_FILE != "") {
+ g_cmd = g_cmd + "script " + RESTORE_MENU_FILE + ";\n";
+ }
+ else {
+ g_cmd = g_cmd + "menu;\n";
+ }
+ }
+
+ exit(g_cmd);
+}
diff --git a/trunk/ulp/pcb-service.ulp b/trunk/ulp/pcb-service.ulp
new file mode 100644
index 00000000..afef1d3a
--- /dev/null
+++ b/trunk/ulp/pcb-service.ulp
@@ -0,0 +1,660 @@
+#usage "en: PCB Quote Service"
+ "
"
+ "Get a quote for manufacturing your PCB. ",
+ "de: PCB-Angebots-Service\n"
+ "
"
+ "Hiermit gelangen Sie zu einem Angebot zur Fertigung Ihres Boards.
"
+ "Autor: support@cadsoft.de
"
+
+// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
+
+#require 5.1000
+int Version = 25; // Refer to versioning system. Needed because ULP version independent from EAGLE version
+
+enum { false = 0, true = 1 };
+
+// Debug stuff
+int Dbg = 0;
+string DbgFile;
+string DbgMsg;
+
+// Messages
+string Warnings;
+int Useless; // When a quote doesn't make sense (e.g empty board or such)
+
+// Design rules
+int Export = 1;
+string DruFile;
+
+// Units / scaling: Handling change of internal units V5 -> V6:
+int UFactor = (EAGLE_VERSION < 6 && EAGLE_RELEASE < 12) ? 1 : 32;
+int PrefUnit; // Preferred unit (representation in dialog)
+
+// Fabrication parameters
+string BoardName;
+int NrLayers;
+int CopperThicknessOutside = INT_MAX;
+int CopperThicknessInside = INT_MAX;
+int MaterialThickness;
+int MinTraceWidth = INT_MAX;
+int MinHoleSize = INT_MAX;
+string SolderSides;
+string SilkScreenSides;
+int NrBlindBuriedTypes;
+int MinPitch = INT_MAX;
+int NrSmdPadsTop;
+int NrSmdPadsBottom;
+
+// Assembly parameters
+int NrPackages;
+int NrThruHoles;
+int NrBGAs;
+int NrQFNs;
+int NrFinePitchs;
+int NrOtherSMDs;
+int HasSMDBothSides;
+
+// For computing width and height
+real XMin = REAL_MAX, XMax = -REAL_MAX, YMin = REAL_MAX, YMax = -REAL_MAX;
+
+// Language support for dialogs: German/English
+// Please keep to alphabetic sorting for better maintainability !
+string Dictionary[] = {
+ "en\v"
+ "de\v",
+ "Assembly Parameters:\v"
+ "Bestückungs-Parameter:\v",
+ "Board length (dimension Y):\v"
+ "Boardlänge (Y-Richtung):\v",
+ "Board name:\v"
+ "Boardname:\v",
+ "Board thickness:\v"
+ "Boarddicke:\v",
+ "Board width (dimension X):\v"
+ "Boardbreite (X-Richtung):\v",
+ "Board width and length could not be determined from dimension layer. \v"
+ "Boardbreite und -länge konnten nicht bestimmt werden anhand des Dimension-Layers. \v",
+ "Both Sides\v"
+ "beidseitig\v",
+ "Bottom Side\v"
+ "unten\v",
+ "Please use the dimension layer to design the board outline.\v"
+ "Bitte benutzen Sie den Dimension-Layer, um die Boardumrisse festzulegen.\v",
+ "Calculating quote parameters...\v"
+ "Berechne Angebots-Parameter...\v",
+ "Change Country:\v"
+ "Land wechseln:\v",
+ "Close\v"
+ "Schliessen\v",
+ "+Continue...\v"
+ "+Weiter...\v",
+ "Copper thickness outer layers:\v"
+ "Kupferstärke aussen:\v",
+ "Copper thickness inner layers:\v"
+ "Kupferstärke innen:\v",
+ "Estimate based on outer layers failed. \v"
+ "Schätzung basierend auf Aussen-Layer fehlgeschlagen. \v",
+ "Estimation based on outer layers. \v"
+ "Schätzung basierend auf Aussen-Layer. \v",
+ "Fabrication Parameters:\v"
+ "Fertigungs-Parameter:\v",
+ "Get PCB Quote\v"
+ "Zum PCB-Angebot\v",
+ "A quote for this board doesn't make sense yet !\v"
+ "Ein Angebot für dieses Board macht noch keinen Sinn !\v",
+ "If you want to get a quote anyway, please follow the link.\v"
+ "Wenn Sie dennoch ein Angebot erhalten wollen, folgen Sie bitte dem Link.\v",
+ "Information:\v"
+ "Hinweise:\v",
+ "Minimum hole size:\v"
+ "Kleinster Bohrdurchmesser:\v",
+ "Minimum SMD pitch:\v"
+ "Kleinster SMD-Abstand:\v",
+ "Minimum trace width (track width):\v"
+ "Kleinste Bahnbreite:\v",
+ "Minimum trace width could not be determined.\v"
+ "Minimale Bahnbreite konnte nicht bestimmt werden.\v",
+ "No copper found in the signal layers. \v"
+ "Kein Kupfer in den Signal-Layern vorhanden. \v",
+ "No\v"
+ "Nein\v",
+ "None\v"
+ "keine\v",
+ "Number of\v"
+ "Anzahl von\v",
+ "Number of blind or buried hole types:\v"
+ "Anzahl von Blind- oder Buried-Bohrungsarten:\v",
+ "Number of different packages:\v"
+ "Anzahl verschiedener Packages:\v",
+ "Number of fine pitch packages:\v"
+ "Anzahl von Fine-Pitch-Packages:\v",
+ "Number of other SMDs:\v"
+ "Anzahl sonstiger SMDs:\v",
+ "Number of SMD pads on bottom:\v"
+ "Anzahl von SMD-Pads unten:\v",
+ "Number of SMD pads on top:\v"
+ "Anzahl von SMD-Pads oben:\v",
+ "Number of thru hole packages: \v"
+ "Anzahl von durchkontaktierten Packages: \v",
+ "Number of layers:\v"
+ "Anzahl Layer:\v",
+ "Wire(s) and/or polygon(s) with zero width found on signal layer(s). \v"
+ "Bahnen und/oder Polygone mit Breite 0 in Signal-Layer(n) gefunden. \v",
+ "None of the signal layers are used.\v"
+ "Keines der Signal-Layer wird verwendet.\v",
+ "Parameters:\v"
+ "Parameter:\v",
+ "PCB Quote Service\v"
+ "PCB-Angebots-Service\v",
+ "Please start from Layout editor !\v"
+ "Bitte starten Sie vom Layout-Editor aus !\v",
+ "Silkscreen sides:\v"
+ "Bestückungsdruck-Seiten:\v",
+ "SMDs on both sides:\v"
+ "SMDs beidseitig:\v",
+ "Solder sides:\v"
+ "Lötseiten:\v",
+ "There are still airwires left.\v"
+ "Es sind noch Luftlinien vorhanden.\v",
+ "Top Side\v"
+ "oben\v",
+ "undefined\v"
+ "unbestimmt\v",
+ "Warnings:\v"
+ "Warnungen:\v",
+ "Yes\v"
+ "Ja\v",
+ "Your board layout is incomplete:\v"
+ "Ihr Board-Layout ist unvollständig:\v"
+};
+
+string DlgLang = language();
+if (DlgLang != "de") DlgLang = "en";
+int LangIdx = strstr(Dictionary[0], DlgLang) / 3;
+
+// Translate, based on dictionary
+string tr(string s) {
+ string t = lookup(Dictionary, s, LangIdx, '\v');
+ return t ? t : s;
+}
+
+string Unknown = tr("undefined");
+
+//- Auxiliary functions -------------------------------------------------------
+
+string GetTargetURL() {
+ return "http://www.element14.com/community/community/knode/pcb_services";
+}
+
+// String handling
+string I2Str(int i) { string str; sprintf(str, "%d", i); return str; }
+string B2Str(int b) { return b ? "true" : "false"; }
+
+// HTML stuff
+string LItem(string txt) { return "
" + txt + "
"; }
+string Bold(string txt) { return "" + txt + ""; }
+
+// Unit handling
+string U2MmStr(int i) { string str; sprintf(str, "%f", u2mm(i)); return str; }
+string U2InStr(int i) { string str; sprintf(str, "%f", u2inch(i)); return str; }
+string U2OzStr(int i) { string str; sprintf(str, "%f", i/(350.0 * UFactor)); return str; }// Todo: Check this !
+// Unit to preferred unit as String with extension !
+string U2PrefUStrExt(int i) { return (PrefUnit == GRID_UNIT_MM) ? U2MmStr(i) + " mm" : U2InStr(i) + " in"; }
+
+int Str2U(string s) {
+ if (strstr(s, "mm") > 0) return int(strtod(s) * 10000 * UFactor);
+ if (strstr(s, "mil") > 0) return int(strtod(s) * 10 * UFactor * 25.4);
+ if (strstr(s, "in") > 0) return int(strtod(s) * 10000 * UFactor * 25.4);
+ if (strstr(s, "mic") > 0) return int(strtod(s) * 10 * UFactor);
+ dlgMessageBox("Unknown unit in design rules !"); exit(EXIT_FAILURE);
+ return 0;
+}
+
+//-------------------------------------------------------
+// Get PCB parameters
+//-------------------------------------------------------
+
+// Means really within, not at the borders
+int Within(int val, int l, int u) { return (val > l) && (val < u); }
+
+int ValidBBox() {
+ return (XMin < REAL_MAX) && (XMax > -REAL_MAX) &&
+ (YMin < REAL_MAX) && (YMax > -REAL_MAX) &&
+ (XMax - XMin > 1000) && (YMax - YMin > 1000); // Could make this much bigger, but that's not crucial (currently 0.1 mm)
+}
+
+/*
+int CheckIfBGA(UL_PACKAGE LBRPAC) {
+// board(B) B.libraries(L) L.packages(PAC)
+// if (PAC.name == pacName) {
+ int i;
+ LBRPAC.contacts(C) {
+ LbrPacConXs[i] = C.x;
+ LbrPacConYs[i++] = C.y;
+ // Get grid dimensions
+ ConXMin = min(ConXMin, C.x);
+ conXMax = max(conXMax, C.x);
+ ConYMin = min(ConYMin, C.y);
+ conYMax = max(conYMax, C.y);
+ if (Dbg) { sprintf(DbgMsg, "LbrPac: (%f %f)\n", u2mm(LbrPacConXs[i-1]), u2mm(LbrPacConYs[i-1])); DbgTxt += DbgMsg; }
+ if (C.smd) {
+ ConDiam = C.smd.dx;
+ // All dx/dy must be equal
+ conDiamMin = min(conDiamMin, C.smd.dx);
+ conDiamMin = min(conDiamMin, C.smd.dy);
+ conDiamMax = max(conDiamMax, C.smd.dx);
+ conDiamMax = max(conDiamMax, C.smd.dy);
+ if (C.smd.roundness - 100 > roundTol) errRound = true;
+ }
+ else {
+ errType = true;
+ break;
+ }
+ }
+ }
+}*/
+
+// Update bounding box with another box
+void UpdateBBoxBox(int xmin, int ymin, int xmax, int ymax) {
+ XMin = min(XMin, xmin);
+ XMax = max(XMax, xmax);
+ YMin = min(YMin, ymin);
+ YMax = max(YMax, ymax);
+}
+
+void UpdateBBoxWire(UL_WIRE W, int layer) {
+ if (W.layer == layer) {
+ real w2 = W.width/2;
+ real xmin = min(W.x1 - w2, W.x2 - w2), ymin = min(W.y1 - w2, W.y2 - w2);
+ real xmax = max(W.x1 + w2, W.x2 + w2), ymax = max(W.y1 + w2, W.y2 + w2);
+ if (W.arc) {
+ if (W.arc.angle2 > 360)
+ xmax = W.arc.xc + W.arc.radius + w2;
+ if (((W.arc.angle1 < 90) && (W.arc.angle2 > 90)) || (W.arc.angle2 > 450))
+ ymax = W.arc.yc + W.arc.radius + w2;
+ if (((W.arc.angle1 < 180) && (W.arc.angle2 > 180)) || (W.arc.angle2 > 540))
+ xmin = W.arc.xc - W.arc.radius - w2;
+ if (((W.arc.angle1 < 270) && (W.arc.angle2 > 270)) || (W.arc.angle2 > 630))
+ ymin = W.arc.yc - W.arc.radius - w2;
+ }
+ UpdateBBoxBox(xmin, ymin, xmax, ymax);
+ }
+}
+
+void UpdateBBoxCircle(UL_CIRCLE C, int layer) {
+ if (C.layer == layer) {
+ real w2 = C.width / 2;
+ UpdateBBoxBox(C.x - C.radius - w2, C.y - C.radius - w2, C.x + C.radius + w2, C.y + C.radius + w2);
+ }
+}
+
+void UpdateBBox(int layer, int el_origin) {
+ board(B) {
+ B.wires(W) UpdateBBoxWire(W, layer);
+ B.circles(C) UpdateBBoxCircle(C, layer);
+ B.elements(E) {
+ if (el_origin) UpdateBBoxBox(E.x, E.y, E.x, E.y); // Elements are always on signal layers.
+ E.package.wires(W) UpdateBBoxWire(W, layer);
+ E.package.circles(C) UpdateBBoxCircle(C, layer);
+ }
+ }
+}
+
+void GetDruParams() {
+ string lines[];
+ int nrlines = fileread(lines, DruFile);
+ if (nrlines == 0) dlgMessageBox("Error reading design rules !");
+ int layer_used[], nrlayers, bottom_idx;
+
+ for (int i = 0; i < nrlines; ++i) {
+ string words[];
+ int nrwords = strsplit(words, lines[i], ' ');
+ if (nrwords < 3) continue; // Empty line or some other stuff
+ string keyword = words[0];
+ if (keyword == "layerSetup")
+ for (int k = 1; k <= 16; ++k) {
+ string nr_pattern;
+ sprintf(nr_pattern, "[\\D]%d[\\D]", k); // Number, surrounded by 'no number character'
+ if (strxstr(words[2], nr_pattern) != -1) {
+ layer_used[k - 1] = true;
+ ++NrLayers;
+ bottom_idx = k - 1;
+ }
+ }
+ else if (keyword == "mtCopper") {
+ if (nrwords != 18) dlgMessageBox("Unexpected design rules !");
+ int top_thickness = -1, bot_thickness;
+ for (int k = 2; k < nrwords; ++k) {
+ if (layer_used[k - 2]) {
+ int thickness = Str2U(words[k]);
+ if (top_thickness == -1)
+ top_thickness = thickness;
+ else if (k - 2 == bottom_idx)
+ bot_thickness = thickness;
+ else
+ CopperThicknessInside = min(thickness, CopperThicknessInside);
+ MaterialThickness += thickness;
+ }
+ }
+ CopperThicknessOutside = min(top_thickness, bot_thickness);
+ }
+ else if (keyword == "mtIsolate") {
+ if (nrwords != 17) dlgMessageBox("Unexpected design rules !");
+ // n used layers => n-1 isolate layers. If only 1 layer, also 1 isolate layer.
+ for (int k = 2; k < nrwords; ++k)
+ if (layer_used[k - 2])
+ MaterialThickness += Str2U(words[k]);
+ }
+ else if (keyword == "mdSmdSmd")
+ MinPitch = Str2U(words[2]);
+ }
+}
+
+void CalcMinTraceWidth() {
+ board(B) {
+ B.wires(W) if (W.layer <= 16) MinTraceWidth = min(W.width, MinTraceWidth);
+ B.signals(S) {
+ S.polygons(P) if (P.layer <= 16) MinTraceWidth = min(P.width, MinTraceWidth);
+ S.wires(W) if (W.layer <= 16) MinTraceWidth = min(W.width, MinTraceWidth);
+ }
+ }
+}
+
+void CheckHoles() {
+ int idx[], start[], end[], k;
+ board(B) {
+ B.holes(H) MinHoleSize = min(MinHoleSize, H.drill);
+ B.signals(S) S.vias(V) {
+ MinHoleSize = min(MinHoleSize, V.drill);
+ // Collect blind/buried holes !
+ if ((V.start > 1) || (V.end < 16)) {
+ start[k] = V.start;
+ end[k] = V.end;
+ ++k;
+ }
+ }
+ B.elements(E) {
+ E.package.contacts(C) if (C.pad)
+ MinHoleSize = min(MinHoleSize, C.pad.drill);
+ E.package.holes(H) MinHoleSize = min(MinHoleSize, H.drill);
+ }
+ }
+ // NrBlindBuriedTypes: Find out how many different ones exist !
+ sort(k, idx, start, end);
+ for (int l = 0, cur_s = 0, cur_e = 0; l < k; ++l)
+ if ((start[idx[l]] != cur_s) || (end[idx[l]] != cur_e)) {
+ ++NrBlindBuriedTypes;
+ cur_s = start[idx[l]];
+ cur_e = end[idx[l]];
+ }
+}
+
+void GetPCBParams() {
+ // Check out layers:
+ int smask_top, smask_bottom, silk_top, silk_bottom;
+ int nr_used_layers;
+ board(B) {
+ BoardName = filename(B.name);
+ B.layers(L) if (L.used)
+ if (L.number <= 16) ++nr_used_layers;
+ else if (L.number == LAYER_TSTOP) smask_top = 1;
+ else if (L.number == LAYER_BSTOP) smask_bottom = 1;
+ else if (L.number == LAYER_TPLACE) silk_top = 1; // Could also take TNAMES/TVALUES. Leave the criterium less strict
+ else if (L.number == LAYER_BPLACE) silk_bottom = 1; // Could also take BNAMES/BVALUES. Leave the criterium less strict
+ }
+ SolderSides = smask_top ? (smask_bottom ? "Both Sides" : "Top Side") :
+ (smask_bottom ? "Bottom Side" : "None");
+ SilkScreenSides = (silk_top) ? (silk_bottom ? "Both Sides" : "Top Side") :
+ (silk_bottom ? "Bottom Side" : "None");
+ if (nr_used_layers == 0) {
+ Warnings += LItem(tr("None of the signal layers are used."));
+ Useless = 1;
+ }
+
+ // Board outlines:
+ UpdateBBox(LAYER_DIMENSION, 0);
+ if (!ValidBBox()) {
+ Warnings += "
" + tr("Board width and length could not be determined from dimension layer. ");
+ UpdateBBox(LAYER_TOP, 1);
+ UpdateBBox(LAYER_BOTTOM, 1);
+ if (!ValidBBox())
+ Warnings += tr("Estimate based on outer layers failed. ") +
+ tr("Please use the dimension layer to design the board outline.") + "