#include #include #include #include #include #include #include #include #include #include #include "myc_mem.h" #include "myc_err.h" #include "coc_util.h" #include "coc_server.h" #include "coc_logfile.h" #include "myc_str.h" #include "myc_time.h" #include "tecs_lsc.h" #include "tecs_data.h" #include "logger.h" /* --- non ANSI signal --- */ #ifndef SIGPIPE #define SIGPIPE 13 #endif #define TABLE_FILE "tecs.cfg" #define DEV_LIST "dev.list" #define LSC_CODES "lsc.codes" #define LOGLIFETIME 24*3600 static SerChannel *ser=NULL; static char binDir[256]=""; static char logDir[256]=""; static char loggerDir[256]=""; static int logIt=0, use_stdout=0; static char serverId[32]="tecs"; static int msecTmo=5000; static char host[64]=""; static int port=9753; typedef struct { char ch[4]; float t, t0, t1, t2, min, max, band; /* temperatures */ float scale; /* scale for extreme ranges */ float kink; /* for T > kink values are scaled kink > RT for thermocouples going to more than 1500 K */ float lim; /* precise range limit (used when two sensors are present) */ float alarm; int customAlarm; int stat1, stat2; /* reading status summary */ int present; /* 0: sensor inactive, 1: sensor configured, -1: sensor parameters read */ int readStat; /* reading status */ int dispfld; char curve[32]; /* name of curve file */ char type[4]; char dispfmt; char typ; } SensorT; enum Sensors { A, B, C, D, A1, A2, A3, A4, N_SENSORS }; static SensorT sensA={"A"}, sensB={"B"}, sensC={"C"}, sensD={"D"}, sensA1={"A1", DATA_UNDEF}, sensA2={"A2", DATA_UNDEF}, sensA3={"A3", DATA_UNDEF}, sensA4={"A4", DATA_UNDEF}, *sensors[N_SENSORS]={&sensA, &sensB, &sensC, &sensD, &sensA1, &sensA2, &sensA3, &sensA4 }, *ctlSens=NULL, /* control sensor */ *heliumSens=NULL, *auxSens=NULL, *testSens=NULL, *test2Sens=NULL, *sens=&sensA; typedef struct { SensorT *sensor1, *sensor2; float temp; /* weighted temperature */ float t1, t2; /* minimum and maximum temperatures since ... */ } Testpoint; static Testpoint /* C standard guarantees initialization to zero */ cryo, /* data for heat exchanger, or the only sensors */ samp, /* data for sensors on sample stick */ *tpoints[2]={&cryo, &samp}, *tpoint=&cryo; typedef struct _Plug { SensorT *sensor1, *sensor2; int devcmd; /* 1: device configured by command, 0: by cabling code */ int code, code1, code2; /* device code, buffers for device code */ int codChanged; /* code has changed */ int codDefined; /* code is not yet confirmed */ char device[16]; /* device name */ char descr[80]; } Plug; static Plug plug0={&sensA, &sensB }, /* data for sensors on plug0 */ plug1={&sensC, &sensD }, /* data for sensors on plug1 */ *plugs[2]={&plug0, &plug1}, *plug=&plug0; static float set, /* set T */ setH, /* set T on heat exchanger */ htr, power=DATA_UNDEF, /* heater current percentage, heater power */ tLimit, /* temperature limit */ tMaxLimit, /* maximal temperature limit */ maxPowerFlt, /* max. Power */ maxCurrent, /* maxCurrent (not really reached for resist > 25 Ohm */ powFact=1, /* power factor (for external power supplies) */ resist=10, /* heater resistance */ empty, full, /* empty/full value for helium level */ prop, integ, deriv, /* pid */ int2=1200.0, /* integration time (sec) for doublecontrol */ tShift=0, /* setpoint shift */ maxShift=10, /* maximal shift for doublecontrol */ propUp=0.5, /* upper limit coefficient (doublecontrol) */ propDown=0.8, /* lower limit coefficient (doublecontrol) */ tm=DATA_UNDEF, /* main temperature */ ts=DATA_UNDEF, /* sample temperature */ tx=DATA_UNDEF, /* controlled temperature */ tr=DATA_UNDEF, /* set temperature (read back) */ te=DATA_UNDEF, /* test temperature */ tk=DATA_UNDEF, /* test temperature 2 */ he=DATA_UNDEF, /* helium level value */ aux=DATA_UNDEF, /* auxiliary value */ scanChan=DATA_UNDEF, /* scan channel */ ramp=0, slope=0, smooth=0, fbuf, /* float buffer */ r1, r2, /* temporary values */ still=0, linearPower=0, /* normally 0. Maximum power when loop=2 and the power linear to the output */ shiftUp, shiftLow, /* upper and lower limit of tShift correction */ state, mout; static int logPeriod=5, /* data logging period (sec.) */ period=5000, /* default read interval (msec.) */ logTime, /* next logging time */ settingsFlag, /* settings to be done */ saveTime, /* time for a CRVSAV command */ noResp=1, /* no response */ quit, /* quit server */ controlMode=0, /* obsolete (now controlSensor/doubleControl) 0: control on heater, 1: control on sample, 2: 2nd loop for difference heater-sample */ doubleControl=0, manual=0, remoteMode, /* 1: local, 2: remote */ local, /* 0: remote, 1: local */ maxfld, /* last used display field */ busy, /* busy after CRVSAV */ relay, relay0, /* relay status */ num, /* curve number */ key, /* key status */ serialNo=340000, /* initialize with a valid, but not existing value */ lscVersion, /* firmware version date yyyymmdd */ readTemp, /* client requested readTemp */ cod1, cod2, out1, out2, /* codes read from digital input/output */ iRange, iAmp, /* max. range and max. current code */ jRange, /* range code, jRange=iRange if controller did not switch off */ ibuf, /* temporary int. buffer */ htrst, htrst0, /* heater status */ loop=1, /* active loop */ touched, /* user touched keys */ tim0, /* msec Time */ per, /* effective period */ mmInt, mmTime, /* interval and time for next min-max logging */ nScan=0, /* number of scanned channels */ alarmListSize=0, keepT=0, /* keep control over power-up */ swRangeOn=60, /* when not happen several times within less than 60 sec. delay, switch heater range on when controller switched it off */ initMaxPower=0, /* set MaxPower for the first time */ lockAlarm, cntError; static int tim, rdTim; /* actual time, read Time */ static int decod[8]={21,20,17,16,5,4,1,0}; /* for code conversion */ static char statusBuf[132], /* phase status */ error[128], /* error message */ status[1000], /* status summary */ pid[128], /* PID summary */ device[64], /* concatenated device names */ buf1[256], buf2[256], buf3[256], buf4[256], /* buffers for temporary use */ head[64], /* curve header */ intype[64], /* input configuration */ chan[4], /* actual channel */ alarmStatus[20], /* alarm status */ config[256], /* special configuration commands */ helium[80], /* helium level status */ heUnits[4], /* helium level units */ alarmChannels[N_SENSORS], alarmHistory[N_SENSORS], swap[4], controlSensor[4], /* '0': main two, '1': sample two, or any of "slmntkabcd" */ dev[80], devHelp[10000], update[32], /* update script option */ lscfg[256], /* lsc commands for configuration */ maxPower[128], controlChannel[4]="A"; static char *alarmList[N_SENSORS], /* enabled alarms */ *table=NULL, /* environment devices table */ *cache=NULL, /* curve list cache */ *logfile=""; static int logMask=LOG_MAIN; static float gradata[COC_RES_LEN/4-100]; static char grapar[128]; static int* grasize; static char ttp[80]; /* temperature, target and power */ typedef struct { char cmd[COC_CMD_LEN]; int logstart; long int logpos; char logline[COC_RES_LEN]; } ClientData; /* static ClientData clInit; static ClientData *clData=&clInit; */ static ClientData *clData; void ignore_forever(int signo) { signal(signo,ignore_forever); } int IdleHdl(int tmo, int fd) { int iRet; iRet=CocHandleRequests(tmo, fd); if (iRet<0) logfileShowErr("CocHandleRequests"); return iRet; } void *SetClientData(void *data) { ClientData *cl; if (data==NULL) { NEW(cl, ClientData); return cl; } clData = data; return NULL; OnError: return NULL; } void ConcatDevice(void) { str_copy(device, plug0.device); if (0!=strcmp(plug0.device, plug1.device) && (plug1.device[0]!='\0' || plug1.devcmd)) { str_append(device, "/"); str_append(device, plug1.device); } if (device[0]=='\0') return; } int PutPermanentData(FILE *fil) { char buf[256]; char *d1, *d2; if (plug0.devcmd) { d1="*"; } else { d1=""; } if (plug1.devcmd) { d2="*"; } else { d2=""; } sprintf(buf, "%s%s/%s%s/%d/%d\n", d1, plug0.device, d2, plug1.device, plug0.code, plug1.code); ERR_SI(fputs(buf, fil)); return 0; OnError: return -1; } int InstalCurve(SensorT *sensor, char *devArg) { /* install sensor */ char nam[32], buf[256], chead[64], nbuf[256], lbuf[16]; char *crv, *entry, *points, *start, *s, /* start of found entry */ *e, /* cache part after found entry */ *t; int i, n; char used[60]; FILE *fil; sens=sensor; str_copy(chan, sens->ch); ERR_P(LscCmd(ser, "FILTER [chan]:1,64,10")); sens->present=0; if (sens->typ=='x' || sens->typ=='h' || sens->typ=='f') { if (chan[0]>='C') { ERR_P(LscCmd(ser, "INTYPE [chan]:0,1,2,1,13;INSET [chan],1")); /* 7.5 V Range */ } else { ERR_P(LscCmd(ser, "INTYPE [chan]:0,1,2,1,12;INSET [chan],1")); /* 5 V Range */ } if (sens->typ=='f') { ERR_P(LscCmd(ser, "MNMX [chan]:1,4;INCRV [chan]:0")); } else { ERR_P(LscCmd(ser, "MNMX [chan]:1,3;INCRV [chan]:0")); } if (settingsFlag==0) sens->present=1; return 0; } fil=NULL; crv=NULL; e=NULL; sprintf(nam, "%s_%c", devArg, sens->typ); logfileOut(LOG_MAIN+LOG_STAT, "install curve %s\n", nam); /* read curve file */ str_copy(nbuf, binDir); if (sensor->curve[0]=='\0') { /* old style file name */ str_append(nbuf, nam); } else { str_append(nbuf, sensor->curve); } str_append(nbuf, ".crv"); ERR_P(crv=str_read_file(nbuf)); t=str_split(chead, crv, '\n'); if (t==NULL) { points=NULL; } else { points=str_split(intype, t, '\n'); } if (points==NULL) ERR_MSG("illegal curve file"); if (cache==NULL) { ERR_SP(cache=MALLOC(1)); *cache='\0'; } /* create empty cache if undefined */ start=strchr(cache, '\n'); /* skip permanent data */ if (start==NULL) { start=cache; } else { start++; } if (points[0]=='$') { /* standard curve */ points++; num=atoi(points); if (num>20) ERR_MSG("illegal standard curve number"); ERR_P(LscCmd(ser, "CRVHDR?[num]>head")); } else { if (sensor->curve[0]!='\0') { strcpy(buf, ","); str_append(buf, sensor->curve); str_append(buf, " "); str_upcase(buf, buf); } else { strcpy(buf, ":"); str_append(buf, nam); str_append(buf, " "); str_upcase(buf, buf); } entry=strstr(start, buf); if (entry==NULL) { /* sensor not found in cache */ entry=start; for (i=60;i>20;i--) used[i]=0; n=40; num=0; while (entry!=NULL && n>0) { i=0; sscanf(entry, "%d", &i); if (i>20 && i<=60) { num=i; s=entry; used[i]=1; n--; } entry=strchr(entry, '\n'); if (entry !=NULL) entry++; } if (n>0) { for (num=60;num>20;num--) { if (used[num]==0) break; } s=NULL; e=NULL; } else { e=strchr(s, '\n'); if (e!=NULL) { *e='\0'; e++; } if (s>start) { s--; *s='\0'; } } head[0]='\0'; } else { s=entry; entry++; while (s>start && *s!='\n') s--; if (s>start) { *s='\0'; s++; } num=0; sscanf(s, "%d", &num); if (num<21 || num>60) ERR_MSG("illegal curve number"); ERR_P(LscCmd(ser, "CRVHDR?[num]>head")); e=strchr(entry, '\n'); if (e!=NULL) { *e='\0'; e++; } } } if (num > 20 && strlen(chead) > 10) { /* replace name by a more meaningful */ for (i=0; i<10 && i20) i=12; /* check only from 12th character (CRC) for user curves */ if (head[0]!='\0' && LscEqPar(head+i, chead+i)) { /* header matches: select sensor type and curve */ if (i>0 && !LscEqPar(head, chead)) { /* name does not match */ str_upcase(head, chead); ERR_P(LscCmd(ser, "CRVHDR [num]:[head]")); } if (chan[1]>'1') { /* scanned inputs A2...A4 */ ERR_P(LscCmd(ser, "INCRV?[chan]>buf2;INSET?[chan]>buf3")); str_copy(buf1, intype); } else { ERR_P(LscCmd(ser, "INTYPE?[chan]>buf1;INCRV?[chan]>buf2;INSET?[chan]>buf3")); } if (!LscEqPar(buf1, intype) || atoi(buf2)!=num || buf3[0]!='1') { ERR_P(LscCmd(ser, "ANALOG 2:0,3;INSET [chan],1")); if (chan[1]<='1') ERR_P(LscCmd(ser, "RANGE:0;INTYPE [chan]:[intype]")); ERR_P(LscCmd(ser, "INCRV [chan]:[num];MNMX [chan]:1,1")); logfileOut(LOG_MAIN, "curve %d on channel %s selected\n", num, chan); } else { logfileOut(LOG_MAIN, "curve %d on channel %s is already selected\n", num, chan); } } else { /* header does not match -> download */ logfileOut(LOG_MAIN, "%s\n%s\n", head, chead); if (num<=20) ERR_MSG("standard curve does not match"); if (busy) ERR_MSG("busy"); logfileOut(LOG_MAIN+LOG_STAT, "download curve %d\n", num); ERR_P(LscCmd(ser, "ANALOG 2:0,3;INSET [chan],1")); /* select sensor type first */ if (chan[1]<='1') ERR_P(LscCmd(ser, "RANGE:0;INTYPE [chan]:[intype]")); n=3; do { /* try to delete curve 3 times */ ERR_P(LscCmd(ser, "CRVDEL [num];CRVHDR?[num]>buf1,")); buf1[4]='\0'; i=strcmp(buf1, "User"); n--; } while (i!=0 && n!=0); if (i!=0) ERR_MSG("can not delete curve"); /* store header, but without name (curve format must be determined before loading points) */ t=strchr(chead, ','); if (t==NULL) ERR_MSG("illegal header"); str_copy(buf2, t); ERR_P(LscCmd(ser, "CRVHDR [num]:[buf2]")); sprintf(lbuf, "CRVPT %d", num); i=0; do { /* download curve */ t=str_split(nbuf, points, '\n'); if (nbuf[0]!='\0') { ERR_I(str_substitute(buf, nbuf, "#0", lbuf)); if (lscVersion<20030000 || strstr(buf,":0,0")==NULL) { ERR_P(LscCmd(ser, buf)); } else { logfileOut(LOG_MAIN, "skip %s\n", buf); } i++; sprintf(statusBuf, "downloading curve %d at line %d", num, i); } points=t; } while (t!=NULL); /* write header, select curve */ str_upcase(head, chead); ERR_P(LscCmd(ser, "CRVHDR [num]:[head];INCRV [chan]:[num];MNMX [chan]:1,1")); logfileOut(LOG_MAIN, "curve %d selected on channel %s\n", num, chan); saveTime=tim+30; } FREE(crv); crv=NULL; if (sens->scale != 1.0 || sens->kink != 0.0) { /* scaling for display */ fbuf = sens->kink * (1.0 - sens->scale); ERR_P(LscCmd(ser, "LINEAR [chan]:1,[sens.scale],1,1,[fbuf]")) } if (settingsFlag==0) sens->present=1; /* if (num<=20) return 0; */ /* standard curve, do not touch cache */ /* rewrite cache with actual entry at beginning */ str_copy(nbuf, logDir); str_append(nbuf, "lsc.tmp"); fil=fopen(nbuf, "w+"); if (fil==NULL) ERR_SP(fil=fopen(nbuf, "w")); ERR_I(PutPermanentData(fil)); if (num>20) { /* write actual entry */ sprintf(buf, "%d:%s", num, head); ERR_SI(fputs(buf, fil)); } if (start!=s) { /* write content before replaced entry */ if (num>20) { ERR_SI(fputs("\n", fil)); } ERR_SI(fputs(start, fil)); } if (e!=NULL) { /* write content after replaced entry */ ERR_SI(fputs("\n", fil)); ERR_SI(fputs(e, fil)); } ERR_SI(fputc('\0', fil)); ERR_SI(fclose(fil)); str_copy(buf, logDir); sprintf(lbuf, "lsc.%d", serialNo); str_append(buf, lbuf); rename(nbuf, buf); /* rename to permanent version */ fil=NULL; FREE(cache); /* re-read it */ ERR_P(cache=str_read_file(buf)); /* for vms: */ str_append(buf, ";-1"); remove(buf); /* remove old version */ buf[strlen(buf)-2]='\0'; /* strip off "-1" */ rename(buf, buf); /* lower version number */ return 0; OnError: if (crv!=NULL) FREE(crv); if (fil!=NULL) fclose(fil); return -1; } int ReadTable(void) { /* obsolete */ char nbuf[256]; if (table!=NULL) { FREE(table); table=NULL; }; str_copy(nbuf, binDir); str_append(nbuf, TABLE_FILE); ERR_P(table=str_read_file(nbuf)); return 1; OnError: return -1; } void InitSensor(SensorT *s) { s->t=DATA_UNDEF; s->scale=1; s->kink=0; s->lim=0; s->alarm=0; s->customAlarm=0; s->present=0; s->curve[0]='\0'; s->type[0]='\0'; } int PrepInput(char *label) { char *t, *e; char nam[16], chans[8], typ; char buf[256]; int i, j, l; SensorT *s; char *cfg; if (label[0]=='\'') { str_copy(nam, label+1); nam[strlen(nam)-1]='\0'; /* strip off quote */ } else { str_copy(nam, label); } again: str_copy(buf, binDir); str_append(buf, nam); str_append(buf, ".cfg"); cfg=str_read_file(buf); if (cfg==NULL) { /* will be obsolete */ logfileOut(LOG_MAIN, "%s not found, try tecs.cfg\n", buf); ERR_I(ReadTable()); t=strstr(table, label); if (t==NULL) ERR_MSG("device not found"); e=strchr(t, '\''); if (e==NULL || e>strchr(t,'\n')) ERR_MSG("missing ' or device name in table file"); t=e+1; } if (cfg && *cfg=='@') { /* alias */ t=strchr(cfg,'\n'); if (t) *t='\0'; str_copy(nam, cfg+1); str_copy(plug->device, nam); FREE(cfg); goto again; } if (plug==&plug0) { InitSensor(&sensA); InitSensor(&sensB); slope=0; ramp=0; controlMode=0; doubleControl=0; controlSensor[0]='0'; linearPower=0; powFact=1; config[0]='\0'; lscfg[0]='\0'; tLimit=0; tMaxLimit=0; keepT=0; swRangeOn=60; loop=1; initMaxPower=1; resist=10; } else { InitSensor(&sensC); InitSensor(&sensD); } empty=0; dev[0]='\0'; str_copy(heUnits, "%"); if (cfg==NULL) { /* will be obsolete */ i=sscanf(t, "%12s%n", nam, &l); if (i<1) ERR_MSG("missing device name"); nam[strlen(nam)-1]='\0'; /* strip off quote */ t+=l; str_copy(chans, "____"); i=sscanf(t, "%8s%n", chans, &l); if (i<1) ERR_MSG("missing chans"); t+=l; /* interprete settings until '+' appeares (after whitespace) */ ERR_P(CocReadVars(t, '+')); if (strlen(chans)>4) ERR_MSG("no more than 4 channels allowed"); } else { ERR_P(CocReadVars(cfg, '\0')); } if (loop!=2) loop=1; if (plug==&plug0) { j=0; } else { j=2; } str_copy(plug->descr, dev); if (cfg==NULL) { /* will be obsolete */ sensA.type[0]=chans[0]; sensA.type[1]='\0'; sensB.type[0]=chans[1]; sensB.type[1]='\0'; sensC.type[0]=chans[2]; sensC.type[1]='\0'; sensD.type[0]=chans[3]; sensD.type[1]='\0'; } if (sensA.type[0]>'0' && sensA.type[0]<='4') { nScan=sensA.type[0]-'0'; for (i=4;i<4+nScan;i++) { s=sensors[i]; s->present=-1; s->band=10; if (s->scale==0.0) s->scale=1.0; s->typ='1'+i-4; } sensA.type[0]='\0'; for (i=4+nScan; it=DATA_UNDEF; sensors[i]->present=0; } } if (tLimit==0.0) { if (tMaxLimit==0.0) { tLimit=310; tMaxLimit=350; } else { tLimit=tMaxLimit-10; } } else if (tMaxLimit==0.0) { tMaxLimit=tLimit+10; } else if (tLimit>tMaxLimit) { tLimit=tMaxLimit; } maxPowerFlt=25; sscanf(maxPower, "%f", &maxPowerFlt); for (i=j; itype[0]; if (typ=='_') typ='\0'; if (NULL==strchr("mnslhxftk", typ)) ERR_MSG("unknown channel type code"); if (typ!='\0') { s->present=-1; } s->typ=typ; s->band=10; if (s->scale==0.0) s->scale=1.0; if ((s->alarm==0.0 && typ=='m') || typ=='s') { s->alarm=tMaxLimit; s->customAlarm=0; } else { s->customAlarm=1; } } if (!plug->devcmd) { /* set device name */ str_copy(plug->device, nam); ConcatDevice(); } if (cfg) { FREE(cfg); } return 0; OnError: if (cfg) { FREE(cfg); } return -1; } int LoadCache(void) { int i, j, k; char *res; char buf[256], nbuf[256], lbuf[16]; char *bufi[4]; FILE *fil; fil=NULL; sprintf(lbuf, "lsc.%d", serialNo); str_copy(nbuf, logDir); str_append(nbuf, lbuf); ERR_SP(fil=fopen(nbuf, "w")); ERR_I(PutPermanentData(fil)); bufi[0]=buf1; bufi[1]=buf2; bufi[2]=buf3; bufi[3]=buf4; for (i=60; i>21; i-=4) { sprintf(buf, "CRVHDR?%d>buf1;CRVHDR?%d>buf2;CRVHDR?%d>buf3;CRVHDR?%d>buf4", i, i-1, i-2, i-3); ERR_P(LscCmd(ser, buf)); k=0; for (j=i; j>i-4; j--) { res=bufi[k]; k++; if (res[1]=='s') { i=0; break;} /* s of "User", must be an empty slot, lowercase letters are not programmable */ sprintf(buf, "%d:", j); ERR_SI(fputs(buf, fil)); ERR_SI(fputs(res, fil)); ERR_SI(fputs("\n", fil)); } } ERR_SI(fclose(fil)); /* re-read cache */ ERR_P(cache=str_read_file(nbuf)); return 0; OnError: if (fil!=NULL) fclose(fil); return -1; } float TrueScale(SensorT *s, float val) { float tval; if (s==NULL) { return val; } else { if (val > s->kink) { tval = (val - s->kink) * s->scale + s->kink; } else { tval = val; } return tval; } } float FakeScale(SensorT *s, float val) { float fval; if (s==NULL) { return val; } else { if (val > s->kink) { fval = (val - s->kink) / s->scale + s->kink; } else { fval = val; } return fval; } } float WeightedAverage(float tH, float tL, Testpoint *t) { float p,q, tLow, tHigh; SensorT *s1, *s2; if (tH==DATA_UNDEF) tH=0.0; if (tL==DATA_UNDEF) tL=0.0; s1=t->sensor1; s2=t->sensor2; tH = TrueScale(s1, tH); tL = TrueScale(s2, tL); if (tH!=0.0) { if (tL!=0.0) { tLow=s1->lim; tHigh=s2->lim; if (tL<=tLow) { return tL; } else if (tHsensor1; s2=tpoint->sensor2; tpoint->t1 = WeightedAverage(s1->min, s2->min, tpoint); tpoint->t2 = WeightedAverage(s1->max, s2->max, tpoint); if (fabsf(tpoint->t1 - tpoint->temp) < fabsf(tpoint->t2 - tpoint->temp)) { tbuf = tpoint->t1; tpoint->t1 = tpoint->t2; tpoint->t2 = tbuf; } s1->min=0; s1->max=0; s2->min=0; s2->max=0; } if (cryo.t1!=DATA_UNDEF) { sprintf(buf1, " Tm %.5g _ %.5g", cryo.t1, cryo.t2); str_append(buf, buf1); } if (cryo.sensor1!=samp.sensor1 && samp.t1!=DATA_UNDEF) { sprintf(buf1, " Ts %.5g _ %.5g", samp.t1, samp.t2); str_append(buf, buf1); } if (tr!=DATA_UNDEF) { sprintf(buf1, " Tr %.5g", tr); str_append(buf, buf1); } if (te!=DATA_UNDEF) { sprintf(buf1, " Te %.5g", te); str_append(buf, buf1); } if (tk!=DATA_UNDEF) { sprintf(buf1, " Tk %.5g", tk); str_append(buf, buf1); } } else if (nScan==0) { return; } for (i=4; i<4+nScan; i++) { s1=sensors[i]; if (s1->t!=DATA_UNDEF) { sprintf(buf1, " T%c %.5g", s1->ch[1], s1->t); str_append(buf, buf1); } } if (power!=DATA_UNDEF) { sprintf(buf1, " P %.4g", power); str_append(buf, buf1); } if (he!=DATA_UNDEF) { sprintf(buf1, " He %.4g", he); str_append(buf, buf1); } if (aux!=DATA_UNDEF) { sprintf(buf1, " Aux %.5g", aux); str_append(buf, buf1); } if (new==2) { mmTime=mmTime+30; first=1; } else { if (first==0) { logfileOut(LOG_MAIN, "%s\n", buf); } else { first=0; } if (new) { mmInt=30; } else { mmInt=60; } mmTime=((tim+mmInt/2)/mmInt+1)*mmInt-logPeriod; } } SensorT *findSensor(char txt) { int i; SensorT *s; s = NULL; txt = tolower(txt); if (strchr("01slmntkabcde", txt) != 0) { for (i=0; i<4; i++) { if (txt == tolower(sensors[i]->ch[0]) || txt == sensors[i]->typ) { s = sensors[i]; } } } return s; } void SetCtlSens(void) { SensorT *s; if (controlSensor[0] == '1') { tShift=0; if (ctlSens==NULL) { ctlSens=samp.sensor1; } else if (ctlSens==samp.sensor1) { if (set < ctlSens->lim) { ctlSens=samp.sensor2; } } else if (ctlSens==samp.sensor2) { if (set > ctlSens->lim) { ctlSens=samp.sensor1; } } else { ctlSens=samp.sensor1; } if (controlMode != 2) { controlMode = 1; } } else if (controlSensor[0] == '0') { if (!doubleControl) { tShift=0; } if (ctlSens==NULL) { ctlSens=cryo.sensor1; } else if (ctlSens==cryo.sensor1) { if (set < ctlSens->lim) { ctlSens=cryo.sensor2; } } else if (ctlSens==cryo.sensor2) { if (set > ctlSens->lim) { ctlSens=cryo.sensor1; } } else { ctlSens=cryo.sensor1; } if (controlMode != 2) { controlMode = 0; } } else { s = findSensor(controlSensor[0]); if (s) { ctlSens = s; if (controlMode != 2) { if (s->typ == 's' || s->typ == 'l') { controlMode = 1; } else { controlMode = 0; } } } else { ctlSens = cryo.sensor1; /* should always be defined */ if (controlMode != 2) { controlMode = 0; } } } } int ReadTemp(void) { char buf[256], typ, *err, dispfmt; int i, doit, stat; int tfill, dfill; static int iScan=0; float hlev; SensorT *s; readTemp=0; doit=0; if (nScan>0) { while (1) { /* read until a non-selected channel found */ if (iScan>=nScan) iScan=0; s=sensors[iScan+4]; if (s->present<1) break; str_copy(chan, s->ch); ERR_P(LscCmd(ser, "KRDG?[chan]>fbuf;DIOST?>,out1")); if (out1==iScan) break; s->t=fbuf; iScan++; } } for (i=0; i<4; i++) { s=sensors[i]; s->stat1=0; s->stat2=0; if (s->present) { if (doit) ERR_P(LscCmd(ser, buf)); if (i<4) { str_substitute(buf , "KRDG?#>sens#.t0;MDAT?#>sens#.t1,sens#.t2;MDATST?#>sens#.stat1,sens#.stat2" , "#", s->ch); } else { str_substitute(buf , "KRDG?#>sens#.t1;RDGST?#>sens#.stat1;DIOST?>,sens#.stat2" , "#", s->ch); } if (s->typ=='h' || s->typ=='x') { buf[0]='S'; /* change KRDG to SRDG */ typ='S'; } else if (s->typ=='f') { buf[0]='L'; /* change KRDG to LDAT */ buf[1]='D'; buf[2]='A'; buf[3]='T'; } doit=1; } } if (doit) { if (ramp!=0) { str_append(buf, ";SETP?[loop]>fbuf"); } str_append(buf, ";MNMXRST"); ERR_P(LscCmd(ser, buf)); SetCtlSens(); if (manual) { tr=DATA_UNDEF; } else if (ramp!=0) { tr=TrueScale(ctlSens, fbuf); } else { tr=TrueScale(ctlSens, setH); } if (tr==0) tr=DATA_UNDEF; } /* check for reading errors, determine legal value */ for (i=0; i<4; i++) { s=sensors[i]; if (s->present) { if (i>=4) { if (s->stat2==i-4) { /* ignore reading, if channel was active (may be noisy) */ s->t1 = s->t; } s->t2 = s->t1; s->stat2 = s->stat1; } if (set != 63.0 && (s->t1 == 63.0 || s->t2 == 63.0 || s->t0 == 63.0)) { /* probably noisy values */ logfileOut(LOG_MAIN, "magic %s: %g %g %g\n", s->ch, s->t1, s->t2, s->t0); } stat=(s->stat1 & s->stat2) & (255-3); /* ignore "old reading" and "invalid reading", error must be on min & max */ if (stat > s->readStat || (stat==0 && s->readStat>0)) { err=LscReadStat(stat); if (*err=='\0') { logfileOut(LOG_MAIN, "reading o.k. %s\n", s->ch); } else { logfileOut(LOG_MAIN, "%s %s\n", err, s->ch); } s->readStat=stat; } if (stat==0) { if (s->typ=='h') { hlev = s->t1; /* take minimum only */ if (full!=empty) { hlev=(hlev-empty)/(full-empty); if (hlev<1.0 && hlev>0.0) { he=hlev*100.0; s->t=he; tfill = tim % (24*3600) / 60; /* min since midnight */ dfill = mycDate(tim) % 10000; /* fill date without year */ sprintf(helium, "%.3g %s (%02d.%02d., %02d:%02d)", he, heUnits , dfill % 100, dfill / 100, tfill / 60, tfill % 60); } } } else if (s->t2 - s->t1 <= s->band*2) { /* normal case */ s->t = (s->t1 + s->t2) * 0.5; /* mean of min and max */ s->band = s->band/2; } else { if (s->t1 < 0.8 * s->t2) { /* probably noisy values */ logfileOut(LOG_MAIN, "min/max %s: %g %g\n", s->ch, s->t1, s->t2); } s->t=s->t0; s->t1 = s->t; s->t2 = s->t; } if (s->t1 < s->min || s->min==0.0) s->min = s->t1; if (s->t2 > s->max) s->max = s->t2; if (s->max - s->min > s->band) { s->band = s->max - s->min; } if (s->scale > 1.0 && s->kink != 0) { if (s->t > s->kink) { dispfmt='4'; } else { dispfmt='1'; } if (dispfmt != s->dispfmt) { /* change display format */ s->dispfmt = dispfmt; sprintf(buf, "DISPFLD %d,%s,%c", s->dispfld, s->ch, dispfmt); ERR_P(LscCmd(ser, buf)); } } } else { s->t=DATA_UNDEF; } } else { s->t=DATA_UNDEF; } } rdTim=mycNow(); tm=DATA_UNDEF; ts=DATA_UNDEF; if (cryo.sensor1!=NULL) { cryo.temp=WeightedAverage(cryo.sensor1->t, cryo.sensor2->t, &cryo); samp.temp=WeightedAverage(samp.sensor1->t, samp.sensor2->t, &samp); tm=cryo.temp; if (samp.sensor1!=cryo.sensor1) { ts=samp.temp; } if (samp.temp==DATA_UNDEF) { samp.temp=cryo.temp; } } else if (nScan==0) { tm=(rdTim % 3600) * 1.0e-4; ts=(rdTim % 60) * 60.0e-4+0.5; } if (doubleControl) { tx=ts; } else if (ctlSens) { tx=TrueScale(ctlSens, ctlSens->t); } if (auxSens != NULL) { aux=TrueScale(auxSens, auxSens->t); } else { aux=DATA_UNDEF; } if (testSens != NULL) { te=TrueScale(testSens, testSens->t); } else { te=DATA_UNDEF; } if (test2Sens != NULL) { tk=TrueScale(test2Sens, test2Sens->t); } else { tk=DATA_UNDEF; } if (heliumSens == NULL) { he=DATA_UNDEF; } return 0; OnError: return -1; } float Percent2Power(float percent) { float curr; if (linearPower != 0) { return percent/100*linearPower; } curr=maxCurrent*percent/100; return curr*curr*resist*powFact; } float Power2Percent(float power) { if (linearPower != 0) { return power/linearPower*100; } return sqrt(power/powFact/resist)/maxCurrent*100; } int ReadHeater(int full) { static time_t lastOff=0; static int cntOff=3; time_t now; if (loop==1) { if (full) { if (relay) { ERR_P(LscCmd(ser, "HTRST?>htrst")); htr=0; } else { ERR_P(LscCmd(ser, "HTR?>htr;HTRST?>htrst;RELAYST?1>relay;RANGE?>ibuf")); if (jRange!=0 && ibuf==0) { if (swRangeOn) { time(&now); if (lastOff > 0) { if (now > lastOff + swRangeOn * 2) { if (cntOff < 3) cntOff++; } else if (now < lastOff + swRangeOn) { cntOff--; } } lastOff = now; if (cntOff > 0) { logfileOut(LOG_MAIN, "controller switched heater off - switch on again (%d more tries)\n", cntOff-1); ERR_P(LscCmd(ser, "RANGE:[jRange]")); } else { logfileOut(LOG_MAIN, "controller switched heater off definitely (happened to often)\n"); jRange=0; } } else { logfileOut(LOG_MAIN, "controller switched heater off\n"); jRange=0; } } } } else { ERR_P(LscCmd(ser, "HTR?>htr")); } } else { ERR_P(LscCmd(ser, "AOUT?2>htr")); htrst=0; } if (htr == 0 && set == 0 && manual == 0) { power=DATA_UNDEF; } else { power=Percent2Power(htr); if (power>maxPowerFlt) power=maxPowerFlt; } return 0; OnError: return -1; } int SetTemp(int switchOn) { int showSet; float tc; float tLim; if (set<0 || set>tLimit) { set=0; logfileOut(LOG_MAIN, "set point not within (0 ... %g), reset to 0\n", tLimit); } if (switchOn) { ERR_I(ReadTemp()); LogMinMax(switchOn); } SetCtlSens(); if (ctlSens==NULL) return 0; str_copy(chan, ctlSens->ch); if (!doubleControl) { tShift=0.0; } tLim = (tLimit+tMaxLimit)*0.5; if (set+tShift <= 0) { /* set + tShift must not be negative */ tShift = -0.999 * set; } else if (set + tShift > tLim) { /* prevent limit overshoot */ tShift = tLim - set; } setH=FakeScale(ctlSens, set+tShift); if (setH > FakeScale(ctlSens, tLim)) setH=FakeScale(ctlSens, tLim); if (switchOn) { /* switch off other loop */ if (loop==1) { ERR_P(LscCmd(ser, "CSET 2:[chan],1,0,0")); } else { ERR_P(LscCmd(ser, "CSET 1:[chan],1,0,0")); } if (ramp > 0 && set != 0) { /* take ramp from actual temperature if more than 10 % deviation */ ERR_P(LscCmd(ser, "CSET?[loop]>,,cod1;SETP?[loop]>fbuf")); if (loop == 1 && cod1 != 0) { ERR_P(LscCmd(ser, "RANGE?>cod1")); } /* cod1 == 0 --> heater is off */ tr=TrueScale(ctlSens, fbuf); tc=TrueScale(ctlSens, ctlSens->t); if (cod1 == 0 || fabsf(tc - tr) >= 0.1 * tc) { fbuf = ctlSens->t; tr = TrueScale(ctlSens, fbuf); ERR_P(LscCmd(ser, "SETP [loop],[fbuf];RAMP [loop],0,0;SETP [loop],[fbuf]")); } } } if (set==0) { mout=0; ERR_P(LscCmd(ser, "CSET [loop]:[chan],1,1,[keepT];MOUT [loop],0")); if (loop==1) { ERR_P(LscCmd(ser, "RANGE:0")); jRange=0; } else { ERR_P(LscCmd(ser, "ANALOG 2:0,0")); } setH=0; } else if (switchOn) { /* switch on also when bad heater message and no alarms: || (htrst>=5 && !relay)) */ ERR_P(LscCmd(ser, "CSET [loop]:[chan],1,1,[keepT]")); if (loop==1) { ERR_P(LscCmd(ser, "RANGE:[iRange]")); jRange=iRange; } else { ERR_P(LscCmd(ser, "ANALOG 2:0,3")); } } else { ERR_P(LscCmd(ser, "CSET?[loop]>,buf1,")); if (buf1[0] != '1') { ERR_P(LscCmd(ser, "CSET [loop]:[chan],1")); } } showSet=(0!=strcmp(ctlSens->ch, controlChannel) || switchOn); str_copy(controlChannel, ctlSens->ch); if (ramp==0 || set==0) { ERR_P(LscCmd(ser, "RAMP?[loop]>buf1,")); if (buf1[0] != '0') { ERR_P(LscCmd(ser, "RAMP [loop]:0,[ramp]")); } ERR_P(LscCmd(ser, "SETP?[loop]>fbuf")); if (fabsf(setH-fbuf) >= (fbuf+setH)*1.0e-5) { ERR_P(LscCmd(ser, "SETP [loop]:[setH]")); if (!doubleControl && !showSet) { logfileOut(LOG_MAIN, "set %g (on %s) (was changed %g -> %g)\n", set, ctlSens->ch, fbuf, setH); } } else { setH=fbuf; } tr=TrueScale(ctlSens, setH); if (showSet) { logfileOut(LOG_MAIN, "set %g (on %s)\n", set, ctlSens->ch); } } else { if (ramp < 0) ramp=-ramp; if (ramp < 0.1) ramp=0.1; if (showSet) { ERR_P(LscCmd(ser, "RAMP [loop]:1,[ramp];SETP [loop],[setH];SETP?[loop]>fbuf")); } else { ERR_P(LscCmd(ser, "SETP?[loop]>fbuf")); if (fabs(fbuf-setH) >= ramp*smooth) { fbuf=ramp; } else { fbuf=sqrt(fabs(fbuf-setH)*ramp/smooth); if (fbuf<0.1) fbuf=0.1; } ERR_P(LscCmd(ser, "RAMP [loop]:1,[fbuf];SETP [loop],[setH]")); ERR_P(LscCmd(ser, "SETP?[loop]>fbuf")); } tr=TrueScale(ctlSens, fbuf); if (showSet) { logfileOut(LOG_MAIN, "set %g (on %s) %g K/min, starting from %g\n", set, ctlSens->ch, ramp, tr); } } if (tr==0) tr=DATA_UNDEF; if (showSet) { /* relay=0; */ ERR_I(ReadHeater(1)); } return 0; OnError: return -1; } void CalcMaxPower(void) { int i, j; struct { float p; int iAmp, iRange; } low, high, *best; float pa, pr, p, plim; float h, maxAt; char warning[128]; iAmp=1; iRange=0; maxCurrent=0; if (maxPowerFlt>0) { if (resist<1) resist=10; maxCurrent = 1; /* must be 1 for Power2Percent */ h=Power2Percent(maxPowerFlt)/100; p=h*h*resist; /* power before amplifier */ plim=2500/resist; /* power limited by 50 V output. U*U/R=2500/R */ if (p>plim) p=plim; pa=resist*4; /* max. maxPower R*I*I (I=2 A) */ low.p = 0; low.iRange = 0; high.p = resist*6; high.iRange = 0; for (i=4; i>0; i--) { pr=pa; for (j=5; j>0; j--) { if (pr > p) { if (pr < high.p) { high.p = pr; high.iAmp = i; high.iRange = j; } } else { if (pr > low.p) { low.p = pr; low.iAmp = i; low.iRange = j; } } pr=pr/10; } pa=pa/4; } if (high.iRange == 0) { best = &low; if (low.iRange == 0) { return; } } else if (low.iRange == 0) { best = &high; } else if (p > low.p*1.1) { best = &high; } else { best = &low; } warning[0]='\0'; maxAt = 100; if (best->p > plim) { maxAt = sqrt(plim/best->p)*100; maxPowerFlt=Percent2Power(100*sqrt(plim/resist)); } else { maxPowerFlt=Percent2Power(100*sqrt(best->p/resist)); } snprintf(maxPower, sizeof maxPower, "%.5g", maxPowerFlt); if (best->p > p * 1.01) { if (low.iRange != 0) { snprintf(warning, sizeof warning, "next lower value: %.4g", Percent2Power(100*sqrt(low.p/resist))); } else { snprintf(warning, sizeof warning, "rounded up to minimal value"); } } else if (best->p < p * 0.99) { if (high.p > plim) high.p = plim; if (high.p < resist * 5) { snprintf(warning, sizeof warning, "next higher value: %.4g", Percent2Power(100*sqrt(high.p/resist))); } else { snprintf(warning, sizeof warning, "rounded down to maximal value"); } } else if (p < h*h*resist * 0.99) { snprintf(warning, sizeof warning, "rounded down to maximal value"); } if (maxAt < 99.0) { str_append(maxPower, " ("); if (warning[0] != '\0') { str_append(maxPower, warning); str_append(maxPower, ", "); } snprintf(warning, sizeof warning, "maximum power already at %.1f %%", maxAt); str_append(maxPower, warning); str_append(maxPower, ")"); } else if (warning[0]!='\0') { str_append(maxPower, " ("); str_append(maxPower, warning); str_append(maxPower, ")"); } maxCurrent=sqrt(best->p/resist); iRange = best->iRange; iAmp = best->iAmp; assert(maxCurrent>0); } } int PutFloat(StrBuf *buf, int prec, float f) { char num[32], fmt[32]; if (f == DATA_UNDEF) { return StrPut(buf, "NaN", StrNONE); } else { sprintf(fmt, "%%.%dg", prec); sprintf(num, fmt, f); return StrPut(buf, num, StrNONE); } } int PidSumHdl(int mode, void *base, int fd) { StrBuf buf; StrLink(&buf, pid); StrClear(&buf); ERR_I(PutFloat(&buf, 5, prop)); ERR_I(StrPut(&buf, " ", StrNONE)); ERR_I(PutFloat(&buf, 5, integ)); ERR_I(StrPut(&buf, " ", StrNONE)); ERR_I(PutFloat(&buf, 4, deriv)); ERR_I(StrPut(&buf, " /", ' ')); ERR_I(PutFloat(&buf, 4, prop*maxCurrent*resist/600)); ERR_I(StrPut(&buf, " A/K,", ' ')); if (integ == 0.0) { ERR_I(StrPut(&buf, " inf,", ' ')); } else { ERR_I(PutFloat(&buf, 4, 1000.0/integ)); ERR_I(StrPut(&buf, " sec,", ' ')); } ERR_I(PutFloat(&buf, 4, deriv)); ERR_I(StrPut(&buf, " sec/maxCurrent", ' ')); if (maxCurrent>0.5) { ERR_I(PutFloat(&buf, 4, maxCurrent)); ERR_I(StrPut(&buf, " A", StrNONE)); } else { ERR_I(PutFloat(&buf, 4, maxCurrent*1000)); ERR_I(StrPut(&buf, " mA", StrNONE)); } return 0; OnError: return -1; } int SetMaxPower(void) { /* static float p0; */ static float lastCurrent, limCurrent, pold; /* float plim; */ if (loop == 1) { if (initMaxPower) { ERR_P(LscCmd(ser, "CLIMIT?1>,,,iAmp,iRange")); pold=0; } else { iRange=0; } if (iRange>0) { lastCurrent=pow(2.0,iAmp-3)*pow(sqrt(10.0),iRange-5); /* p0=resist*pow(4.0,iAmp)*pow(10.0,iRange)/6.4e6*powFact; plim=2500/resist*powFact; pold=p0; if (pold>plim) pold=plim; */ if (resist<1) resist=10; limCurrent=50/resist; /* 50 V max. */ if (limCurrent > lastCurrent) limCurrent=lastCurrent; pold=limCurrent*limCurrent*resist; } CalcMaxPower(); } else if (linearPower != 0) { maxCurrent = 1; maxPowerFlt = linearPower; } else { maxCurrent=10/resist; /* 10 V max. */ if (maxCurrent>0.1) { limCurrent=0.1; /* 0.1 A max. */ } else { limCurrent=maxCurrent; } maxPowerFlt=limCurrent*limCurrent*resist; } logfileOut(LOG_MAIN, "maxPower changed from %g to %g\n", pold, maxPowerFlt); if (manual) { cod1=3; } else { cod1=1; } ERR_P(LscCmd(ser, "CDISP 1:[loop],[resist],1;MOUT [loop]:0;CMODE [loop]:[cod1]")); mout=0; jRange=0; if (slope<0) slope=-slope; if (slope!=0 && slope<0.1) slope=0.1; SetCtlSens(); fbuf=FakeScale(ctlSens, (tLimit + tMaxLimit)*0.5); if (loop==1) { PidSumHdl(COC_RD, NULL, 0); if (!initMaxPower && lastCurrent != maxCurrent && lastCurrent != 0) { logfileOut(LOG_MAIN, "pid: %s\nlast %f max %f\n", pid, lastCurrent, maxCurrent); prop=prop*lastCurrent/maxCurrent; } ERR_P(LscCmd(ser, "CLIMIT 1:[fbuf],[slope],0,[iAmp],[iRange];PID [loop],[prop]")); } else { ERR_P(LscCmd(ser, "CLIMIT 2:[fbuf],[slope],0")); } initMaxPower=0; lastCurrent=maxCurrent; pold=maxPowerFlt; PidSumHdl(COC_RD, NULL, 0); logfileOut(LOG_MAIN, "pid: %s\n", pid); return 0; OnError: return -1; } int ConfigAlarms(float genLimit) { int i, k; SensorT *s; ERR_P(LscCmd(ser, "RELAY 1:1;BEEP:0")); relay=0; k=0; for (i=0;i<4+nScan;i++) { s=sensors[i]; str_copy(buf1, s->ch); if (s->customAlarm==0 && genLimit>0.0) s->alarm=genLimit; if (s->present==1 && s->alarm>0) { r1=FakeScale(s, s->alarm); ERR_P(LscCmd(ser, "ALARM [buf1]:1,1,[r1],0,1,1")); alarmList[k]=s->ch; k++; } else { ERR_P(LscCmd(ser, "ALARM [buf1]:0")); /* switch off unused alarms */ } } alarmListSize=k; return 0; OnError: return -1; } int LoadFromLsc(void) { ERR_P(LscCmd(ser, "PID?[loop]>prop,integ,deriv")); ERR_P(LscCmd(ser, "RAMP?[loop]>,ramp")); ERR_P(LscCmd(ser, "ANALOG?1>,,,,,,fbuf")); still=fbuf*fbuf/70; return 0; OnError: return -1; } int DisplayFmt(SensorT *s, SensorT *fields[], int *dispfld) { if (s==NULL || s->present<=0 || s->typ=='h' || *dispfld>4) return 0; if (s->typ == 'x') { s->dispfmt='3'; } else if (s->typ == 'f') { s->dispfmt='4'; } else { if (s->scale == 1.0 || s->kink > 0.0) { s->dispfmt='1'; } else { s->dispfmt='4'; } } s->dispfld=*dispfld; fields[*dispfld]=s; *dispfld=*dispfld+1; /* logfileOut(LOG_MAIN, "display %d %c\n", *dispfld, s->dispfmt); */ return 1; } void AssignTypes(void) { int i; char typ; SensorT *s; cryo.sensor1=NULL; cryo.sensor2=NULL; samp.sensor1=NULL; samp.sensor2=NULL; heliumSens=NULL; auxSens=NULL; testSens=NULL; test2Sens=NULL; for (i=0; i<4+nScan; i++) { s=sensors[i]; if (s->present==1) { typ=s->typ; if ('m'==typ) { if (cryo.sensor2==NULL) cryo.sensor2=s; cryo.sensor1=s; } else if ('n'==typ) { if (cryo.sensor1==NULL) cryo.sensor1=s; cryo.sensor2=s; } else if ('s'==typ) { if (samp.sensor2==NULL) samp.sensor2=s; samp.sensor1=s; } else if ('l'==typ) { if (samp.sensor1==NULL) samp.sensor1=s; samp.sensor2=s; } else if ('h'==typ) { heliumSens=s; } else if ('x'==typ || 'f'==typ) { auxSens=s; } else if ('t'==typ) { testSens=s; } else if ('k'==typ) { test2Sens=s; } s->band=10; } } if (cryo.sensor1==NULL) { if (samp.sensor1==NULL) { if (testSens==NULL) { cryo.sensor1=test2Sens; } else { cryo.sensor1=testSens; } } else { cryo.sensor1=samp.sensor1; } cryo.sensor2=cryo.sensor1; } if (samp.sensor1==NULL) { samp.sensor1=cryo.sensor1; samp.sensor2=cryo.sensor2; } } int Settings(void) { char buf[256]; SensorT *s; SensorT *fields[8]; char *cfg, *p; int i,k,l; if (remoteMode!=2) { remoteMode=2; /* set to remote mode */ local=0; ERR_I(LoadFromLsc()); ERR_P(LscCmd(ser, "MODE:[remoteMode]")); } else { ERR_P(LscCmd(ser, "PID [loop],[prop],[integ],[deriv]")); } for (i=0; i<4+nScan; i++) { s=sensors[i]; if (i<4) { plug=plugs[i/2]; } else { plug=&plug0; } if (s->present < 0) { if (settingsFlag) return 0; if (i==4) { ERR_P(LscCmd(ser, "DOUT:2;XSCAN:2,,2")); } ERR_I(InstalCurve(s, plug->device)); } } if (nScan>0) { for (out1=nScan+1;out1<=4;out1++) { ERR_P(LscCmd(ser, "INSET A[out1],0")); } ERR_P(LscCmd(ser, "INSET A5,0;INSET A6,0;INSET A7,0;INSET A8,0")); ERR_P(LscCmd(ser, "INSET A9,0;INSET A10,0;INSET A11,0;INSET A12,0")); ERR_P(LscCmd(ser, "INSET A13,0;INSET A14,0;INSET A15,0;INSET A16,0")); } AssignTypes(); if (settingsFlag) return 0; s=cryo.sensor1; if (s!=NULL) { ERR_I(SetMaxPower()); } if (settingsFlag) return 0; str_copy(statusBuf, "alarms"); ERR_I(ConfigAlarms(0.0)); if (settingsFlag) return 0; str_copy(statusBuf, "display"); /* display */ k=1; DisplayFmt(cryo.sensor1, fields, &k); if (samp.sensor1 != cryo.sensor1) { DisplayFmt(samp.sensor1, fields, &k); } if (cryo.sensor2 != cryo.sensor1) { DisplayFmt(cryo.sensor2, fields, &k); } if (samp.sensor2 != samp.sensor1 && samp.sensor2 != cryo.sensor2) { DisplayFmt(samp.sensor2, fields, &k); } DisplayFmt(testSens, fields, &k); DisplayFmt(test2Sens, fields, &k); DisplayFmt(auxSens, fields, &k); if (nScan>0) { i=0; while (ich, fields[k]->dispfmt); l=strlen(buf); } str_append(buf, "DISPLAY:[maxfld]"); ERR_P(LscCmd(ser, buf)); } if (config[0] != '\0') { /* obsolete */ str_copy(buf, binDir); str_append(buf, config); cfg=str_read_file(buf); if (cfg != NULL) { logfileOut(LOG_MAIN, "load %s\n", config); p=cfg; while (p!=NULL) { p=str_split(buf, p, '\n'); ERR_P(LscCmd(ser, buf)); } FREE(cfg); } } if (lscfg[0] != '\0') { ERR_P(LscCmd(ser, lscfg)); } if (settingsFlag) return 0; str_copy(statusBuf, "reading temperatures"); if (cryo.sensor1!=NULL) { ERR_I(SetTemp(2)); } else { ERR_I(ReadTemp()); } logTime=(rdTim / logPeriod + 2) * logPeriod; /* wait before logging "dirty" temperatures */ return 0; OnError: return -1; } int ConfigByCode(int plugNr) { char buf[256], nam[16]; int c1, c2; char *p; FILE *fil; plug=plugs[plugNr]; str_copy(plug->device,""); plug->devcmd=0; ConcatDevice(); if (plug->code==0) { logfileOut(LOG_MAIN ,"reset inputs on plug%d\n", plugNr); plug->sensor1->present=0; plug->sensor2->present=0; } else { str_copy(buf, binDir); str_append(buf, LSC_CODES); ERR_SP(fil=fopen(buf, "r")); p=fgets(buf, sizeof(buf), fil); c1=0; c2=0; while (p!=NULL && plug->code != c1 && plug->code != c2) { if (*p != '#') { c1=0; c2=0; sscanf(buf, "%15s %d %d", nam, &c1, &c2); } p=fgets(buf, sizeof(buf), fil); } fclose(fil); if (plug->code != c1 && plug->code != c2) { logfileOut(LOG_MAIN+LOG_STAT ,"unknown code %d on plug%d\n", plug->code, plugNr); return 0; } else { logfileOut(LOG_MAIN+LOG_STAT ,"configure plug%d for %s (code %d)\n", plugNr, nam, plug->code); str_copy(buf, "'"); str_append(buf, nam); str_append(buf, "'"); ERR_I(PrepInput(buf)); } } settingsFlag=1; return 0; OnError: return -1; } int ConfigByName(int plugNr) { char buf[20]; plug=plugs[plugNr]; plug->devcmd=1; logfileOut(LOG_MAIN+LOG_STAT ,"configure plug%d for %s\n", plugNr, plug->device); plug->sensor1->present=0; plug->sensor2->present=0; if (0!=strcmp(plug->device, "none")) { sprintf(buf, "'%s'", plug->device); ERR_I(PrepInput(buf)); } else { plug->descr[0]='\0'; } settingsFlag=1; return 0; OnError: plug->device[0]='\0'; ConcatDevice(); return -1; } #define HISTSIZE 65 typedef struct { int init; float vals[HISTSIZE]; float fore; float weight; float err; } Hist; /* static Hist fore, mFore; */ float forecast(Hist *h, float value, int tim, int nmax) { int i, n, stp, ne; float d1, d2, d, vmean, vsig, val, val1, fact, fact1; float emean, esig, errLin, valLin; if (h->init == 0) { /* put a start value */ h->init = 1; for (i=0; ivals[i] = value; } h->err = value; return value; } for (i=HISTSIZE-1; i>0; i--) { h->vals[i] = h->vals[i-1]; } h->vals[0] = value; h->err = value; h->fore = 0; errLin = value; valLin = value; for (stp = 1; stp*4 < HISTSIZE; stp *= 2) { vmean = 0; vsig = 0; n = 0; val1 = 0; emean = 0; esig = 0; ne = 0; for (i = 0; i < stp*nmax && i + 2 * stp < HISTSIZE; i += stp) { d1 = h->vals[i+stp] - h->vals[i]; d2 = h->vals[i+2*stp] - h->vals[i+stp]; if (fabs(d2) > fabsf(d1) && d1 * d2 >= 0 && n >= 0) { /* exponential extrapolation */ fact = d1 / d2; val = h->vals[i] - d1 * fact / (1 - fact); if (n == 0) { fact1 = fact; val1 = val; } n++; d = val - vmean; vmean += d / n; vsig += d * (val - vmean); } else { n = -1; /* exponential interpolation not possible */ } /* linear extrapolation */ val = h->vals[i] - 2 * d1 * tim / stp; ne++; d = val - emean; emean += d / ne; esig += d * (val - emean); val = h->vals[i]; ne++; d = val - emean; emean += d / ne; esig += d * (val - emean); } if (n > 1) { vsig = sqrt(vsig / (n - 1)); if (vsig < h->err) { h->err = vsig; h->fore = val1; if (fact1 > 0.9) { h->weight = (1 - fact1) / stp; } else { h->weight = 1 - pow(fact1, 1.0/stp); } } } esig = sqrt(esig / (ne - 1)); if (esig < errLin) { errLin = esig; valLin = emean; } } h->init = 1; if (h->fore == 0) { h->fore = valLin; h->err = errLin; h->init = -1; h->weight = 1.0 / tim; } return h->fore; } #define MAXTIMES 16 typedef struct { int init; int ntimes; float period; float mn[MAXTIMES]; float mx[MAXTIMES]; float upper; float lower; } Stat; static Stat mStat, sStat; void statInit(Stat *s, float mn, float mx) { int i; assert(mx >= mn); for (i=1; i < MAXTIMES; i++) { s->mn[i] = mn; s->mx[i] = mx; } } void statCrop(Stat *s, float mn, float mx) { int i; float d; if (mn > s->upper) { d = mn - s->upper; for (i=1; i < MAXTIMES; i++) { s->mx[i] += d; } } if (mx < s->lower) { d = mx - s->lower; for (i=1; i < MAXTIMES; i++) { s->mn[i] += d; } } } void statBegin(Stat *s, float period, float value) { s->ntimes = 0; s->period = period; s->mn[0] = value; s->mx[0] = value; if (s->init == 0) { /* put a start value */ s->init = 1; statInit(s, value*0.9, value*1.1); } s->lower = 0; s->upper = 0; } int statTime(Stat *s, float tim1, float tim2) { float w1, w2, dif, mn, mx; int i; i = s->ntimes; assert(tim1 <= tim2); assert(i < MAXTIMES-1); mn = s->mn[s->ntimes]; mx = s->mx[s->ntimes]; s->ntimes++; i = s->ntimes; s->upper = s->mx[i]; s->lower = s->mn[i]; if (tim1 <= 0) { w1 = 1; } else { w1 = 1 - exp(-s->period / tim1); } if (tim2 <= 0) { w2 = 1; } else { w2 = 1 - exp(-s->period / tim2); } dif = mx - s->mx[i]; if (dif > 0) { s->mx[i] += w1 * dif; } else { s->mx[i] += w2 * dif; } dif = mn - s->mn[i]; if (dif < 0) { s->mn[i] += w1 * dif; } else { s->mn[i] += w2 * dif; } return i; } void statEnd(Stat *s) { int i; i = s->ntimes; if (s->upper < s->mx[i]) { s->upper = s->mx[i]; } if (s->lower > s->mn[i]) { s->lower = s->mn[i]; } } typedef struct { float slope; float last; float mx; int wasmax; time_t lastTim; } Slope; void maxSlope(Slope *s, float value) { float d; if (rdTim <= s->lastTim + per*0.0015) { return; } s->wasmax = 0; if (s->slope < 0) { s->last = value; s->lastTim = rdTim; s->slope = 0; } else { d = (value - s->last) / (rdTim - s->lastTim); s->slope = d; if (fabsf(d) > s->mx) { s->mx = fabsf(d); s->wasmax = 1; } } s->last = value; s->lastTim = rdTim; } static Slope slopeS, slopeU, slopeL; int PeriodicTask(void) { char buf[256], lbuf[16]; char *next, *alms; int i, k, cnt; float t, htr0, mstep, fdif, d, dif2, ml; static time_t finTime; static int lastIntTim; static float dif=0; static float oldSet=0; static float oldShift=0; /* static float shiftTarget=0; */ if (nScan==0) { ERR_P(LscCmd(ser, "DIOST?>cod1,out1;DOUT 3,29;BUSY?>busy")); } else { cod1=0; ERR_P(LscCmd(ser, "BUSY?>busy")); } if ((plug0.codDefined && plug1.codDefined) || nScan>0) { per=period; /* no timeout on above command and codes are defined: normal period */ if (per>logPeriod*1000) per=logPeriod*1000; } if (noResp) { /* there was no response on an earlier command, or we are initializing */ k=serialNo; /* check serial number */ ERR_P(LscCmd(ser, "*IDN?>buf1,buf2,buf3,buf4")); /* decode firmware version date */ i=0; sscanf(buf4, "%d", &i); i=i/100+(i%100+2000)*10000; if (i>20900000) i-=1000000; /* 90..99 --> 1990-1999 */ lscVersion=i; sscanf(buf3, "%d", &serialNo); if (0!=strcmp(buf1, "LSCI") || 0!=strcmp(buf2, "MODEL340")) return 0; if (k!=serialNo) { /* controller exchanged or we are initializing */ logfileOut(LOG_MAIN, "serialNo: %d (was %d)\n", serialNo, k); if (serialNo < 340000 || serialNo > 349999) { serialNo=k; } else if (k < 340000 || k > 349999) { k=serialNo; } } if (k!=serialNo) { /* controller exchanged or we are initializing */ logfileOut(LOG_MAIN, "controller connected\n"); set=0; /* reload curve cache: */ if (cache!=NULL) FREE(cache); sprintf(lbuf, "lsc.%d", serialNo); str_copy(buf, logDir); str_append(buf, lbuf); cache=str_read_file(buf); if (cache==NULL && 0==strcmp(ErrMessage, "file not found")) ERR_I(LoadCache()); /* get device names and last codes separated by '/' */ str_split(buf, cache, '\n'); /* read 1 line */ plug1.device[0]='\0'; plug0.code=0; plug1.code=0; next=str_split(buf1, buf, '/'); if (next!=NULL) { next=str_split(buf2, next, '/'); if (next!=NULL) { next=str_split(buf3, next, '/'); plug0.code=atoi(buf3); plug0.codChanged=1; if (next!=NULL) { next=str_split(buf3, next, '\n'); plug1.code=atoi(buf3); plug1.codChanged=1; } } } if (buf1[0]=='*') { str_copy(plug0.device, buf1+1); plug0.codChanged=0; ConfigByName(0); } else { if (plug0.code!=0) str_copy(plug0.device, buf1); plug0.devcmd=0; } if (buf2[0]=='*') { str_copy(plug1.device, buf2+1); plug1.codChanged=0; ConfigByName(1); } else { if (plug1.code!=0) str_copy(plug1.device, buf2); plug1.devcmd=0; } ConcatDevice(); settingsFlag=1; } noResp=0; } ERR_I(ReadHeater(1)); if (alarmListSize!=0) { buf[0]='\0'; for (k=0;k=logTime) { ERR_I(DataPutAll(NULL, rdTim)); logTime=(rdTim / logPeriod + 1) * logPeriod; if (rdTim>mmTime && (cryo.sensor1 != NULL || nScan>0)) LogMinMax(0); } if (set!=0 && remoteMode==2) { t=ctlSens->t; if (htr == 0.0 && mout < 0) { mstep=0.2; while (htr == 0 && mout < 0) { mstep *= 2; mout += mstep; ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); ERR_I(ReadHeater(0)); } cnt=10; while (htr >= 0.2 && cnt > 0) { mout -= htr - 0.1; htr0=htr; if (mout > 0) mout=0; ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); while (htr == htr0 && cnt > 0) { ERR_I(ReadHeater(0)); cnt--; } } logfileOut(LOG_MAIN, "adjusted mout=%.2f\n", mout); } if (htr == 100.0 && mout > 0) { mstep = 0.2; while (htr == 0 && mout > 0) { mstep *= 2; mout -= mstep; ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); ERR_I(ReadHeater(0)); } cnt=10; while (htr <= 99.8 && cnt > 0) { mout += 99.9 - htr; htr0=htr; if (mout < 0) mout=0; ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); while (htr == htr0 && cnt > 0) { ERR_I(ReadHeater(0)); cnt--; } } logfileOut(LOG_MAIN, "adjusted mout=%.2f\n", mout); } fdif=FakeScale(ctlSens, tr)-t; fbuf=htr-mout-prop/6*fdif; /* value of integrator (assume deriv=0) */ if ((fbuf > 99.8 && mout < 0 && fdif > 0) || (fbuf < 0.2 && mout > 0 && fdif < 0)) { /* probably integrator overflow */ if (lastIntTim > 0) { mout += fdif*prop*integ/3000*(rdTim-lastIntTim); /* use mout for integral */ if (mout < -100) mout=-100; if (mout > 100) mout=100; ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); } else { logfileOut(LOG_MAIN, "possible integrator overflow, mout=%.2f\n", mout); } lastIntTim=rdTim; } else { if (lastIntTim>0) { logfileOut(LOG_MAIN, "end integrator overflow mout=%.2f\n", mout); lastIntTim=0; } } ml = set/100; if (ml == 0) ml = 1; statBegin(&mStat, per*0.001, TrueScale(ctlSens, ctlSens->t)); statTime(&mStat, 10, 20); statTime(&mStat, int2/16, int2/2); statTime(&mStat, int2/1.5, int2+10); statEnd(&mStat); statBegin(&sStat, per*0.001, samp.temp); statTime(&sStat, 10, 20); statEnd(&sStat); maxSlope(&slopeS, samp.temp); maxSlope(&slopeU, mStat.upper); maxSlope(&slopeL, mStat.lower); /* statBegin(&sStat, maxShift*0.01, per*0.001, samp.temp); */ d = set - samp.temp; shiftLow = mStat.lower - sStat.upper; shiftUp = mStat.upper - sStat.lower; if (cryo.sensor1!=samp.sensor1 && doubleControl) { dif2 = d - dif; if (oldSet == 0) oldSet = samp.temp; if (oldSet != set || fabsf(d) > 50*ml) { if (oldSet != set) { float f = fabsf((oldSet - set)/ (oldSet + set)); oldShift *= exp(-f*f*25); tShift = oldShift; statCrop(&mStat, sStat.lower+tShift, sStat.upper+tShift); state = 1; } else { state = 0; } finTime = rdTim + int2 + 30; slopeS.mx = -1; slopeU.mx = -1; slopeL.mx = -1; } if (rdTim < finTime) { if (slopeS.wasmax) { finTime = rdTim + int2 + 30; } if (fabs(slopeS.slope) > slopeS.mx * 0.2 && finTime < rdTim + per * 0.0035) { finTime = rdTim + per * 0.0035; } if (d > 0) { tShift = oldShift + propUp * d; } else { tShift = oldShift + propDown * d; } } else { if (state != 2) { /* tShift = oldShift; */ state = 2; statCrop(&mStat, sStat.lower+tShift, sStat.upper+tShift); } else { if (shiftLow > tShift) { tShift = shiftLow; oldShift = tShift; } else if (shiftUp < tShift) { tShift = shiftUp; oldShift = tShift; } } } if (tShift > ml * maxShift) { tShift = ml * maxShift; } else if (tShift < -ml * maxShift) { tShift = - ml * maxShift; } dif = d; ERR_I(SetTemp(0)); } else { ERR_I(SetTemp(0)); } } else { oldShift = 0; } oldSet = set; if (nScan==0) { ERR_P(LscCmd(ser, "KEYST?>key;DIOST?>cod2,out2;DOUT 3,30")); } else { ERR_P(LscCmd(ser, "KEYST?>key")); } if (busy==0) { if (nScan==0) { if (out1!=30) { ERR_P(LscCmd(ser, "DOUT:3,30")); ERR_P(LscCmd(ser, "DIOST?>cod1,out1")); } if (out2!=29) { ERR_P(LscCmd(ser, "DOUT:3,29")); ERR_P(LscCmd(ser, "DIOST?>cod2,out2;DOUT 3,30")); } } if (out1==30 && out2==29) { /* code conversion */ plug0.code1=3*decod[cod2 % 8] ^ 2*decod[cod1 % 8]; /* ^ is exclusive OR */ if ((plug0.code1 & 0x2a) == 0x20) { /* for external switch (MA09) */ scanChan = cod1 & 0x03; plug0.code1 = plug0.code1 & 0x30; } else { scanChan = DATA_UNDEF; } plug1.code1=-(3*decod[cod2 / 8] ^ 2*decod[cod1 / 8]); for (i=0; i<2; i++) { plug=plugs[i]; if (plug->code1!=plug->code) { /* code has changed -> wait for a confirmation */ if (plug->code1!=plug->code2) { plug->code2=plug->code1; } else { plug->code=plug->code1; plug->codChanged=1; } } else { plug->code2=plug->code; if (plug->codChanged) { /* code change confirmed */ plug->codChanged=0; if (plug->code1==0) { logfileOut(LOG_MAIN, "plug%d unplugged\n", i); str_copy(plug->descr,"unplugged"); } else { logfileOut(LOG_MAIN, "plugged %d on plug%d\n", plug->code1, i); } set=0; ERR_I(ConfigByCode(i)); } plug->codDefined=1; } } } } if (key!=0) { ERR_P(LscCmd(ser, "MODE?>remoteMode")); local = (remoteMode == 1); if (!touched) { touched=1; logfileOut(LOG_MAIN ,"user touched keys\n"); } if (remoteMode==2) { logfileOut(LOG_MAIN ,"user switched to remote\n"); touched=0; ERR_I(LoadFromLsc()); if (doubleControl) { ERR_P(LscCmd(ser, "RANGE?>iRange")); if (iRange==0) set=0; } else { ERR_P(LscCmd(ser, "RAMP?[loop]>,ramp")); ERR_P(LscCmd(ser, "RANGE?>iRange;CSET?[loop]>,cod1,;SETP?[loop]>fbuf")); if (ctlSens!=NULL) { set=TrueScale(ctlSens,fbuf); } else { set=0; } if (cod1!=1) { set=0; logfileOut(LOG_MAIN, "set point was not in K, set to 0\n"); } } settingsFlag=1; jRange=iRange; } } if (saveTime!=0 && tim>saveTime) { ERR_P(LscCmd(ser, "CRVSAV;BUSY?>busy")); while (!busy) { IdleHdl(200, 0); /* wait 200 ms */ ERR_P(LscCmd(ser, "BUSY?>busy")); } saveTime=0; } return 0; OnError: return -1; } int DeviceHdl(int mode, void *base, int fd) { char *t; int do0, do1; if (mode==COC_WR) { set=0; t=strchr(device, '/'); if (t==NULL) { if (0==strcmp(device, "0") || 0==strcasecmp(device, "auto")) { nScan=0; ERR_I(ConfigByCode(0)); ERR_I(ConfigByCode(1)); } else { str_copy(plug0.device, device); str_copy(plug1.device, device); ERR_I(ConfigByName(0)); ERR_I(ConfigByName(1)); } } else { do0=0; do1=0; if (t!=device) { *t='\0'; str_copy(plug0.device, device); *t='/'; do0=1; } t++; if (*t!='\0') { str_copy(plug1.device, t); do1=1; } if (do0) ERR_I(ConfigByName(0)); if (do1) ERR_I(ConfigByName(1)); } ConcatDevice(); } return 0; OnError: return -1; } int PidHdl(int mode, void *base, int fd) { if (mode==COC_WR) { return COC_DWR; } else if (mode==COC_DWR) { ERR_P(LscCmd(ser,"PID [loop]:[prop],[integ],[deriv]")); PidSumHdl(COC_RD, base, fd); logfileOut(LOG_MAIN, "pid: %s\n", pid); } return 0; OnError: return -1; } int AlarmHdl(int mode, void *base, int fd) { if (mode==COC_WR) { return COC_DWR; } else if (mode==COC_DWR) { ERR_I(ConfigAlarms(0.0)); } return 0; OnError: return -1; } int TLimitHdl(int mode, void *base, int fd) { if (mode==COC_WR) { if (tLimit>tMaxLimit) tLimit=tMaxLimit; return COC_DWR; } else if (mode==COC_DWR) { ERR_I(ConfigAlarms(tLimit)); ERR_I(SetMaxPower()); } return 0; OnError: return -1; } int SwapHdl(int mode, void *base, int fd) { static char swp; static SensorT *s1, *s2; if (mode==COC_WR) { if (strlen(swap) != 2) ERR_MSG("must be 2 letters"); str_lowcase(swap, swap); s1 = findSensor(swap[0]); s2 = findSensor(swap[1]); if (s1 == NULL || s2 == NULL) { ERR_MSG("no such sensor(s)"); } if (s1 == s2) { return 0; } return COC_DWR; } else if (mode==COC_DWR) { swp = s1->typ; s2->typ = s1->typ; s1->typ = swp; AssignTypes(); } return 0; OnError: return -1; } int SetPower(float setpower) { float htr1, htr0; int cnt; logfileOut(LOG_MAIN,"SetPower\n"); if (setpower<0) return 0; if (setpower>maxPowerFlt) setpower=maxPowerFlt; if (setpower<0) setpower=0; mout=Power2Percent(setpower); if (mout>100) mout=100; if (!manual && set == 0 && setpower > 0) { ERR_P(LscCmd(ser, "RANGE:[iRange]")); manual=1; } ERR_P(LscCmd(ser, "CMODE [loop]:3;MOUT [loop],[mout]")); /* set to open loop */ if (manual) return 0; ERR_I(ReadHeater(0)); ERR_P(LscCmd(ser, "RANGE:0")); htr0=htr; ERR_P(LscCmd(ser, "CMODE [loop]:1")); /* pid control*/ ERR_P(LscCmd(ser, "RANGE:[iRange]")); ERR_I(ReadHeater(0)); cnt=20; htr1=htr; while (htr1==htr && cnt>0) { /* wait for heater change */ ERR_I(ReadHeater(0)); cnt--; } if (htr != htr0) { mout=0; cnt=10; while (cnt>0) { mout+=htr0-htr; if (mout > 100) mout=100; if (mout < -100) mout =-100; ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); ERR_I(ReadHeater(0)); cnt--; } } power=Percent2Power(htr); logfileOut(LOG_MAIN, "power: %5f (tried %5f), mout %.1f\n", power, setpower, mout); return 0; OnError: return -1; } int AlarmReset(void) { if (relay) { ERR_P(LscCmd(ser, "RELAY 1:2,1")); if (alarmHistory[0]=='\0') { str_copy(alarmHistory, "X"); } } else { alarmHistory[0]='\0'; alarmStatus[0]='\0'; ERR_P(LscCmd(ser, "ALMRST;RELAY 1:1")); logfileOut(LOG_MAIN, "reset alarms\n"); relay0=0; lockAlarm=0; } OnError: return -1; } int SetHdl(int mode, void *base, int fd) { if (mode==COC_WR) { if (remoteMode!=2) { ERR_MSG("controller is in local mode, enter 'remote' first"); } if (relay && set!=0) { if (alarmChannels[0]!='\0') { ERR_MSG("alarm is active, set prohibited"); } else { ERR_MSG("alarm was active, enter 'reset' first"); } } else if (set<=0) { set=0; } else if (set>tLimit) { set=0; ERR_MSG("set point too high"); } return COC_DWR; } else if (mode==COC_DWR) { if (manual) { manual=0; mout=0; ERR_P(LscCmd(ser, "CMODE [loop],1;MOUT [loop],0")); } if (cryo.sensor1!=NULL && remoteMode==2) { ERR_I(SetTemp(1)); } } return 0; OnError: return -1; } int ControlModeHdl(int mode, void *base, int fd) { if (mode==COC_WR) { if (controlMode == 1) { controlSensor[0]='1'; } else { controlSensor[0]='0'; } if (controlMode >= 2) { doubleControl = 1; controlMode = 2; } else { doubleControl = 0; if (controlMode < 0) { controlMode = 0; } } } return SetHdl(mode, base, fd); } int MaxPowerHdl(int mode, void *base, int fd) { static float setpower; if (mode==COC_WR) { if (loop!=1) return COC_DWR; setpower=power; sscanf(maxPower, "%f", &maxPowerFlt); CalcMaxPower(); if (remoteMode!=2) { ERR_MSG("controller is in local mode, enter 'remote' first"); } else if (relay) { if (alarmChannels[0]!='\0') { ERR_MSG("alarm is active, maxPower prohibited"); } else { ERR_MSG("alarm was active, enter 'reset' first"); } } return COC_DWR; } else if (mode==COC_DWR && remoteMode==2) { ERR_I(SetMaxPower()); if (maxCurrent>0 && loop==1) { ERR_I(SetPower(setpower)); } } return 0; OnError: return -1; } int PowerHdl(int mode, void *base, int fd) { static float setpower=0; float htr1, diff; if (mode==COC_WR) { if (power>maxPowerFlt) power=maxPowerFlt; htr1=Power2Percent(power); diff=htr1-htr; if (mout+diff>100) { diff=100-mout; htr+=diff; power=Percent2Power(htr); } else if (mout+diff<-100) { diff=-100-mout; htr+=diff; power=Percent2Power(htr); } if (power<0) power=0; setpower=power; return COC_DWR; } else if (mode==COC_DWR && maxCurrent>0) { ERR_I(SetPower(setpower)); } return 0; OnError: return -1; } int ManualHdl(int mode, void *base, int fd) { if (mode == COC_DWR && maxCurrent>0) { if (manual == 0 && ctlSens != NULL) { set=TrueScale(ctlSens, ctlSens->t); } } return PowerHdl(mode, base, fd); } int MoutHdl(int mode, void *base, int fd) { if (mode==COC_WR) { return COC_DWR; } else if (mode==COC_DWR) { ERR_P(LscCmd(ser, "MOUT [loop],[mout]")); } return 0; OnError: return -1; } int StillHdl(int mode, void *base, int fd) { if (mode==COC_WR) { return COC_DWR; } else if (mode==COC_DWR) { fbuf=sqrt(still*70); ERR_P(LscCmd(ser,"ANALOG 1:0,2,,,,,[fbuf]")); } return 0; OnError: return -1; } int SendHdl(int mode, void *base, int fd) { char *res; ClientData *data; if (mode==COC_WR) { return COC_DRD; } else if (mode==COC_DRD) { data=base; if (NULL!=strchr(data->cmd, '>') || NULL!=strchr(data->cmd, '[')) ERR_MSG("no variables allowed"); ERR_P(res=LscCmd(ser, data->cmd)); str_copy(data->cmd, res); } return 0; OnError: return -1; } int LogHdl(int mode, void *base, int fd) { ClientData *data; if (mode==COC_RD) { data=base; if (data->logstart != 0) { data->logpos = logfilePos(data->logstart); data->logstart = 0; } data->logpos=logfileGetLines(data->logpos, 25, data->logline, sizeof(data->logline)); } return 0; } int PltHdl(int mode, void *base, int fd) { if (mode==COC_RD) { ERR_MSG("Tecs client version not up to date"); } return 0; OnError: return -1; } int GraHdl(int mode, void *base, int fd) { int l; char names[64]; long startTime, endTime, step; if (mode==COC_RD) { ERR_SI(sscanf(grapar, "%ld %ld %ld %n", &startTime, &endTime, &step, &l)-2); str_copy(names, grapar+l); ERR_I(l=DataGetMult(names, startTime, endTime, step, 30, gradata, sizeof(gradata)/sizeof(float))); assert(l*sizeof(float)present!=1) return 0; ERR_I(StrPut(buf, "\n ", ' ')); ERR_I(StrPut(buf, s->ch, ':')); ERR_I(StrPut(buf, "", ' ')); if (s->readStat==0) { if (s->t==0) { ERR_I(StrPut(buf, "not yet read", StrNONE)); } else { ERR_I(StrPut(buf, name, '=')); ERR_I(PutFloat(buf, 5, TrueScale(s, s->t))); ERR_I(StrPut(buf, " ", StrNONE)); ERR_I(StrPut(buf, units, StrNONE)); } } else { ERR_I(StrPut(buf, LscReadStat(s->readStat), StrNONE)); } if (s==ctlSens && !manual) { ERR_I(StrPut(buf, ", setpoint", '=')); if (tr==DATA_UNDEF) { ERR_I(PutFloat(buf, 5, 0.0)); } else { ERR_I(PutFloat(buf, 5, tr)); } ERR_I(StrPut(buf, " ", StrNONE)); ERR_I(StrPut(buf, units, StrNONE)); } if (s->lim > 0 && lim!=0) { ERR_I(StrPut(buf, ", for T", lim)); ERR_I(PutFloat(buf, 5, s->lim)); } return 0; OnError: return -1; } int ErrorHdl(int mode, void *base, int fd) { error[0]='\0'; if (noResp==3) { snprintf(error, sizeof(error), "no connection or controller switched off"); } else if (statusBuf[0] != '\0') { snprintf(error, sizeof(error), "configuring: %s", statusBuf); } else if (device[0] == '\0') { snprintf(error, sizeof(error), "no device selected"); } return 0; } int StatusHdl(int mode, void *base, int fd) { int i; StrBuf buf; float tM, tS; char pendAct[256]; char *p; readTemp=1; StrLink(&buf, status); StrClear(&buf); ERR_I(StrPut(&buf, "\n", StrNONE)); ErrorHdl(mode, base, fd); if (error[0] != '\0') { ERR_I(StrPut(&buf, error, StrNONE)); goto EndStatus; } CocShowHandlers(pendAct, sizeof(pendAct)); if (pendAct[0]!='\0') { if (mode==COC_RD) { return COC_DRD; } else { ERR_I(StrPut(&buf, "pending action(s):", ' ')); ERR_I(StrPut(&buf, pendAct, StrNONE)); goto EndStatus; } } if (remoteMode==1) { ERR_I(StrPut(&buf, "LOCAL mode, enter 'remote' to enable remote control", '\n')); } ERR_I(StrPut(&buf, "device:", ' ')); p=strchr(device, '/'); if (p!=NULL) { *p='\0'; ERR_I(StrPut(&buf, device, ' ')); *p='/'; p++; } else { ERR_I(StrPut(&buf, device, ' ')); } ERR_I(StrPut(&buf, plug0.descr, StrNONE)); if (plug0.devcmd) { ERR_I(StrPut(&buf, " ", '*')); } if (p!=NULL) { ERR_I(StrPut(&buf, "\n ", ' ')); ERR_I(StrPut(&buf, p, ' ')); ERR_I(StrPut(&buf, plug1.descr, StrNONE)); if (plug1.devcmd) { ERR_I(StrPut(&buf, " ", '*')); } } if (set==0) { ERR_I(StrPut(&buf, "\nheater off,",' ')); } else { if (manual) { ERR_I(StrPut(&buf, "\nmanual power,", ' ')); } else { ERR_I(StrPut(&buf, "\ntarget", '=')); ERR_I(PutFloat(&buf, 5, set)); if (ramp==0 || tr==TrueScale(ctlSens, setH)) { ERR_I(StrPut(&buf, " K,", ' ')); } else { ERR_I(StrPut(&buf, " K ramping at", ' ')); ERR_I(PutFloat(&buf, 4, ramp)); ERR_I(StrPut(&buf, " K/min,", ' ')); } } } if (relay) { if (alarmChannels[0]!='\0') { ERR_I(StrPut(&buf, "alarm on channel",' ')); ERR_I(StrPut(&buf, alarmChannels, StrNONE)); } else if (alarmHistory[0]!='\0') { ERR_I(StrPut(&buf, "alarm was on channel", ' ')); ERR_I(StrPut(&buf, alarmHistory, ',')); ERR_I(StrPut(&buf, " (enter 'reset' to confirm)", StrNONE)); } else { ERR_I(StrPut(&buf, "alarm",' ')); } } else if (htrst!=0) { ERR_I(StrPut(&buf, LscHtrStat(htrst), StrNONE)); } else { if (power!=DATA_UNDEF) { ERR_I(StrPut(&buf, "htr power", '=')); if (power>=0.5) { ERR_I(PutFloat(&buf, 3, power)); ERR_I(StrPut(&buf, " W, htr current", '=')); } else { ERR_I(PutFloat(&buf, 3, power*1000)); ERR_I(StrPut(&buf, " mW, htr current", '=')); } ERR_I(PutFloat(&buf, 4, htr)); ERR_I(StrPut(&buf, "% ", '(')); ERR_I(PutFloat(&buf, 4, sqrt(power/resist))); ERR_I(StrPut(&buf, " A", ')')); } else { ERR_I(StrPut(&buf, "set=0", StrNONE)); } } tM=0; tS=0; if (cryo.sensor1!=NULL) { if (cryo.sensor1!=samp.sensor1) { ERR_I(StrPut(&buf, "\nheat exchanger", ':')); if (cryo.sensor2!=cryo.sensor1) { ERR_I(StrPut(&buf, " T", '=')); ERR_I(PutFloat(&buf, 4, cryo.temp)); ERR_I(StrPut(&buf, " ", 'K')); ERR_I(ShowSensor(&buf, cryo.sensor1, "T", "K", '>')); } ERR_I(ShowSensor(&buf, cryo.sensor2, "T", "K", '<')); ERR_I(StrPut(&buf, "\nsample:", ' ')); } if (samp.sensor2!=samp.sensor1) { ERR_I(StrPut(&buf, " T", '=')); ERR_I(PutFloat(&buf, 4, samp.temp)); ERR_I(StrPut(&buf, " ", 'K')); ERR_I(ShowSensor(&buf, samp.sensor1, "T", "K", '>')); } ERR_I(ShowSensor(&buf, samp.sensor2, "T", "K", '<')); } if (testSens!=NULL || test2Sens!=NULL || nScan>0) { ERR_I(StrPut(&buf, "\ntest", ':')); } if (testSens!=NULL) { ERR_I(ShowSensor(&buf, testSens, "T", "K", 0)); } if (test2Sens!=NULL) { ERR_I(ShowSensor(&buf, test2Sens, "T", "K", 0)); } for (i=4; i<4+nScan; i++) { ERR_I(ShowSensor(&buf, sensors[i], "T", "K", 0)); } if (auxSens!=NULL) { ERR_I(StrPut(&buf, "\nauxilliary", ':')); ERR_I(ShowSensor(&buf, auxSens, "U", "V", 0)); } if (heliumSens!=NULL) { ERR_I(StrPut(&buf, "\nhelium:", ' ')); ERR_I(StrPut(&buf, helium, StrNONE)); } if (still!=0) { ERR_I(StrPut(&buf, "\nstill:", ' ')); ERR_I(PutFloat(&buf, 1, still)); ERR_I(StrPut(&buf, " mW", ' ')); } EndStatus: ERR_I(StrPut(&buf, "", '\0')); return 0; OnError: return -1; } int DevHelpHdl(int mode, void *base, int fd) { char nbuf[256]; char *list; str_copy(nbuf, binDir); str_append(nbuf, DEV_LIST); ERR_P(list=str_read_file(nbuf)); str_copy(devHelp, list); FREE(list); return 0; OnError: return -1; } int UpdateHdl(int mode, void *base, int fd) { char cmd[128]; if (mode==COC_WR) { return COC_DRD; } else if (mode==COC_DRD) { str_copy(cmd, "tecsinstall "); str_lowcase(update, update); str_append(cmd, update); str_append(cmd, " "); if (NULL==strstr(" cfg server sync ", cmd+11)) { str_copy(update, "unknown"); } else { system(cmd); } } return 0; } int RemoteHdl(int mode, void *base, int fd) { if (mode==COC_WR) { return COC_DWR; } else if (mode==COC_DWR) { ERR_P(LscCmd(ser, "MODE:[remoteMode]")); } return 0; OnError: return -1; } int LocalHdl(int mode, void *base, int fd) { if (mode==COC_RD) { local = (remoteMode == 1); return 0; } else if (mode==COC_WR) { remoteMode = 1 + (local == 0); return RemoteHdl(mode, base, fd); } else if (mode==COC_DWR) { return RemoteHdl(mode, base, fd); } return 0; } int RelayHdl(int mode, void *base, int fd) { if (mode==COC_WR) { if (alarmChannels[0]!='\0') ERR_MSG("alarm is still active"); return COC_DWR; } else if (mode==COC_DWR) { ERR_I(AlarmReset()); set = 0; } return 0; OnError: return -1; } int TmoHdl(int mode, void *base, int fd) { if (mode==COC_WR) { ERR_I(SerSetTmo(ser, msecTmo)); } return 0; OnError: return -1; } int LogfileHdl(int mode, void *base, int fd) { char buf[256]; if (mode==COC_WR) { logfileClose(); str_copy(buf, logDir); str_append(buf, serverId); logfile=logfileInit(buf, logIt, use_stdout, logIt && use_stdout); CocDefStr(logfile, COC_RDONLY); } return 0; } int ExecuteRequest(void) { if (readTemp) ERR_I(ReadTemp()); ERR_I(CocCallHandlers()); while (settingsFlag==1) { settingsFlag=0; ERR_I(Settings()); } statusBuf[0]='\0'; return 0; OnError: return -1; } int MainBody(void) { int iret, tdif; logfileWrite(logMask); while (!quit) { tdif = per - mycMsecSince(tim0); if (tdif<0) { tim = mycNow(); break; } /* timeout */ ERR_I(iret=CocHandleRequests(tdif, 0)); tim=mycNow(); if (iret==0) { /* timeout */ break; } if (ser!=NULL) { ERR_I(ExecuteRequest()); } logfileWrite(logMask); } tdif = mycMsecSince(tim0); if (tdif>60000 && cntError < 2) { logfileOut(LOG_MAIN ,"%d seconds lost\n", tdif/1000); } tim0 = mycMsecSince(0)/period*period; if (ser!=NULL) { ERR_I(PeriodicTask()); ERR_I(ExecuteRequest()); } return 0; OnError: if (0==strcmp(ErrMessage, "timeout")) { if (noResp==2) { /* this is the second time we have no response */ per=1000; /* 1 sec */ cryo.temp=0; samp.temp=0; noResp=3; } else if (noResp < 2) { logfileShowErr("no response"); logfileOut(LOG_ALL ,"no response\n"); noResp=2; per=100; /* try again soon */ } return 0; } return -1; } int main(int argc, char *argv[]) { int i, iret; char *inistr; char buf[256], opt; signal(SIGPIPE, ignore_forever); #define RD COC_RDONLY #define RW COC_RDWR #define RA COC_RDWRALL CocDefStruct(cryo, Testpoint); CocDefStruct(samp, Testpoint); CocDefPtr(tpoint, Testpoint); CocFltFld(Testpoint, temp, RD); CocFltFld(Testpoint, t1, RD); CocFltFld(Testpoint, t2, RD); CocDefStruct(sensA, SensorT); CocDefStruct(sensB, SensorT); CocDefStruct(sensC, SensorT); CocDefStruct(sensD, SensorT); CocDefStruct(sensA1, SensorT); CocDefStruct(sensA2, SensorT); CocDefStruct(sensA3, SensorT); CocDefStruct(sensA4, SensorT); CocDefPtr(sens, SensorT); CocFltFld(SensorT, t, RD); CocFltFld(SensorT, t0, RD); CocFltFld(SensorT, t1, RD); CocFltFld(SensorT, t2, RD); CocFltFld(SensorT, lim, RW); CocFltFld(SensorT, scale, RD); CocFltFld(SensorT, kink, RD); CocFltFld(SensorT, alarm, RW); CocHdl(AlarmHdl); CocIntFld(SensorT, readStat, RD); CocIntFld(SensorT, stat1, RD); CocIntFld(SensorT, stat2, RD); CocStrFld(SensorT, ch, RD); CocStrFld(SensorT, curve, RD); CocStrFld(SensorT, type, RD); CocDefStr(maxPower, RW); CocHdl(MaxPowerHdl); CocDefFlt(maxPowerFlt, RD); CocDefFlt(slope, RW); CocHdl(MaxPowerHdl); CocDefFlt(prop, RW); CocHdl(PidHdl); CocDefFlt(integ, RW); CocHdl(PidHdl); CocDefFlt(deriv, RW); CocHdl(PidHdl); CocDefFlt(set, RW); CocHdl(SetHdl); CocDefFlt(ramp, RW); CocHdl(SetHdl); CocDefFlt(still, RW); CocHdl(StillHdl); CocDefFlt(power, RW); CocHdl(PowerHdl); CocDefFlt(mout, RW); CocHdl(MoutHdl); CocDefFlt(tLimit, RW); CocHdl(TLimitHdl); CocDefFlt(tMaxLimit, RD); CocDefFlt(maxCurrent, RD); CocDefFlt(smooth, RW); CocDefFlt(powFact, RW); CocDefFlt(resist, RD); CocDefFlt(htr, RD); CocDefFlt(setH, RD); CocDefFlt(full, RW); CocDefFlt(empty, RW); CocDefFlt(int2, RW); CocDefFlt(propUp, RW); CocDefFlt(propDown, RW); CocDefFlt(maxShift, RW); CocDefFlt(tm, RD); CocDefFlt(ts, RD); CocDefFlt(tr, RD); CocDefFlt(tx, RD); CocDefFlt(te, RD); CocDefFlt(tk, RD); CocDefFlt(aux, RD); CocDefFlt(he, RD); CocDefFlt(fbuf, RD); CocDefFlt(r1, RD); CocDefFlt(r2, RD); CocDefFlt(tShift, RW); CocDefFlt(linearPower, RW); CocDefFlt(scanChan, RW); CocDefFlt(shiftUp, RW); CocDefFlt(shiftLow, RW); CocDefFlt(state, RW); CocDefPtr(clData, ClientData); CocStrFld(ClientData, cmd, RW); CocHdl(SendHdl); CocIntFld(ClientData, logstart, RA); CocStrFld(ClientData, logline, RA); CocHdl(LogHdl); CocAlias(send, clData.cmd); CocAlias(logstart, clData.logstart); CocAlias(logline, clData.logline); CocDefStr(device, RW); CocHdl(DeviceHdl); CocDefStr(buf1, RD); CocDefStr(buf2, RD); CocDefStr(buf3, RD); CocDefStr(buf4, RD); CocDefStr(head, RD); CocDefStr(chan, RD); CocDefStr(helium, RD); CocDefStr(heUnits, RD); CocDefStr(intype, RD); CocDefStr(error, RD); CocHdl(ErrorHdl); CocDefStr(status, RD); CocHdl(StatusHdl); CocDefStr(pid, RD); CocHdl(PidSumHdl); CocDefStr(config, RD); CocDefStr(swap, RW); CocHdl(SwapHdl); CocDefStr(dev, RD); CocDefStr(devHelp, RD); CocHdl(DevHelpHdl); CocDefStr(update, RW); CocHdl(UpdateHdl); CocDefStr(lscfg, RD); CocDefStr(ttp, RD); CocDefStr(alarmChannels, RD); CocDefStr(alarmHistory, RD); CocDefInt(cod1, RD); CocDefInt(cod2, RD); CocDefInt(out1, RD); CocDefInt(out2, RD); CocDefInt(num, RD); CocDefInt(key, RD); CocDefInt(maxfld, RD); CocDefInt(iAmp, RD); CocDefInt(iRange, RD); CocDefInt(jRange, RD); CocDefInt(remoteMode, RW); CocHdl(RemoteHdl); CocDefInt(local, RW); CocHdl(LocalHdl); CocDefInt(relay, RW); CocHdl(RelayHdl); CocDefInt(manual, RW); CocHdl(ManualHdl); CocDefInt(htrst, RD); CocDefInt(loop, RW); CocDefInt(rdTim, RD); CocDefInt(tim0, RD); CocDefInt(ibuf, RD); CocDefInt(logMask, RW); CocDefInt(logPeriod, RW); CocDefInt(readTemp, RW); CocDefInt(controlMode, RW); CocHdl(ControlModeHdl); CocDefInt(busy, RD); CocDefInt(serialNo, RD); CocDefInt(quit, RW); CocDefInt(nScan, RD); CocDefInt(keepT, RW); CocDefInt(swRangeOn, RW); CocDefInt(doubleControl, RW); CocDefStr(controlSensor, RW); CocHdl(SetHdl); CocDefStr(grapar, RA); CocDefArr(gradata, RD); CocHdl(GraHdl); grasize=CocSizePtr(); CocAlias(tempX,cryo.temp); CocAlias(tempP,samp.temp); CocAlias(Ta,sensA.t); CocAlias(Tb,sensB.t); CocAlias(Tc,sensC.t); CocAlias(Td,sensD.t); CocAlias(T1,sensA1.t); CocAlias(T2,sensA2.t); CocAlias(T3,sensA3.t); CocAlias(T4,sensA4.t); CocAlias(P,power); CocAlias(tempC, set); CocAlias(int,integ); CocDefInt(msecTmo, RW); CocHdl(TmoHdl); CocDefStr(host, RW); CocDefInt(port, RD); CocDefInt(use_stdout, RW); CocHdl(LogfileHdl); CocDefStr(serverId, RW); CocHdl(LogfileHdl); CocDefInt(logIt, RW); CocHdl(LogfileHdl); CocDefStr(logDir, RW); CocHdl(LogfileHdl); CocDefStr(loggerDir, RW); CocDefStr(binDir, RW); logfileOut(LOG_MAIN ,"%s ", argv[0]); for (i=1;i0 && host[0]!='\0' && port!=0 && msecTmo>0); str_copy(statusBuf, "starting up"); logfileStatusBuf(statusBuf); if (logDir[0] == '/') { str_copy(buf, logDir); } else { getcwd(buf, sizeof buf); str_append(buf, "/"); ERR_I(str_append(buf, logDir)); } ERR_I(str_append(buf, "tecs")); logfile=logfileInit(buf, logIt, use_stdout, logIt && use_stdout); if (loggerDir[0] != '\0') { if (loggerDir[0] == '/') { str_copy(buf, loggerDir); } else { getcwd(buf, sizeof buf); str_append(buf, "/"); ERR_I(str_append(buf, loggerDir)); } str_copy(loggerDir, buf); LoggerSetDir(loggerDir); } CocDefStr(logfile, RD); logfileOut(LOG_MAIN ,"\n"); logfileWrite(logMask); ERR_I(CocInitServer(SetClientData, port)); ser=SerOpen(host, msecTmo, IdleHdl); if (ser==NULL) { str_copy(statusBuf, "can not connect to serial port server or terminal server"); logfileShowErr("error in SerOpen"); } ERR_I(iret=CocHandleRequests(100, 0)); tim0=mycMsecSince(0)/period*period; tim=mycNow(); ERR_P(DataCreateSet(NULL, "Tm", &tm, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "Ts", &ts, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "Tr", &tr, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "Te", &te, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "Tk", &tk, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "He", &he, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "T1", &sensA1.t, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "T2", &sensA2.t, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "T3", &sensA3.t, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "T4", &sensA4.t, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "Aux", &aux, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "P", &power, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "ScanChan", &scanChan, logPeriod, LOGLIFETIME, tim)); DataUndef(0); ERR_P(DataCreateSet(NULL, "Set", &set, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "shiftUp", &shiftUp, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "shiftLow", &shiftLow, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "state", &state, logPeriod, LOGLIFETIME, tim)); DataUndef(DATA_UNDEF); ERR_P(DataCreateSet(NULL, "tShift", &tShift, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "prop", &prop, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "int", &integ, logPeriod, LOGLIFETIME, tim)); ERR_P(DataCreateSet(NULL, "deriv", &deriv, logPeriod, LOGLIFETIME, tim)); remoteMode=2; local = 0; prop=50; integ=20; deriv=0; if (ser!=NULL) { LscCmd(ser, "MODE?>remoteMode"); LoadFromLsc(); } per=1; /* advance fast when initializing */ cntError=0; while (!quit) { iret=MainBody(); if (ser!=NULL && 0!=strcmp(host, ser->host)) { SerClose(ser); ser=NULL; noResp=1; } if (iret<0 || ser==NULL) { cntError++; ser=SerCheck(ser); if (0==strcmp(ErrMessage, "asynsrv error")) { if (ser!=NULL) SerClose(ser); ser=NULL; noResp=1; } if (cntError<4) { if (iret<0) { logfileShowErr("error in TecsServer/MainBody"); } else { logfileShowErr("error in SerOpen"); } } else if (cntError==4) { logfileOut(LOG_MAIN, "--- too many errors: skip messages ---\n"); } if (ser==NULL) { CocHandleRequests(msecTmo, 0); ser=SerOpen(host, msecTmo, IdleHdl); if (ser==NULL) { str_copy(statusBuf, "can not connect to serial port server or terminal server"); } else { LscCmd(ser, "MODE?>remoteMode"); LoadFromLsc(); } } } else { if (cntError>0) { if (cntError>4) { cntError=4; } cntError--; } } } LogMinMax(0); logfileWrite(logMask); if (quit==1) { ERR_MSG("restart by quit command"); } else { ERR_MSG("killed by quit command"); } OnError: printf("TecsServer exited: %s\n", ErrMessage); logfileShowErr("exit TecsServer"); if (ser!=NULL) SerClose(ser); CocCloseServer(); logfileClose(); return quit; }