/************************************************************************/ /* Hahn-Meitner-Institut Berlin */ /* Bereich Strukturforschung */ /* Abteilung NI / BENSC */ /* Glienicker Strasse 100 */ /* D-14109 Berlin (Wannsee) */ /* Software:K. Emmelmann, Tel.(030)8062-2588, Mail: klaus@dvwbs5.hmi.de */ /************************************************************************/ /* Datei: SEL.C */ /* Teil von: KWS.C */ /* Anwendung bei: V4 - KWS */ /* Titel: Treiberprogramm fuer Geschwindigkeitsselektor DORNIER */ /* Version: 1.0 vom: 30.1.96 */ /************************************************************************/ /* Legende ======= 30.1.96 Emmelmann Implementierung 1.2.96 Emmelmann Statusdekodierung eingebaut 27.2.96 Emmelmann Strom wird auch im Status geliefert Das Handbuch sagt Empfangsterminator ist Linefeed. Jeder Befehl erzeugt ein Echo; argumentlose Befehle werden im Echo zusaetzlich mit einer Zahl versehen, deren Bedeutung unbekannt ist. FEHLERMELDUNGEN, die bekannt sind: **************************************** 1. Solldrehzahl zu klein ! 2. Solldrehzahl zu gross ! 3. derzeit keine Ausfuehrung moeglich ! 4. Solldrehzahl in einem kritischen Bereich - return to m 5. HOCHFAHREN 1 6. zu 3: Abfrage der Istgeschwindigkeit ist waehrend des Hochfahrens aus dem Stillstand nur ueber Lesen des Gesamtstatus moeglich zu 4: es gibt verbotene Geschwindigkeitsbereiche zu 5: beim Uebergang von Stop in den gestarteten Zustand Zeitliches Protokollverhalten ----------------------------- Wird ein Befehl bearbeitet, werden alle weiteren ueber die serielle Schnittstelle einlaufenden Befehle ignoriert - auch nicht gepuffert ! Max. Befahlsrate: 1 Befehl / 5 Sekunden Geraete-Verhalten ----------------- Der Startbefehl faehrt den Selektor auf die Minimalgeschwindigkeit (3100U/min) Das Protokoll: fuer jeden Befehl erzeugt der Selektor-PC ein Echo ! Host -> Selektor ------------------------ REM (disabled) Remote-Betrieb einschalten Rueckmeldung: ENABLED / Host nicht betriebsbereit! TTY (disabled) Local-Betrieb einschalten Rueckmeldung: DISABLED ??? Sende Status (Status ist nicht fest und geht von der Interpretation der Kennworte aus !) TIM (disabled) Setzen des Zeitintervalles zur Time-Out-Ueberwachung des PCs ???? SST Start des Selektors und Ausregeln der Drehzahl (Nur wenn der Selektor steht !); liefert als Rueckmeldung die Solldrehzahl SDR nnnnn Vorgabe einer Soll-Drehzahl und geregelten Betrieb einschalten. 3100 => nnnnn <=28300 U/min; liegt der Wert in einem kritischen Bereich (geht aus Setup-Menue hervor), kommt eine entsprechende Rueckmeldung FDR Sende die Solldrehzahl (Format 'RPM n') STB Leerlauf ohne Regelung BRE Beginne eine Verlustleistungsmessung - ist bei Statusabruf lesbar, wenn dort die Betriebsart regeln erscheint ! HAL Bremse Selektor bis zum Stillstand ab (unterhalb 3000 U/min.) */ #include stdio.h #include descrip.h #include iodef.h #include errno.h #include lnmdef.h #define FALSE 0 #define TRUE !FALSE #define OK 0L #define NOT_OK !OK #define LIMIT_U 3100 /* niedrigste Drehzahl */ #define LIMIT_O 28300 /* Verbotene Drehzahlbereiche (Resonanzgefahr) */ #define RESONANZ_1U 3648 #define RESONANZ_1O 4552 #define RESONANZ_2U 5248 #define RESONANZ_2O 6449 #define RESONANZ_3U 9148 #define RESONANZ_3O 9949 #define TOK_BUF_L 25 #define SELE_LUN 0 extern FILE *fs; static short chan_s=6; /* *********************************************************************** */ /* ------------------------------------------------------------------------ */ long select_setup() { register rc; $DESCRIPTOR(dev_descr, "TXA1:"); chan_s=SELE_LUN; if ((rc=sys$assign(&dev_descr, &chan_s, NULL,NULL)) != 1) {printf("Error in Selector_SETUP: Ret = %d\n",rc); return(NOT_OK);} return(OK); } /* ------------------------------------------------------------------------ */ /* Function liest ueberprueft das Befehlsecho */ long sele_test_echo(cmd, lng) char *cmd[]; int lng; { char echo[80]; if (sele_read(&echo)!= OK) return(NOT_OK); if (strncmp(&echo, cmd, lng) != 0) {printf("Selector:protocol error%s\n",echo); return(NOT_OK);} else return(OK); } /* ------------------------------------------------------------------------ */ /* Function prueft die Anzahl der sich im Typeahead-Buffer befindenden Bytes und liefert das naechste dort anstehende Zeichen, jedoch ohne es aus dem Puffer zu entnehmen. */ long tst_buf_s(bt) int *bt; { int bytes; register rc; struct {unsigned short status, bytes; int pid; } iosb; if ((rc=sys$qiow(NULL,chan_s,IO$_SENSEMODE | IO$M_TYPEAHDCNT,&iosb, NULL, NULL, &bytes, NULL, NULL, NULL, NULL, NULL)) != 1) {print_error(fs,"Error in QIOW"); return(NOT_OK);} /**ch = (bytes >> 16) & 0xff;*/ *bt = bytes & 0xffff; return(OK); } /* ------------------------------------------------------------------------ */ long sele_read(message) char *message; { char char_l[8], *ptr; register rc; struct {unsigned short status, bytes; int pid; } iosb; ptr = message; for (;;) { if ((rc=sys$qiow(NULL,chan_s,IO$_READVBLK | IO$M_NOECHO, &iosb,NULL, NULL, char_l, 1, NULL, NULL, NULL, NULL)) != 1) {printf("Error in QIOW, READ_MESS: %d\n", rc);return(NOT_OK);} *ptr = char_l[0]; /* Terminator (linefeed) ? */ ptr++; if (char_l[0] == '\n') break; } return(OK); } /* ------------------------------------------------------------------------ */ /* Pruefe ob der Selektor eine Fehlermeldung erzeugt hat und gib sie aus */ long select_error_msg(err) long *err; { char chr[10], msg[80]; float waiti=3.0; /* Selektor PC hat 3 Sekunden Reaktionszeit !! */ /* Warte ein wenig - es koennte auf den Befehl hin eine Fehlermeldung erscheinen */ lib$wait(&waiti); /* Es koennen auch mehrere Zeilen sein */ *err = FALSE; for (;;) {if (tst_buf_s(&chr) != OK) return(NOT_OK); if (chr[0] != NULL) { if (sele_read(&msg) != OK) return(NOT_OK); printf("Selektor failure:"); printf("%s\n\7",msg); *err = TRUE; } else return(OK); } } /* ------------------------------------------------------------------------ */ long sele_write(message) char message[]; { char msg[80]; long err; register rc; struct { unsigned short status, bytes; int pid; } iosb; if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); if ((rc=sys$qiow(NULL,chan_s,IO$_WRITEVBLK,&iosb,NULL, NULL, message, strlen(message), NULL, NULL, NULL, NULL)) != 1) {printf("Error in QIOW: %d\n",rc); return(NOT_OK);} return(OK); } /* -------------------------------------------------------------------------- */ /* Ein-/ Ausschalten von Stoerungsmeldungen vom Selektor an den Host Diese Funktion ist z.Z. nur vom Selektor-PC aktivierbar */ long select_msg(tim) long tim; { int sts; long err; char cmd[20] = "TIM "; sprintf(&cmd+4,"%5u\0",tim); sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); return(OK); } /* -------------------------------------------------------------------------- */ /* Einschaltung der Fremdsteuerung des Selektors Diese Funktion ist z.Z. nur vom Selektor-PC aktivierbar */ long select_remote() { int sts; long err; char cmd[] = "REM"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Ausschaltung der Fremdsteuerung des Selektors - ein Steuerung kann dann nur noch ueber den PC des Geraetes erfolgen. Diese Funktion ist z.Z. nur vom Selektor-PC aktivierbar */ long select_local() { int sts; long err; char cmd[] = "TTY"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Starten des Selektors nach Stillstand auf die Minimaldrehzahl */ long select_start() { int sts; long err; char cmd[] = "SST"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Bremsen des Selektors bis zum Stillstand; eine Drehzahlanzeige unterhalb 3000 U/min ist nicht moeglich. */ long select_stop() { int sts; long err; char cmd[] = "HAL"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Einschalten des geregelten Betriebes mit dem Setzen eines Sollwertes der Drehzahl. Aenderungen werden spontan uebernommen und ausgefuehrt. Neben dem absoluten Minimum und Maximum existieren verbotene Drehzahlbereiche, die z.Z. noch nicht exakt bekannt sind. */ long select_set_rpm(rpm) int rpm; { int sts; long err; char cmd[] = "SDR", s_dat[10] = "SDR 00000"; if ((rpm < LIMIT_U) || (rpm > LIMIT_O)) { print_error(fs,"nominal value out of allowed range"); return; } /* Resonanzbereiche sind auch verboten */ if ( ((rpm >= RESONANZ_1U) && (rpm <= RESONANZ_1O)) || ((rpm >= RESONANZ_2U) && (rpm <= RESONANZ_2O)) || ((rpm >= RESONANZ_3U) && (rpm <= RESONANZ_3O))) { print_error(fs,"nominal value within inhibited range"); return; } sprintf(&s_dat+4,"%5u",rpm); sts = sele_write(s_dat); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Leerlauf des Selektors einschalten; weder Antrieb noch Verzoegerung erfolgen - eine anschliessende Abbremsung oder ein Uebergang zum geregelten Betrieb ist moeglich. */ long select_set_idle() { int sts; long err; char cmd[] = "STB"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Starten der Messung der elektrischen Verlustleistung des Selektors. Anscheinend wird waehrend der Zeit die Regelung deaktiviert. Nach Abschluss der Messung erfolgt ein Uebergang in den\ geregelten Berieb. Das Messergebnis wird in den Statusinformationsblock eingetragen. */ long select_read_power() { int sts; long err; char cmd[] = "BRE"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Lesen der aktuellen Drehzahl des Selektors */ long select_read_rpm(rpm) int *rpm; { int sts, tmp; long err; char status[80], cmd[] = "FDR"; sts = sele_write(cmd); if (sele_test_echo(&cmd,3)!= OK) lib$stop(-1); sts = sele_read(&status); sscanf(&status+4,"%d",&tmp); *rpm = tmp; if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); } /* -------------------------------------------------------------------------- */ /* Auslesen des kompletten Statusblockes des Selektors. Der Informationseintrag 'Verlustleistung' ist anscheinend nur dann aktuell, wenn zuvor eine Verlustleistungsmessung aktiviert wurde. Argumente: rm = Betriebsstatus [REG == regelnd] [STB == im Leerlauf] [BRE == bremsend] nom_rpm = Soll der Drehzahl (U/min) cur_rpm = Ist der Drehzahl (U/min) pwr = Verlustleistung (W) curr = elektr. Stomstaerke (A) rot_temp= Temperatur des Rotors (C) cont_temp= Temperatur des Gehaeuses (C) inl_temp= Temperatur Kuehlwasser-Einlass outl_temp= Temperatur Kuehlwasser-Abfluss cool_wat= Kuehlwasser-Durchfluss (l/min) vacuum = Betriebsvakuum (mbar) accel = Rotationsbeschleunigung (g) komm = Kommunikation zwischen Selektor-PC und Host 'ENABLED' oder "DISABLED' dat = Tagesdatum dd.m.yyyy tim = Tageszeit hh.mm.s */ long select_read_status(rm,nom_rpm, cur_rpm, pwr, curr, rot_temp, cont_temp, inl_temp, outl_temp, cool_wat, vacuum, accel, komm, dat, tim) char *rm[]; int *nom_rpm, *cur_rpm, *pwr, *rot_temp, *cont_temp, *inl_temp, *outl_temp; float *cool_wat, *vacuum, *accel, *curr; char *dat[], *tim[]; short *komm; { int cnt, key_id, sl, sts; long err; char ena_str[] = "ENABLED"; char dis_str[] = "DISABLED"; char keys[15][9] = { "Status:\0 ", "S_DREH:\0 ", "I_DREH:\0 ", "P_VERL:\0 ", "STROM:\0 ", "T_ROT:\0 ", "T_GEH:\0 ", "T_VOR:\0 ", "T_RUECK:\0", "DURCHFL:\0", "VAKUUM:\0 ", "BESCHL:\0 ", "KOM: \0 ", "DATE: \0 ", "TIME: \0 "}; char tok_buf[TOK_BUF_L], *ptr_token, *ptr_src, *ptr, tok_c[] = "/\0"; char status[255], cmd[] = "???"; if (sele_write(cmd) != OK) return(NOT_OK); if (sele_test_echo(&cmd, 3) == NOT_OK) lib$stop(-1); if (sele_read(&status) != OK) return(NOT_OK); /* Und nun der Status */ ptr_src = &status; for (;;) { /* Lies Zeichenfolge bis zum naechsten Trennzeichen '/' */ ptr_token = strtok(ptr_src, &tok_c); ptr_src = NULL; /* fuer die weitere Suche notwendig */ if (ptr_token == NULL) break; strcpy(&tok_buf,ptr_token); for (key_id = 0; key_id<=14; key_id++) { /* Ist das Schluesselwort enthalten ? */ sl = strlen(keys[key_id]); if (strncmp(&keys[key_id][0], &tok_buf, sl) == NULL) { /* Schiebe das Schluesselwort raus */ for (cnt=0;cnt+sl < TOK_BUF_L; cnt++) tok_buf[cnt] = tok_buf[cnt+sl]; switch (key_id) { case 0: { ptr = rm; strcpy(ptr, &tok_buf); break; } case 1: {sscanf(&tok_buf,"%d",nom_rpm); break;} case 2: {sscanf(&tok_buf,"%d",cur_rpm); break;} case 3: {sscanf(&tok_buf,"%d",pwr); break;} case 4: {sscanf(&tok_buf,"%f",curr); break;} case 5: {sscanf(&tok_buf,"%d",rot_temp); break;} case 6: {sscanf(&tok_buf,"%d",cont_temp); break;} case 7: {sscanf(&tok_buf,"%d",inl_temp); break;} case 8: {sscanf(&tok_buf,"%d",outl_temp); break;} case 9: {sscanf(&tok_buf,"%f",cool_wat); break;} case 10: {sscanf(&tok_buf,"%f",vacuum); break;} case 11: {sscanf(&tok_buf,"%f",accel); break;} case 12: { if (strcmp(&tok_buf, &ena_str) == NULL) {*komm = TRUE; break;} if (strcmp(&tok_buf, &dis_str) == NULL) {*komm = FALSE;break;} printf("Invalid Communication value"); break; } case 13: { ptr = dat; strcpy(ptr, &tok_buf); break; } case 14: { ptr = tim; strcpy(ptr, &tok_buf); break; } } } } } if (select_error_msg(&err) != OK) return(NOT_OK); if (err == TRUE) return(NOT_OK); return(OK); }