Files
SyncHome/trunk/ulp/Felicitas_PCBSim.ulp
paolo.iocco ab6f495c89
2023-03-09 10:24:21 +00:00

975 lines
37 KiB
Plaintext

#usage "en:<b>Felicitas PCBSim</b><p>"
"Pre-Layout Simulation (PreSim)<br>"
"<p>"
"RUN Felicitas_PCBSim /E | Export data.<br>"
"RUN Felicitas_PCBSim /I | Export attributes of selected instance.<br>"
"RUN Felicitas_PCBSim /S | Setup option<br>"
"RUN Felicitas_PCBSim /RELOAD | Import of simulation values."
"<p>"
"Wait on handshake by file polling."
"<p>"
"<author>Author: alf@cadsoft.de</author>"
,
"de:<b>Felicitas PCBSim</b><p>"
"Pre-Layout Simulation (PreSim)<br>"
"<p>"
"RUN Felicitas_PCBSim /E | Daten-Export.<br>"
"RUN Felicitas_PCBSim /I | Exportiert nur die Attribute der selektierten Instanz.<br>"
"RUN Felicitas_PCBSim /S | Setup Option.<br>"
"RUN Felicitas_PCBSim /RELOAD | Import der simulierten Werte."
"<p>"
"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.<br>"
"SET CONTEXT instance 'PCBsim' 'RUN Felicitas_PCBSim /I';"
"<p>"
"Globale Attribute für die Übergabe von Werten (Design-Regeln) müssen mit 'FEL_' beginnen.<br>"
"Jedes globale Attribute wird mit \"@GLOBAL\" gekennzeichnet."
"<p>"
"<author>Author: alf@cadsoft.de</author>"
#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 <b>" + OS_SIGNATURE + "</b> 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<n; f++) {
searchfoundfile[cntf] = SearchFiles[f];
return searchfoundfile[cntf]; // das erst gefunden File zurückgeben
cntf++;
}
}
}
if (finish || (maxiteration && iteration == maxiteration)) break;
// 2. die Root-Ordner nach Ordnern durchsuchen
for (r = SearchStart; r < SearchEnd; r++) {
sprintf(h, "%d %d %s", iteration, SearchnRoot, SearchRoot[r]);
status(h); // Anzeige des aktuellen Verzeichnisnamen
n = fileglob(a, SearchRoot[r] + "/"); // lesen der Dateien
if (n) {
for (int xl = 0; xl < n; xl++) {
sprintf(h, "%s\n", a[xl]);
if (a[xl][strlen(a[xl])-1] == '/') { // nach Verzeichnis suchen
SearchRoot[SearchnRoot] = a[xl];
sprintf(h, "%d %d %s", iteration, SearchnRoot, SearchRoot[SearchnRoot]);
status(h); // Anzeige des aktuellen Verzeichnisnamen
SearchnRoot++;
}
else {
break;
}
}
}
}
SearchStart = r;
SearchEnd = SearchnRoot; // Suchende erweitern
if (SearchStart == SearchEnd) {
finish = 1;
}
iteration++;
} while(SearchnRoot);
return searchfoundfile[0];
}
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;
}
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("<hr>");
dlgCell( 5, 2) dlgLabel("<hr>");
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 <b>" + pcbsimpresent[1] + "</b> 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);
}