Files
sicspsi/tecs/tecs.c
zolliker 317aa90840 .
2007-04-26 14:47:51 +00:00

3646 lines
92 KiB
C

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#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 with 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="<none>";
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 && i<strlen(nam); i++) {
chead[i]=nam[i];
}
for (i=strlen(nam); i<10; i++) {
chead[i]=' ';
}
}
i=0;
if (num>20) 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; i<N_SENSORS; i++) {
sensors[i]->t=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; i<j+2; i++) {
s=sensors[i];
typ=s->type[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 (tH<tHigh) {
p=tHigh-tH;
q=tL-tLow;
if (p==0.0 && q==0.0) { p=1; q=1; } /* should not be the case */
return (tL*p*p+tH*q*q)/(p*p+q*q);
}
}
return tH ;
} else if (tL!=0.0) {
return tL ;
}
return DATA_UNDEF;
}
void LogMinMax(int new) {
char buf[256];
int i;
static int first;
float tbuf;
SensorT *s1, *s2;
sprintf(buf, "@");
if (cryo.sensor1!=NULL) { /* at least one sensor is present */
for (i=0; i<2; i++) {
tpoint=tpoints[i];
s1=tpoint->sensor1;
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 (i<nScan && DisplayFmt(sensors[i+4], fields, &k)) {
i++;
}
}
maxfld=k-1;
/* 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++) {
assert(l<128);
sprintf(buf+l, "DISPFLD %d,%s,%c;", k, fields[k]->ch, 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));
}
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; i<HISTSIZE; i++) {
h->vals[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<alarmListSize;k++) {
str_append(buf,";ALARMST?");
str_append(buf, alarmList[k]);
}
ERR_P(alms=LscCmd(ser, buf+1)); /* send without leading semicolon */
if (0!=strcmp(alarmStatus, alms)) {
str_copy(alarmStatus, alms);
alarmChannels[0]='\0';
for (k=0;k<alarmListSize;k++) {
if (alms[k*4] != '0') {
str_append(alarmChannels, alarmList[k]);
str_append(alarmChannels, " ");
if (NULL==strstr(alarmHistory, alarmList[k])) { /* if not yet in history */
str_append(alarmHistory, alarmList[k]); /* add to history */
}
}
}
if (alarmChannels[0]=='\0') {
if (lockAlarm) {
logfileOut(LOG_MAIN, "No more active alarms, latching alarms: %s!\n", alarmHistory);
} else {
alarmHistory[0]='\0';
alarmChannels[0]='\0';
logfileOut(LOG_MAIN, "No more active alarms\n");
ERR_P(LscCmd(ser, "ALMRST"));
relay=0;
}
} else {
logfileOut(LOG_MAIN, "Alarm on channel %s\n", alarmChannels);
if (!relay0 && set!=0) {
lockAlarm=1;
logfileOut(LOG_MAIN, "Switch off heater\n");
jRange=0;
if (loop==1) { /* turn on high relay manually, switch off heater and reset alarms */
ERR_P(LscCmd(ser, "RELAY 1:2,1;RANGE:0;ALMRST"));
} else {
ERR_P(LscCmd(ser, "RELAY 1:2,1;ANALOG 2:0,0;ALMRST"));
relay=1;
}
} else {
ERR_P(LscCmd(ser, "ALMRST"));
}
}
} else {
ERR_P(LscCmd(ser, "ALMRST"));
}
} else if (loop == 1) {
if (!relay0) logfileOut(LOG_MAIN, "Relay is on!\n");
alarmStatus[0]='\0';
}
relay0=relay;
ERR_I(ReadTemp());
snprintf(ttp, sizeof(ttp), "%.6g %.6g %.6g %.6g %.6g", tm, tr, power, tx, set);
if (htrst!=htrst0) {
LogMinMax(0);
if (htrst==0) {
logfileOut(LOG_MAIN, "heater o.k.\n");
} else {
logfileOut(LOG_MAIN, "%s\n", LscHtrStat(htrst));
}
htrst0=htrst;
}
if (rdTim>=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)<sizeof(gradata));
*grasize=l;
}
return 0;
OnError: return -1;
}
int ShowSensor(StrBuf *buf, SensorT *s, char *name, char *units, char lim) {
if (s->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;i<argc;i++) {
if (argv[i]!=NULL) {
if (argv[i][0]=='-') {
opt=tolower(argv[i][1]);
} else {
opt=' ';
}
if ('l'==opt) {
logIt=1;
logMask=LOG_ALL;
opt=' ';
} else if ('s'==opt) {
use_stdout=1;
opt=' ';
} else if ('n'==opt) {
i++;
str_copy(serverId, argv[i]);
} else if ('b'==opt) {
i++;
str_copy(binDir, argv[i]);
} else if ('d'==opt) {
i++;
str_copy(logDir, argv[i]);
} else if ('m'==opt) {
i++;
str_copy(loggerDir, argv[i]);
} else if ('t'==opt) {
i++;
msecTmo=atoi(argv[i]);
} else if ('h'==opt) {
i++;
str_copy(host, argv[i]);
} else if ('p'==opt) {
i++;
port=atoi(argv[i]);
} else if ('f'==opt) {
i++;
logPeriod=atoi(argv[i]);
} else {
if (NULL!=strchr(argv[i], '=')) {
CocReadVars(argv[i], '\0');
} else {
inistr=str_read_file(argv[i]);
if (inistr==NULL) {
logfileOut(LOG_MAIN ,"?");
} else {
CocReadVars(inistr, '\0');
FREE(inistr);
}
}
}
if (opt!=' ') logfileOut(LOG_MAIN ,"-%c ", opt);
logfileOut(LOG_MAIN ,"%s ", argv[i]);
}
}
assert(logPeriod>0 && 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));
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;
}