#include #include #include #include #include #include #include #include #include "sys_util.h" #include "err_handling.h" #include "coc_server.h" #include "coc_logfile.h" #include "str_util.h" #include "tecs_lsc.h" #include "tecs_dlog.h" int ftime (struct timeb *__timeptr); /* for some reason not defined in timeb.h with flag -std1 */ #define TABLE_FILE "tecs.tab" #define Progress(I) if (configuring) { configuring+=I; } #define undef -65535. static SerChannel *ser=NULL; static char *serverId=NULL; static char *binDir=NULL; static char *logDir=NULL; typedef struct { float t, t1, t2, min, max, band; /* temperatures */ int stat1, stat2; /* reading status summary */ int present; /* sensor is present */ int readStat; /* reading status */ char ch[2]; /* channels */ } SensorT; SensorT sens1, sens2, sens3, sens4, *sensors[5]={NULL, &sens1, &sens2, &sens3, &sens4 }, *sensor=&sens1; typedef struct { SensorT *sensor1, *sensor2; float temp; /* weighted temperature */ float tMin, tMax; /* minimum and maximum temperatures since ... */ int dirty; /* input config to be reloaded */ int try; /* trial count */ int manual; /* manual device */ int code, code1, code2; /* device code, buffer for device code */ int codChanged; /* code has changed */ int codDefined; /* code is not yet confirmed */ float scale; /* scale for extreme ranges */ char device[16]; /* device name */ char tname[16]; } Testpoint; Testpoint /* C standard guarantees initialization to zero */ cryo={&sens1, &sens2 }, /* data for main sensors (on heat exchanger, or the only sensors) */ samp={&sens3, &sens4 }, /* data for extra sensors of sample stick */ *tpoints[2]={&cryo, &samp}, *tpoint=&cryo; static float tempC, /* set T (for sample) */ tempH, /* set T on heat exchanger */ htr, /* heater current percentage */ tLimit, maxPower, /* heater parameters */ tLow=0, tHigh=0, /* lower limit of high-T sensor, upper limit of low-T sensor */ tShift=0, /* setpoint shift */ aux, /* auxilliary value, i.e. helium level */ full, /* full value for helium level */ prop, integ, deriv, /* pid */ maxShift=2, /* maximal shift in when controlMode=2 */ fbuf, /* float buffer */ tInt=0; /* integral time (sec.) for setpoint shift */ static int logPeriod=0, /* data logging period (sec.) */ period=5000, /* default read interval (msec.) */ logTime, /* next logging time */ setFlag, /* temperature to be set */ maxPowerFlag, /* maxPower to be set */ pidFlag, /* pid's to be set */ saveTime, /* time for a CRVSAV command */ noResp=2, /* no response */ quit, /* quit server */ controlMode=2, /* 0: control on heater, 1: control on sample, 3: 2nd loop for difference heater-sample */ heliumMode, /* 0: no level meter, 1: constant current, 2: pulsed */ int2=30, /* inegration time for controlMode 2 */ remoteMode, /* 1: local, 2: remote */ maxfld, /* last used display field */ busy, /* busy after CRVSAV */ relay, relay0, /* relay status */ deviceFlag, /* device given via net */ num, /* curve number */ fld, /* field number */ key, /* key status */ serialNo, configuring=1, stable, /* stable since 2 min. */ resist, /* heater resistance */ cmode=1, /* 1: manual PID, 5: auto PI */ readTemp, /* client requested readTemp */ cod1, cod2, out1, out2, /* codes read from digital input/output */ iRange, iAmp, /* max. range and max. current code */ htrst, htrst0, /* heater status */ tuning=0, per; /* effective period */ static time_t tim, /* actual time */ mmInt, mmTime, /* interval and time for next min-max logging */ tableTime; /* last time when table was read */ static int decod[8]={21,20,17,16,5,4,1,0}; /* for code conversion */ static char status[160], /* status buffer */ 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[2], /* actual channel */ alarms[20], /* alarm status */ alarmList[4], /* alarm list */ chanS[4], chanM[4], /* channels in input routine */ helium[80], /* helium level status */ dlogfile[128], controlChannel[2]="A"; static char *table=NULL, /* environment devices table */ *cache=NULL, /* curve list cache */ *logfile=""; static char *heaterStatus[7]={ "heater o.k.\n", "heater supply over V\n", "heater supply under V\n", "heater output DAC error\n", "heater Ilimit DAC error\n", "open heater load\n", "heater load < 10 Ohm\n", }; struct timeb tim0; int logMask; void idleHdl(int tmo, int fd) { int iRet; iRet=CocHandleRequests(tmo, fd); if (iRet<0) logfileShowErr("CocHandleRequests"); } void concatDevice(void) { str_copy(device, cryo.device); if (0!=strcmp(cryo.device, samp.device) && (samp.device[0]!='\0' || samp.manual)) { str_append(device, "/"); str_append(device, samp.device); } if (cryo.manual) { str_append(device, " (manual"); } else { str_append(device, " (auto"); } if (samp.manual==cryo.manual) { str_append(device, ")"); } else if (samp.manual) { str_append(device, "/manual)"); } else { str_append(device, "/auto)"); } } int putPermanentData(FILE *fil) { char buf[256]; char *d1, *d2; if (cryo.manual) { d1="*"; } else { d1=""; } if (samp.manual) { d2="*"; } else { d2=""; } sprintf(buf, "%s%s/%s%s/%d/%d\n", d1, cryo.device, d2, samp.device, cryo.code, samp.code); ERR_SI(fputs(buf, fil)); return(0); OnError: return(-1); } int instCurve(char *nam, char *channel, int dispFld) { /* install sensor nam on channel */ char buf[256], chead[64], nbuf[256], lbuf[16]; char *crv, *entry, *points, *start, *s, /* start of found entry */ *e, /* cache part after found entry */ *res, *t; int i, n, c1, c2; char used[60]; FILE *fil; int retstat; fil=NULL; crv=NULL; e=NULL; str_copy(chan, channel); logfileOut(LOG_MAIN, "install curve %s\n", nam); /* read curve file */ str_copy(nbuf, binDir); str_append(nbuf, nam); retstat=-2; /* an error would be severe */ 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"); retstat=-1; /* an error could be fixed */ ERR_P(LscCmd(ser, "CRVHDR?[num]>head")); } 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"); retstat=-1; /* an error could be fixed */ ERR_P(LscCmd(ser, "CRVHDR?[num]>head")); e=strchr(entry, '\n'); if (e!=NULL) { *e='\0'; e++; } } } fld=dispFld; if (fld>maxfld) maxfld=fld; if (head[0]!='\0' && LscEqPar(head, chead)) { /* header matches: select sensor type and curve */ retstat=-1; /* an error could be fixed */ ERR_P(LscCmd(ser, "RANGE:0")); ERR_P(LscCmd(ser, "INTYPE [chan]:[intype]")); ERR_P(LscCmd(ser, "INCRV [chan]:[num]")); ERR_P(LscCmd(ser, "MNMX [chan]:1,1")); ERR_P(LscCmd(ser, "DISPFLD [fld],[chan],1")); ERR_P(LscCmd(ser, "DISPLAY [maxfld]")); logfileOut(LOG_MAIN, "curve %d on channel %s selected\n", num, chan); Progress(100); } else { /* header does not match -> download */ retstat=-2; /* an error would be severe */ if (num<=20) ERR_MSG("standard curve does not match"); retstat=-1; /* an error could be fixed */ if (busy) ERR_MSG("busy"); logfileOut(LOG_MAIN, "download curve %d\n", num); /* select sensor type first to display sensor units */ ERR_P(LscCmd(ser, "RANGE:0")); ERR_P(LscCmd(ser, "INTYPE [chan]:[intype]")); ERR_P(LscCmd(ser, "DISPLAY:[maxfld]")); Progress(1); n=3; do { 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"); 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)); ERR_P(LscCmd(ser, buf)); i++; if (i%10==0) sprintf(status, "downloading curve at line %d", i); Progress(1); } points=t; } while (t!=NULL); /* write header, select curve */ str_upcase(head, chead); ERR_P(LscCmd(ser, "CRVHDR [num]:[head]")); ERR_P(LscCmd(ser, "INCRV [chan]:[num]")); ERR_P(LscCmd(ser, "MNMX [chan]:1,1")); ERR_P(LscCmd(ser, "DISPFLD [fld],[chan],1")); ERR_P(LscCmd(ser, "DISPLAY [maxfld]")); Progress(1); logfileOut(LOG_MAIN, "curve selected on channel %s\n", chan); saveTime=tim+30; } FREE(crv); crv=NULL; if (num<=20) return(0); /* standard curve, do not touch cache */ /* rewrite cache with actual entry at beginning */ retstat=-2; /* errors in following section are severe */ sprintf(lbuf, "lsc.%d", serialNo); str_copy(nbuf, logDir); str_append(nbuf, lbuf); fil=fopen(nbuf, "r+"); 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 */ 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)); fil=NULL; FREE(cache); /* re-read it */ ERR_P(cache=str_read_file(nbuf)); return(0); OnError: if (crv!=NULL) FREE(crv); if (fil!=NULL) fclose(fil); return(retstat); } int configInput(void) { char *t, *e; char buf[80], nam[16], nbuf[256], ch[4]; int i, l, n, nn, dispFld; int retstat; char *ext; Str_Buf sbuf; retstat=-2; /* errors in following section are severe */ if (tpoint->manual) { sprintf(buf, "'%s'", tpoint->device); } else { sprintf(buf, "%+d,", tpoint->code); if (tpoint->code==0) return(0); } if (table!=NULL && tim>tableTime+60) { FREE(table); table=NULL; }; /* clear old table */ if (table==NULL) { /* read table */ str_copy(nbuf, binDir); str_append(nbuf, TABLE_FILE); ERR_P(table=str_read_file(nbuf)); tableTime=tim; } t=strstr(table, buf); 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 (tpoint==&samp) { sens3.present=0; sens4.present=0; ext=".s"; dispFld=2; } else { sens1.present=0; sens2.present=0; ext=".x"; dispFld=1; tLow=0; tHigh=0; controlMode=0; heliumMode=0; } chanS[0]='\0'; chanM[0]='\0'; 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; /* interprete settings until '+' appeares */ i=sscanf(t, "%64s%n", buf, &l); while (i>0 && buf[0]!='+') { t+=l; e=strchr(buf,'='); if (e==NULL) ERR_MSG("syntax error"); *e='\0'; str_link_buf(&sbuf, e+1, 0, ','); ERR_I(CocGetVar(serverVarList, &sbuf, buf, 0)); i=sscanf(t, "%64s%n", buf, &l); } if (tpoint==&samp) { str_copy(ch, chanS); } else { if (!samp.manual && (NULL!=strchr(chanS,'A') || NULL!=strchr(chanS,'B'))) { samp.dirty=1; /* sample and heat exchanger are on main plug */ samp.manual=1; str_copy(samp.device, nam); } str_copy(ch, chanM); if (heliumMode==0) { sprintf(helium, "no He-level meter for %s", nam); } else { sprintf(helium, "He-level meter not yet read", nam); } } n=strlen(ch); if (n==0) return(0); if (n>2) ERR_MSG("no more than 2 channels per plug allowed"); if (!tpoint->manual) { /* set device name */ str_copy(tpoint->device, nam); concatDevice(); } str_append(nam, ext); if (ch[0]<'A' || ch[0]>'D') ERR_MSG("illegal channel"); tpoint->sensor1->ch[0]=ch[0]; tpoint->sensor1->ch[1]='\0'; ERR_I(retstat=instCurve(nam, tpoint->sensor1->ch, dispFld)); tpoint->sensor1->present=1; tpoint->sensor1->band=10; if (n==2) { if (ch[1]>='a' && ch[1]<='d') { tpoint->sensor2->ch[0]=ch[1]; tpoint->sensor2->ch[1]='\0'; str_copy(chan, ch+1); logfileOut(LOG_MAIN, "auxilliary input on channel %s\n", chan); if (ch[0]>'b') { ERR_P(LscCmd(ser, "INTYPE [chan]:0,1,2,1,13")); } else { ERR_P(LscCmd(ser, "INTYPE [chan]:0,1,2,1,12")); } ERR_P(LscCmd(ser, "MNMX [chan]:1,3")); tpoint->sensor2->present=2; } else { if (ch[1]<'A' || ch[1]>'D') ERR_MSG("illegal channel"); tpoint->sensor2->ch[0]=ch[1]; tpoint->sensor2->ch[1]='\0'; str_append(nam, "l"); ERR_I(retstat=instCurve(nam, tpoint->sensor2->ch, dispFld+2)); tpoint->sensor2->present=1; } tpoint->sensor2->band=10; } return(0); OnError: return(retstat); } 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); Progress(1); 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 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 WeightedAverage(float tH, float tL) { float p,q; if (tH!=0.0) { if (tL!=0.0) { if (tLsensor1; s2=tpoint->sensor2; tpoint->tMin = WeightedAverage(s1->min, s2->min) * tpoint->scale; tpoint->tMax = WeightedAverage(s1->max, s2->max) * tpoint->scale; s1->min=0; s1->max=0; s2->min=0; s2->max=0; } if (cryo.tMax>0.0) { sprintf(buf, "@%.3f < T < %.3f K", cryo.tMin, cryo.tMax); if (samp.tMax>0.0) { sprintf(buf1, " (reg), %.3f < T < %.3f K (samp)", samp.tMin, samp.tMax); str_append(buf, buf1); } logfileOut(LOG_MAIN, "%s\n", buf); } if (new) { mmInt=60; } else if (mmInt<600) { mmInt=mmInt+60; } mmTime=tim+mmInt; } int ReadTemp(void) { char buf[256], bufs[256]; int i, l, ls, stat; struct tm *tb; readTemp=0; l=0; ls=0; for (i=1; i<=4; i++) { sensor=sensors[i]; sensor->stat1=0; sensor->stat2=0; if (sensor->present) { assert(l<128); sprintf(buf+l, "MDAT?[sens%d.ch]>sens%d.t1,sens%d.t2;", i, i, i); l=strlen(buf); assert(ls<128); sprintf(bufs+ls, "MDATST?[sens%d.ch]>sens%d.stat1,sens%d.stat2;", i, i, i); ls=strlen(bufs); } } if (ls>0) { buf[l-1]='\0'; /* strip off ';' */ ERR_P(LscCmd(ser, buf)); str_append(bufs, "MNMXRST"); ERR_P(LscCmd(ser, bufs)); } /* check for reading errors */ for (i=1; i<=4; i++) { sensor=sensors[i]; if (sensor->present) { stat=(sensor->stat1 | sensor->stat2) & (255-2); /* ignore old reading */ if (stat != sensor->readStat) { sensor->readStat=stat; if (stat & 1) logfileOut(LOG_MAIN, "invalid reading %s\n", sensor->ch); /* if (stat & 2) logfileOut(LOG_MAIN, "old reading %s\n", sensor->ch); */ if (stat & 12) logfileOut(LOG_MAIN, "unknown reading status %s\n", sensor->ch); if (stat & 16) logfileOut(LOG_MAIN, "temp underrange %s\n", sensor->ch); if (stat & 32) logfileOut(LOG_MAIN, "temp overrange %s\n", sensor->ch); if (stat & 64) logfileOut(LOG_MAIN, "units zero %s\n", sensor->ch); if (stat &128) logfileOut(LOG_MAIN, "units overrange %s\n", sensor->ch); if (stat==0) logfileOut(LOG_MAIN, "reading o.k. %s\n", sensor->ch); } if (stat==0) { if (sensor->present==2 && heliumMode==2) { sensor->t = sensor->t1; /* take minimum only */ } else if (sensor->t2 - sensor->t1 <= sensor->band*2) { /* normal case */ sensor->t = (sensor->t1 + sensor->t2) * 0.5; /* mean of min and max */ sensor->band = sensor->band/2; } else { /* probably noisy values */ /* logfileOut(LOG_MAIN, "min/max %s: %f %f\n", sensor->ch, sensor->t1, sensor->t2); */ if (fabs(sensor->t1 - sensor->t) < fabs(sensor->t2 - sensor->t) ) { sensor->t=sensor->t1; sensor->t2 = sensor->t1; } else { sensor->t=sensor->t2; sensor->t1 = sensor->t1; } sensor->t1 = sensor->t; sensor->t2 = sensor->t; } if (sensor->present==2) { aux=sensor->t; sensor->t=0; if (full>0 && heliumMode>0) { tb=localtime(&tim); if (aux0) { sprintf(helium, "%5.1f %% (%02d.%02d., %02d:%02d)", 100.0*aux/full , tb->tm_mday, tb->tm_mon+1, tb->tm_hour, tb->tm_min); } } } if (sensor->t1 < sensor->min || sensor->min==0.0) sensor->min = sensor->t1; if (sensor->t2 > sensor->max) sensor->max = sensor->t2; if (sensor->max - sensor->min > sensor->band) { sensor->band = sensor->max - sensor->min; } } else { sensor->t=0; } } else { sensor->t=0; } } cryo.temp=WeightedAverage(sens1.t, sens2.t)*cryo.scale; samp.temp=WeightedAverage(sens3.t, sens4.t)*samp.scale; if (samp.temp==0.0) samp.temp=cryo.temp; if (!deviceFlag && !samp.dirty && samp.codDefined && !samp.codChanged && !cryo.dirty && cryo.codDefined && !cryo.codChanged) { configuring=0; } else if (configuring==0 && remoteMode==2) { str_copy(status, "configuring"); configuring=1; } return(0); OnError: return(-1); } int SetTemp(int switchOn) { char *ch; float scale; if (tempC>tLimit) { tempC=tLimit; logfileOut(LOG_MAIN, "set point too high, reset to %f\n", tempC); } if (switchOn) { ERR_I(ReadTemp()); LogMinMax(1); } scale=cryo.scale; ch=sens1.ch; if (sens2.present==1 && tempC<(tLow+tHigh)/2) ch=sens2.ch; if (sens3.present) { if (controlMode==1) { /* control directly on sample sensor */ tShift=0; if (sens3.t!=0) ch=sens3.ch; if (sens4.present==1 && tempC<(tLow+tHigh)/2 && sens4.t!=0) ch=sens4.ch; scale=samp.scale; } else if (controlMode!=2) { tShift=0; } } else { tShift=0; } str_copy(chan, ch); if (scale!=1.0) { /* show set point on display (for rdrn) */ ERR_P(LscCmd(ser, "LINEAR C,1,0,1,1,[tempC]")); } if (tShift>maxShift) { tShift=maxShift; } else if (tShift<-maxShift) { tShift=-maxShift; } tempH=(tempC+tShift)/scale; if (tempH>tLimit) tempH=tLimit; if (tempC==0) { ERR_P(LscCmd(ser, "CSET 1:[chan],1,1,0")); ERR_P(LscCmd(ser, "RANGE:0")); tempH=0; } else if (remoteMode==1) { /* in local mode: do not switch on heater */ ch=controlChannel; } else if (switchOn) { /* switch on also when bad heater message and no alarms: || (htrst>=5 && relay==0)) */ ERR_P(LscCmd(ser, "CSET 1:[chan],1,1,0")); ERR_P(LscCmd(ser, "RANGE:[iRange]")); ERR_P(LscCmd(ser, "CMODE 1:[cmode]")); if (cmode>=4) { ERR_P(LscCmd(ser, "PID?1>prop,integ,deriv")); logfileOut(LOG_MAIN, "PID %f,%f,%f\n", prop, integ, deriv); tuning=2; } } else { ERR_P(LscCmd(ser, "CSET 1:[chan],1")); } ERR_P(LscCmd(ser, "SETP?1>fbuf")); if (tempH==0 || fbuf/tempH<0.9999 || fbuf/tempH>1.0001) { ERR_P(LscCmd(ser, "SETP 1:[tempH]")); if (controlMode!=2 && !switchOn) { logfileOut(LOG_MAIN, "set %f (on %s) (was changed)\n", tempC, ch); } } if (0!=strcmp(ch, controlChannel) || switchOn) { str_copy(controlChannel, ch); logfileOut(LOG_MAIN, "set %f (on %s)\n", tempC, ch); } return(0); OnError: return(-1); } int PeriodicTask(void) { char buf[256], lbuf[16]; char *next, *alms; int i, k; time_t putTim; float t3[3], p, d, w, t; ERR_P(LscCmd(ser, "DIOST?>cod1,out1")); if (cryo.codDefined && samp.codDefined) { per=period; /* no timeout on above command and codes are defined: normal period */ if (per>logPeriod*1000) per=logPeriod*1000; } ERR_P(LscCmd(ser, "DOUT 3,29")); ERR_P(LscCmd(ser, "HTR?>htr")); ERR_P(LscCmd(ser, "HTRST?>htrst")); ERR_P(LscCmd(ser, "RELAYST?1>relay;BUSY?>busy")); if (noResp) { /* there was no response on an earlier command, or we are initializing */ if (!configuring) remoteMode=2; LscCmd(ser, "MODE:[remoteMode]"); k=serialNo; /* check serial number */ ERR_P(LscCmd(ser, "*IDN?>buf1,buf2,serialNo,")); if (0!=strcmp(buf1, "LSCI") || 0!=strcmp(buf2, "MODEL340") || serialNo==0) return(0); if (k!=serialNo) { /* controller exchanged or we are initializing */ if (!configuring) { logfileOut(LOG_MAIN, "controller connected\n"); } if (remoteMode==2) configuring++; tempC=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 */ samp.device[0]='\0'; cryo.code=0; samp.code=0; next=str_split(buf1, buf, '/'); if (next!=NULL) { next=str_split(buf2, next, '/'); if (next!=NULL) { next=str_split(buf3, next, '/'); cryo.code=atoi(buf3); cryo.codChanged=0; if (next!=NULL) { next=str_split(buf3, next, '\n'); samp.code=atoi(buf3); samp.codChanged=0; } } } if (buf1[0]=='*') { str_copy(cryo.device, buf1+1); cryo.manual=1; } else { if (cryo.code!=0) str_copy(cryo.device, buf1); cryo.manual=0; } if (buf2[0]=='*' && buf2[1]!='\0') { str_copy(samp.device, buf2+1); samp.manual=1; } else { if (samp.code!=0) str_copy(samp.device, buf2); samp.manual=0; } concatDevice(); if (cryo.manual || cryo.code!=0) { cryo.dirty=1; } if (samp.manual || samp.code!=0) { samp.dirty=1; } } noResp=0; } if (relay) { if (alarmList[0]!='\0') { str_copy(buf, "ALARMST?*"); buf[8]=alarmList[0]; if (alarmList[1]!='\0') { str_append(buf,";ALARMST?*"); buf[18]=alarmList[1]; } str_append(buf, ";ALMRST"); ERR_P(alms=LscCmd(ser, buf)); if (0!=strcmp(alarms, alms)) { str_copy(buf, " "); if (alms[ 0]!='0' || alms[ 2]!='0') buf[0]=alarmList[0]; if (alms[ 4]!='0' || alms[ 6]!='0') buf[1]=alarmList[1]; if (0==strcmp(buf," ")) { logfileOut(LOG_MAIN, "No more alarms, but relay is on!\n"); } else { logfileOut(LOG_MAIN, "Alarm on channel %s\n", buf); } str_copy(alarms, alms); } } else { if (!relay0) logfileOut(LOG_MAIN, "Relay is on!\n"); alarms[0]='\0'; } } else { if (relay0) logfileOut(LOG_MAIN, "No more alarms, relay is off\n"); alarms[0]='\0'; } relay0=relay; ERR_I(ReadTemp()); if (htrst!=htrst0) { LogMinMax(0); if (htrst<0 || htrst>6) { sprintf(buf, "heater status %d\n", htrst); logfileOut(LOG_MAIN, buf); } else { logfileOut(LOG_MAIN, heaterStatus[htrst]); } htrst0=htrst; } if (tim>=logTime) { i=0; if (sens1.present) { t3[0]=cryo.temp; /* if (cryo.temp==0) { logfileOut(LOG_MAIN, "zero??\n"); } */ i=1; } else { t3[0]=undef; } if (sens3.present) { t3[1]=samp.temp; i=2; } else { if (sens2.present==1) { t3[1]=sens2.t; i=2; } else { t3[1]=undef; } } if (tempC!=0 || htr!=0) { t3[2]=htr*htr*maxPower*1e-4; i=3; } else { t3[2]=undef; } time(&putTim); if (i>0) ERR_I(dlog_put_(&putTim, &i, t3)); logTime=(putTim/logPeriod+1)*logPeriod; if (tim>mmTime) LogMinMax(0); } if (tempC!=0) { if (sens1.present && sens3.present && controlMode==2) { t=sens1.t; if (sens2.present==1 && tempC<(tLow+tHigh)/2) t=sens2.t; d=(tempH-t)/t-1.0; /* relative difference */ w=exp(-d*d*230); /* gaussian */ if (w<0.1) tInt=0; /* reset when far from setpoint (more than 10 %) */ if (int2<1) int2=1; if (tIntw) { p=w/tInt; } else { p=1.0; } tShift=tShift*(1.0-p)+p*(cryo.temp-samp.temp); ERR_I(SetTemp(0)); } else if (remoteMode==2 && sens1.present) { ERR_I(SetTemp(0)); } } ERR_P(LscCmd(ser, "KEYST?>key")); ERR_P(LscCmd(ser, "DIOST?>cod2,out2")); ERR_P(LscCmd(ser, "DOUT 3,30")); if (busy==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")); ERR_P(LscCmd(ser, "DOUT 3,30")); } if (out1==30 && out2==29) { /* code conversion */ cryo.code1=3*decod[cod2 % 8] ^ 2*decod[cod1 % 8]; /* ^ is exclusive OR */ samp.code1=-(3*decod[cod2 / 8] ^ 2*decod[cod1 / 8]); for (i=0; i<2; i++) { tpoint=tpoints[i]; if (tpoint->code1!=tpoint->code) { /* code has changed -> wait for a confirmation */ logfileOut(LOG_MAIN, "%s codes: %d,%d,%d\n", tpoint->tname, tpoint->code, tpoint->code1, tpoint->code2); if (tpoint->code1==tpoint->code2) { tpoint->code=tpoint->code1; tpoint->codChanged=1; } else { tpoint->code2=tpoint->code1; } } else { tpoint->code2=tpoint->code; if (tpoint->codChanged) { /* code change confirmed */ tpoint->codChanged=0; Progress(1); tpoint->manual=0; if (tpoint->code1==0) { logfileOut(LOG_MAIN, "%s unplugged\n", tpoint->tname); if (tpoint==&cryo && samp.sensor1->ch[0]<='B') { samp.manual=0; samp.dirty=1; } } else { logfileOut(LOG_MAIN, "plugged %d on %s\n", tpoint->code1, tpoint->tname); } tempC=0; remoteMode=2; /* set to remote mode */ LscCmd(ser, "MODE:[remoteMode]"); tpoint->dirty=1; if (!configuring) configuring=1; } tpoint->codDefined=1; } } } } if (key!=0) { if (!(cryo.dirty || samp.dirty)) { logfileOut(LOG_MAIN ,"user touched keys\n"); } if (cryo.manual || cryo.code!=0) cryo.dirty=1; if (samp.manual || samp.code!=0) samp.dirty=1; remoteMode=1; ERR_P(LscCmd(ser, "MODE?>remoteMode")); if (remoteMode==2) { /* user switched to remote mode */ ERR_P(LscCmd(ser, "PID?1>prop,integ,deriv")); if (controlMode==2) { ERR_P(LscCmd(ser, "RANGE?>iRange")); if (iRange==0) tempC=0; } else { ERR_P(LscCmd(ser, "RANGE?>iRange")); ERR_P(LscCmd(ser, "CSET?1>,cod1,")); ERR_P(LscCmd(ser, "SETP?1>tempC")); if (cod1!=1) { tempC=0; logfileOut(LOG_MAIN, "set point was not in K, set to 0\n"); } } setFlag=(iRange>0); } } if (tuning==2) { ERR_P(LscCmd(ser, "TUNEST?>tuning")); if (tuning==0) tuning=2; } else if (tuning==1) { ERR_P(LscCmd(ser, "TUNEST?>tuning")); if (tuning==0) { ERR_P(LscCmd(ser, "PID?1>prop,integ,deriv")); logfileOut(LOG_MAIN, "@tuned PID %f,%f,%f\n", prop, integ, deriv); } } 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 inputSettings(Testpoint *this) { tpoint=this; if (tpoint->dirty && samp.codDefined) { if (busy==0 || cryo.dirty>=0 && tpoint->dirty>=0) { /* do not enter when busy and cryo.dirty/P indicates error on last time */ if (tpoint->manual) { logfileOut(LOG_MAIN ,"configure %s inputs for %s\n", tpoint->tname, tpoint->device); } else { if (tpoint->code==0) { logfileOut(LOG_MAIN ,"reset %s inputs\n", tpoint->tname); if (cryo.code==0 && samp.code==0 && cryo.manual==0 && samp.manual==0) { logfileOut(LOG_MAIN, "no more sensor connected\n"); } } else { logfileOut(LOG_MAIN ,"configure %s inputs for code %+d\n", tpoint->tname, tpoint->code); } } if (tpoint->dirty>0) tpoint->try=0; tpoint->sensor1->present=0; tpoint->sensor2->present=0; if (!tpoint->manual) { tpoint->device[0]='\0'; concatDevice(); } tpoint->dirty=configInput(); if (tpoint->dirty<0) { tpoint->try++; if (tpoint->dirty!=-1 || tpoint->try>3) { logfileShowErr("fatal error"); tpoint->dirty=0; tpoint->device[0]='\0'; concatDevice(); } else { logfileShowErr("try again"); } } } } return(0); OnError: return(-1); } int SetMaxPower(void) { int i, j; float pa, pr, pw, dif; iAmp=1; iRange=0; if (maxPower>0) { pa=resist*4; /* max. maxPower */ pw=0; dif=1.0e6; for (i=4; i>0; i--) { pr=pa; for (j=5; j>0; j--) { if (pr>maxPower) { if (pr/maxPowerpresent) { flds[k]=s->ch[0]; if (s->present==1) { fmt[k]='1'; } else { fmt[k]='3'; } /* special value */ if (k>maxfld) maxfld=k; } else { flds[k]='\0'; } k=k+2; if (k>4) k=2; } for (i=1; i<=4; i++) { /* fill in raw fields */ s=sensors[i]; if (s->present) { k=strlen(flds); /* find next free field */ if (k<=4) { if (k>maxfld) maxfld=k; flds[k]=s->ch[0]; fmt[k]='3'; } } } /* fields 5-8 standard raw data */ ERR_P(LscCmd(ser, "DISPFLD 5,A,3;DISPFLD 6,C,3;DISPFLD 7,B,3;DISPFLD 8,D,3")); if (maxfld==0) { /* show raw data */ ERR_P(LscCmd(ser, "DISPFLD 1,A,3;DISPFLD 2,C,3;DISPFLD 3,B,3;DISPFLD 4,D,3;DISPLAY:4")); } else { l=0; for (k=1; k<=maxfld; k++) { if (flds[k]!='\0') { assert(l<128); sprintf(buf+l, "DISPFLD %d,%c,%c;", k, flds[k], fmt[k]); l=strlen(buf); } } str_append(buf, "DISPLAY:[maxfld]"); ERR_P(LscCmd(ser, buf)); } return(0); OnError: return(-1); } int Settings(void) { char nbuf[256], buf[256], *cfg, *p; cfg=NULL; if (cryo.dirty && cryo.codDefined || samp.dirty && samp.codDefined) { ERR_I(inputSettings(&cryo)); ERR_I(inputSettings(&samp)); ERR_P(LscCmd(ser, "ALARM A:0;ALARM B:0;ALARM C:0;ALARM D:0")); alarmList[0]='\0'; alarmList[1]='\0'; alarmList[2]='\0'; if (sens1.present) { ERR_I(SetMaxPower()); str_copy(buf, "ALARM [sens1.ch]:1,1,[tLimit],0,1,1;RELAY 1:1;BEEP:0"); alarmList[0]=sens1.ch[0]; if (sens3.present) { str_append(buf, ";ALARM [sens3.ch]:1,1,[tLimit],0,1,1"); alarmList[1]=sens3.ch[0]; } ERR_P(LscCmd(ser, buf)); } /* switch of unused channels */ buf[0]='\0'; if (NULL==strchr(alarmList, 'A')) str_append(buf, ";ALARM A:0"); if (NULL==strchr(alarmList, 'B')) str_append(buf, ";ALARM B:0"); if (NULL==strchr(alarmList, 'C')) str_append(buf, ";ALARM C:0"); if (NULL==strchr(alarmList, 'D')) str_append(buf, ";ALARM D:0"); if (buf[0]!='\0') ERR_P(LscCmd(ser, buf+1)); /* send without leading semicolon */ ERR_I(Display()); str_copy(nbuf, binDir); str_append(nbuf, cryo.device); str_append(nbuf, ".cfg"); cfg=str_read_file(nbuf); if (cfg!=NULL) { logfileOut(LOG_MAIN, "%s opened\n", nbuf); p=str_split(buf, cfg, '\n'); sscanf(buf, "%f%f", &cryo.scale, &samp.scale); while (p!=NULL) { p=str_split(buf, p, '\n'); ERR_P(LscCmd(ser, buf)); } FREE(cfg); } else { cryo.scale=1; samp.scale=1; } ERR_I(ReadTemp()); } return(0); OnError: if (cfg!=NULL) FREE(cfg); return(-1); } int ExecuteRequest(void) { char *t, *res; struct CocClient *client; float p; if (readTemp) ERR_I(ReadTemp()); if (remoteMode==2) ERR_I(Settings()); if (maxPowerFlag) { maxPowerFlag=0; ERR_I(SetMaxPower()); } if (pidFlag) { pidFlag=0; ERR_P(LscCmd(ser,"PID 1:[prop],[integ],[deriv]")); } if (setFlag) { setFlag=0; if (sens1.present) { tInt=0; /* reset integral time */ ERR_I(SetTemp(1)); } } client=CocGetNextCmd(); if (client!=NULL) { if (NULL!=strchr(client->cmd, '>') || NULL!=strchr(client->cmd, '[')) ERR_MSG("no variables allowed"); res=LscCmd(ser, client->cmd); if (res==NULL && ErrMessage!=NULL) { str_copy(client->res, ErrMessage); } else { str_copy(client->res, res); } client->cmd[0]='\0'; } if (deviceFlag) { tempC=0; remoteMode=2; /* set to remote mode */ ERR_P(LscCmd(ser, "MODE:[remoteMode]")); if (!configuring) { str_copy(status, "configuring"); configuring=1; } t=strchr(device, '/'); if (t==NULL) { if (0==strcmp(device, "0") || 0==strcasecmp(device, "auto")) { cryo.manual=0; cryo.dirty=1; cryo.device[0]='\0'; samp.manual=0; samp.dirty=1; samp.device[0]='\0'; } else { str_copy(cryo.device, device); str_copy(samp.device, device); cryo.manual=1; cryo.dirty=1; samp.manual=1; samp.dirty=1; } } else { if (t!=device) { *t='\0'; str_copy(cryo.device, device); *t='/'; cryo.manual=1; cryo.dirty=1; } t++; if (*t!='\0') { str_copy(samp.device, t); samp.manual=1; samp.dirty=1; } } concatDevice(); deviceFlag=0; } return(0); OnError: return(-1); } int mainBody(void) { int i, iret, tdif; struct timeb tim1; logfileWrite(logMask); while (!quit) { ftime(&tim1); tdif=per-((tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm); if (tdif<0) { tim=tim1.time; break; } /* timeout */ ERR_I(iret=CocHandleRequests(tdif, 0)); if (iret==0) { time(&tim); break; } /* timeout */ tim=tim1.time; if (ser!=NULL) { ERR_I(ExecuteRequest()); } logfileWrite(logMask); } ftime(&tim1); tdif=((tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm)/period; i=period*tdif+tim0.millitm; tim0.time+=i / 1000; tim0.millitm=i % 1000; if (tdif>4) { logfileOut(LOG_MAIN ,"%d cycles lost\n", tdif-1); } if (ser!=NULL) { ERR_I(PeriodicTask()); } if (remoteMode==2) ERR_I(Settings()); return(0); OnError: if (0==strcmp(ErrMessage, "timeout")) { if (noResp==1) { /* this is the second time we have no response */ per=period+15000; /* long period if no response */ cryo.temp=0; samp.temp=0; remoteMode=1; configuring=0; } else { /* logfileShowErr("error"); */ logfileOut(LOG_ALL ,"no response\n"); noResp=1; per=100; /* try again soon */ } return(0); } return(-1); } int main(int argc, char *argv[]) { int logIt=0; int i, iret, cntError, use_stdout=0; char *host; char buf[256], opt; int port, msecTmo; str_copy(cryo.tname,"main"); str_copy(sens1.ch,"A"); str_copy(sens2.ch,"B"); str_copy(samp.tname,"sample stick"); str_copy(sens3.ch,"C"); str_copy(sens4.ch,"D"); cryo.codChanged=1; cryo.scale=1.0; samp.codChanged=1; samp.scale=1.0; logMask=LOG_MAIN; binDir="bin/"; logDir="log/"; serverId="tecs"; host="lnsp26:4000/0"; port=0; msecTmo=0; logfileOut(LOG_MAIN ,"%s ", argv[0]); for (i=1;i1000) { /* round time */ tim0.time=tim0.time-(tim0.time % (period/1000)); tim0.millitm=0; } str_copy(dlogfile, logDir); str_append(dlogfile, serverId); str_append(dlogfile, ".dlog"); logfileOut(LOG_MAIN, "open data log file: %s\n", dlogfile); ERR_I(iret=dlog_open_write_(dlogfile)); if (iret==1) logfileOut(LOG_MAIN, "created new data log file\n"); logfileWrite(logMask); remoteMode=2; prop=50; integ=20; deriv=0; if (ser!=NULL) { LscCmd(ser, "MODE?>remoteMode"); LscCmd(ser, "PID?1>prop,integ,deriv"); } if (remoteMode!=2) configuring=0; per=1; /* advance fast when initializing */ cntError=0; while (!quit) { iret=mainBody(); if (iret<0 || ser==NULL) { cntError++; if (0==strcmp(ErrMessage, "asynsrv error")) { if (ser!=NULL) SerClose(ser); ser=NULL; } if (cntError<4) { logfileShowErr("error in TecsServer/mainBody"); } 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) { LscCmd(ser, "MODE?>remoteMode"); LscCmd(ser, "PID?1>prop,integ,deriv"); } } } else { if (cntError>0) { if (cntError>4) { cntError=4; } cntError--; } } } LogMinMax(0); logfileWrite(logMask); ERR_MSG("got quit command"); OnError: logfileShowErr("exit TecsServer"); dlog_close_w_(); SerClose(ser); CocCloseServer(); return(0); }