From 0cda1588496e3ac62b88447fafea7366e615c222 Mon Sep 17 00:00:00 2001 From: cvs Date: Thu, 16 Aug 2001 10:17:09 +0000 Subject: [PATCH] new tecs version M.Z.08.2001 --- tecs/Makefile | 46 +- tecs/coc_client.c | 426 ++++++--- tecs/coc_client.h | 51 +- tecs/coc_logfile.c | 294 +++--- tecs/coc_logfile.h | 10 +- tecs/coc_server.c | 609 ++++++++++--- tecs/coc_server.h | 81 +- tecs/coc_util.c | 267 ++---- tecs/coc_util.h | 89 +- tecs/myc_buf.c | 218 +++++ tecs/myc_buf.h | 58 ++ tecs/myc_err.c | 144 +++ tecs/myc_err.h | 85 ++ tecs/myc_mem.h | 30 + tecs/myc_str.c | 252 ++++++ tecs/myc_str.h | 122 +++ tecs/myc_time.c | 120 +++ tecs/myc_time.h | 42 + tecs/str.f | 131 +++ tecs/sys_aunix.f | 2 +- tecs/sys_aunix_c.c | 15 +- tecs/sys_util.c | 20 +- tecs/sys_util.h | 36 +- tecs/tecs.c | 2125 ++++++++++++++++++++++++++------------------ tecs/tecs_cli.c | 332 +++++-- tecs/tecs_cli.h | 3 - tecs/tecs_client.f | 169 ++-- tecs/tecs_data.c | 585 ++++++++++++ tecs/tecs_data.h | 47 + tecs/tecs_for.f | 39 +- tecs/tecs_lsc.c | 69 +- tecs/tecs_lsc.h | 6 +- tecs/tecs_plot.f90 | 555 +++++++----- tecs/tecs_serial.c | 263 ++++-- tecs/tecs_serial.h | 13 +- 35 files changed, 5289 insertions(+), 2065 deletions(-) create mode 100644 tecs/myc_buf.c create mode 100644 tecs/myc_buf.h create mode 100644 tecs/myc_err.c create mode 100644 tecs/myc_err.h create mode 100644 tecs/myc_mem.h create mode 100644 tecs/myc_str.c create mode 100644 tecs/myc_str.h create mode 100644 tecs/myc_time.c create mode 100644 tecs/myc_time.h create mode 100644 tecs/str.f create mode 100644 tecs/tecs_data.c create mode 100644 tecs/tecs_data.h diff --git a/tecs/Makefile b/tecs/Makefile index d0dd9b22..76430d40 100644 --- a/tecs/Makefile +++ b/tecs/Makefile @@ -3,47 +3,55 @@ # # Markus Zolliker, March 2000 #-------------------------------------------------------------------------- -LIBR_OBJ= coc_util.o err_handling.o str_util.o str_buf.o -DLOG_OBJ= sys_util.o tecs_dlog.o -SERV_OBJ= tecs.o coc_server.o tecs_lsc.o tecs_serial.o coc_logfile.o $(LIBR_OBJ) $(DLOG_OBJ) +LIBR_OBJ= coc_util.o myc_err.o myc_str.o myc_buf.o myc_time.o +SERV_OBJ= tecs.o coc_server.o tecs_lsc.o tecs_serial.o coc_logfile.o tecs_data.o $(LIBR_OBJ) CLI_OBJ= tecs_cli.o coc_client.o $(LIBR_OBJ) -TCLI_OBJ= tecs_client.o tecs_plot.o tecs_for.o sys_aunix.o sys_aunix_c.o str.o cho.o $(CLI_OBJ) $(DLOG_OBJ) +TCLI_OBJ= sys_aunix.o sys_aunix_c.o $(CLI_OBJ) +TECLI_OBJ= tecs_client.o tecs_plot.o tecs_for.o sys_util.o str.o $(TCLI_OBJ) #------------ for DigitalUnix (add -DFORTIFY to CFLAGS for fortified version) CC=cc + +#CFLAGS= -std1 -g -warnprotos -I../ -I. -I../hardsup -DFORTIFY CFLAGS= -std1 -g -warnprotos -I../ -I. -I../hardsup -#------------ for Linux -##CC=gcc -##CFLAGS = -fwritable-strings -DCYGNUS -DNONINTF -g -I../ -I. -I../hardsup -#------------ .f.o: - f77 -c -g $*.f + f77 -c -u -g $*.f .c.o: $(CC) $(CFLAGS) -c $*.c libtecsl.a: $(CLI_OBJ) - - rm -f libtecsl.a + - rm libtecsl.a ar cr libtecsl.a $(CLI_OBJ) ranlib libtecsl.a -all: libtecsl.a bin/TecsServer tecs +all: libtecsl.a bin/TecsServer bin/TecsClient tecs_plot.o: tecs_plot.f90 - f90 -c -g tecs_plot.f90 + f90 -c -u -g tecs_plot.f90 bin/TecsServer: $(SERV_OBJ) - - rm -f bin/TecsServer + - rm bin/TecsServer $(CC) $(CFLAGS) -o bin/TecsServer -g $(SERV_OBJ) fortify1.c \ -lm -L../hardsup -lhlib -lfor -tecs: $(TCLI_OBJ) - f77 -o tecs -g $(TCLI_OBJ) \ +bin/TecsClient: $(TECLI_OBJ) + f77 -o bin/TecsClient -g $(TECLI_OBJ) \ -L/data/lnslib/lib -lpgplot -so_archive -lreadline -ltermcap -lX11 -lXm +six: six.c term.c sys_select.c $(LIBR_OBJ) + $(CC) $(CFLAGS) -o six six.c term.c sys_select.c $(LIBR_OBJ) \ + -L/data/lnslib/lib -so_archive -lreadline -ltermcap -lX11 -lXm + +rstart: $(LIBR_OBJ) rstart.c myc_str.o myc_err.o + $(CC) $(CFLAGS) -o rstart rstart.c myc_str.o myc_err.o + +keep_running: keep_running.c + $(CC) $(CFLAGS) -o keep_running keep_running.c + clean: - - rm -f *.o - - rm -f *.a - - rm -f bin/TecsServer - - rm -f tecs + - rm *.o + - rm *.a + - rm bin/TecsServer + - rm bin/TecsClient diff --git a/tecs/coc_client.c b/tecs/coc_client.c index 9189ffd4..3373411c 100644 --- a/tecs/coc_client.c +++ b/tecs/coc_client.c @@ -1,19 +1,24 @@ #include #include #include -#include #include #include #include -#include "err_handling.h" +#include +#include "myc_err.h" +#include "coc_util.h" #include "coc_client.h" -#include "str_util.h" +#include "sys_util.h" +#include "myc_str.h" /* --- non ANSI signal --- */ #ifndef SIGPIPE #define SIGPIPE 13 #endif +#define COC_NETTMO 5 +#define COC_RESTMO 60 + /*-------------------------------------------------------------------------*/ int CocConnect(CocConn *conn) { @@ -67,15 +72,13 @@ int CocOpen(CocConn *conn) int CocInitClient(CocConn *conn, char *host, int port, char *magic, int bufsize, char *startcmd) { assert(conn!=NULL); if (bufsize==0) bufsize=1024; - ERR_P(conn->cmdbuf=str_create_buf(bufsize, '\0')); - ERR_P(conn->resbuf=str_create_buf(bufsize, '\0')); + StrLink(&conn->cmdbuf, conn->cmdbuf_); + StrLink(&conn->resbuf, conn->resbuf_); conn->port=port; ERR_I(str_copy(conn->host, host)); ERR_I(str_copy(conn->magic, magic)); ERR_I(str_copy(conn->startcmd, startcmd)); conn->fd=-1; - conn->varList=NULL; - CocVarList(&conn->varList); ERR_I(CocOpen(conn)); ERR_I(CocSendMagic(conn, conn->magic)); return(0); @@ -86,15 +89,17 @@ int CocInitClient(CocConn *conn, char *host, int port, char *magic, int bufsize, int CocSendMagic(CocConn *conn, char *magic) { char *err; + int siz, n; - if (magic[0]!='#') ERR_MSG("magic must start with '#'"); - str_put_start(conn->resbuf); /* use return buffer for command in order to preserve command buffer */ - ERR_I(str_put_str(conn->resbuf, magic)); - ERR_SI(send(conn->fd, conn->resbuf->buf, conn->resbuf->wrpos, 0)); - ERR_I(CocRecv(conn->fd, conn->resbuf)); - ERR_P(err=str_get_str(conn->resbuf, NULL)); - if (*err!='\0') { ErrMsg(err); ErrTxt(": (response from server)",0); goto OnError; } - ERR_I(str_get_end(conn->resbuf)); + StrClear(&conn->resbuf); /* use return buffer for command in order to preserve command buffer */ + ERR_I(StrPut(&conn->resbuf, "", COC_MAGIC)); + ERR_I(StrPut(&conn->resbuf, magic, COC_SEP)); + ERR_I(CocSend(conn->fd, conn->resbuf.buf, conn->resbuf.wrpos)); + ERR_I(CocRecv(conn->fd, &conn->resbuf, COC_NETTMO, NULL)); + ERR_P(err=StrGet(&conn->resbuf, NULL, COC_SEP)); + if (err[0]!=COC_MAGIC) ERR_MSG("magic synch error"); + if (err[1]!='\0') { ErrMsg(err+1); ErrTxt(": (response from server)",0); goto OnError; } + ERR_I(StrGetEnd(&conn->resbuf)); return(0); OnError: return(-1); } @@ -102,9 +107,10 @@ int CocSendMagic(CocConn *conn, char *magic) { /*-------------------------------------------------------------------------*/ int CocCheck(CocConn *conn) { + if (conn->fd<0) return(1); - ERR_SI(send(conn->fd, "quit", 5, 0)); - ERR_I(CocRecv(conn->fd, conn->resbuf)); + ERR_I(CocSend(conn->fd, "_quit", 6)); + ERR_I(CocRecv(conn->fd, &conn->resbuf, COC_NETTMO, NULL)); return(0); OnError: if (ErrCode==ECONNRESET || ErrCode==EPIPE) return(1); @@ -114,16 +120,24 @@ int CocCheck(CocConn *conn) { /*-------------------------------------------------------------------------*/ int CocTryCmd(CocConn *conn) { - int iret=-1; + int iret=-1, siz; signal(SIGPIPE, SIG_IGN); if (conn->fd<0) { +/* ERR_I(iret=CocOpen(conn)); +*/ + ERR_I(iret=CocConnect(conn)); + if (iret == 1) { + CocDelay(500); + ErrTxt("connect",1); return (-1); + } + iret=-1; ERR_I(CocSendMagic(conn, conn->magic)); } - ERR_SI(send(conn->fd, conn->cmdbuf->buf, conn->cmdbuf->wrpos, 0)); - ERR_I(CocRecv(conn->fd, conn->resbuf)); + ERR_I(CocSend(conn->fd, conn->cmdbuf.buf, conn->cmdbuf.wrpos)); + ERR_I(CocRecv(conn->fd, &conn->resbuf, COC_NETTMO, NULL)); return(0); OnError: if (ErrCode==ECONNRESET || ErrCode==EPIPE) return(-2); @@ -134,7 +148,6 @@ int CocTryCmd(CocConn *conn) { int CocCmdWithRetry(CocConn *conn) { int cnt, iret; - char *err; if (conn==NULL) ERR_MSG("not connected"); cnt=3; @@ -152,118 +165,321 @@ int CocCmdWithRetry(CocConn *conn) { ErrShort(ErrMessage); ErrShort("try to reconnect"); } - ERR_P(err=str_get_str(conn->resbuf, NULL)); - if (*err!='\0') { ErrMsg(err); ErrTxt(": (response from server)",0 ); return(-2); } return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ -int CocSet(CocConn *conn, const char *name, const char *value) { - int iret=-1; - +void CocReset(CocConn *conn) { assert(conn!=NULL); - str_put_start(conn->cmdbuf); - ERR_I(str_put_str(conn->cmdbuf, "[")); - ERR_I(str_put_str(conn->cmdbuf, name)); - ERR_I(str_put_str(conn->cmdbuf, value)); - ERR_I(str_put_str(conn->cmdbuf, "]")); - - ERR_I(iret=CocCmdWithRetry(conn)); - - ERR_I(str_get_end(conn->resbuf)); - return(0); - - OnError: return(iret); + StrClear(&conn->cmdbuf); + if (conn->synch!=COC_SYN0) { + conn->synch=COC_SYN0; + } else { + conn->synch=COC_SYN1; + } + StrPut(&conn->cmdbuf, "", conn->synch); + conn->nargs=0; } /*-------------------------------------------------------------------------*/ -int CocGetN(CocConn *conn, const char *name, char *value, int reslen) { - int iret=-1; +int CocPushArg(CocConn *conn, const char *name, void *value, int type) { + StrBuf *buf; + int n; assert(conn!=NULL); - str_put_start(conn->cmdbuf); - ERR_I(str_put_str(conn->cmdbuf, name)); - - ERR_I(iret=CocCmdWithRetry(conn)); - - ERR_P(str_nget_str(conn->resbuf, value, reslen)); - ERR_I(str_get_end(conn->resbuf)); + assert(NULL==strchr(name, ' ')); + buf=&conn->cmdbuf; + n=conn->nargs; + if (n>=sizeof(conn->args)) ERR_MSG("too many return arguments"); + conn->args[n].adr=value; + conn->args[n].type=type; + conn->args[n].cmd=buf->buf + buf->wrpos; + conn->nargs=n+1; + if (value==NULL) { + ERR_I(StrPut(buf, name, ' ')); + } else { + ERR_I(StrPut(buf, name, COC_SEP)); + } return(0); - - OnError: return(iret); + OnError: return(-1); } /*-------------------------------------------------------------------------*/ -int CocCmd(CocConn *conn, const char *rwList) -{ int setmode, i, iret=-1; - const char *t, *s; - char nam[32]; - CocVar *var; - void *adr; +int CocPutStr(CocConn *conn, const char *name, const char *value) { + StrBuf *buf; + + ERR_I(CocPushArg(conn, name, NULL, 4)); + ERR_I(StrPut(&conn->cmdbuf, value, COC_SEP)); + return(0); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +int CocPutFloat(CocConn *conn, const char *name, float value) { + + ERR_I(CocPushArg(conn, name, NULL, COC_FLT)); + ERR_I(StrPutFloat(&conn->cmdbuf, value, COC_SEP)); + return(0); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +int CocPutInt(CocConn *conn, const char *name, int value) { + + ERR_I(CocPushArg(conn, name, NULL, COC_INT)); + ERR_I(StrPutInt(&conn->cmdbuf, value, COC_SEP)); + return(0); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +int CocGetStr(CocConn *conn, const char *name, char *value, int value_len) { + + return(CocPushArg(conn, name, value, value_len)); +} + +/*-------------------------------------------------------------------------*/ + +int CocGetFloat(CocConn *conn, const char *name, float *value) { + + return(CocPushArg(conn, name, value, COC_FLT)); +} + +/*-------------------------------------------------------------------------*/ + +int CocGetInt(CocConn *conn, const char *name, int *value) { + + return(CocPushArg(conn, name, value, COC_INT)); +} + +/*-------------------------------------------------------------------------*/ + +int CocDoIt(CocConn *conn, char *res, int res_len) { + StrBuf *buf; + int i, pending; + CocArg *a; + char *resp, *t, tag; + int iret=0; assert(conn!=NULL); - str_put_start(conn->cmdbuf); - s=rwList; - setmode=0; - do { - t=strchr(s, ','); - if (t==NULL) t=s+strlen(s); - if (*s=='[') { - if (!setmode) ERR_I(str_put_str(conn->cmdbuf, "[")); - s++; - setmode=1; - } - i=t-s; - assert(i<32); - str_ncpy(nam, s, i+1); - if (setmode) { - if (nam[i-1]==']') { i--; nam[i]='\0'; setmode=0; } - ERR_I(str_put_str(conn->cmdbuf, nam)); - ERR_I(CocPutVar(conn->varList, conn->cmdbuf, nam, 0)); - if (!setmode) ERR_I(str_put_str(conn->cmdbuf, "]")); - } else { - var=CocFindVar(conn->varList, nam, NULL); - if (var==NULL) ERR_MSG("variable not found"); - ERR_I(str_put_str(conn->cmdbuf, nam)); - } - s=t+1; - } while (*t!='\0'); + ERR_I(CocCmdWithRetry(conn)); + buf=&conn->resbuf; + while (buf->buf[0] != conn->synch) { /* throw away unsynchronized answers */ + ERR_I(CocRecv(conn->fd, buf, COC_NETTMO, NULL)); + } - ERR_I(iret=CocCmdWithRetry(conn)); + pending=conn->nargs; + *res='\0'; + while (1) { + if (buf->buf[0] != conn->synch) ERR_MSG("synch error"); + ERR_P(StrGet(buf, NULL, conn->synch)); + i=0; + a=conn->args; + while (pending>0 && inargs) { + if (a->type!=0) { + resp=buf->buf + buf->rdpos; + tag=*resp; + if (tag==COC_DELAYED) { /* delayed response */ + resp++; + ERR_P(StrGet(buf, NULL, COC_SEP)); + } else { + pending--; + if (tag==COC_ERR || tag==COC_TRM) { /* error response */ + str_ncat(res, a->cmd, res_len); + resp++; + ERR_P(StrGet(buf, NULL, COC_SEP)); + str_ncat(res, ": ", res_len); + iret=1; + if (tag==COC_TRM) return(1); + } else { + if (a->adr==NULL) { + t=strchr(res, COC_SEP); + str_ncat(res, a->cmd, res_len); + t=strchr(t, ' '); + assert(t!=NULL); /* truncate argument */ + *t=COC_SEP; + str_ncat(res, "=", res_len); + ERR_P(StrGet(buf, NULL, COC_SEP)); + } else { + str_ncat(res, a->cmd, res_len); + str_ncat(res, "=", res_len); + if (a->type==COC_INT) { + ERR_I(StrGetInt(buf, (int *)a->adr, COC_SEP)); + } else if (a->type==COC_FLT) { + ERR_I(StrGetFloat(buf, (float *)a->adr, COC_SEP)); + } else if (a->type>1) { + ERR_P(StrNGet(buf, (char *)a->adr, a->type, COC_SEP)); + } else { + ERR_MSG("unknown type"); + } + a->type=0; + } + } + str_ncat(res, resp, res_len); + str_ncat(res, "\n", res_len); + } + } + i++; a++; + } + ERR_I(StrGetEnd(buf)); + if (pending==0) return(iret); /* no more delayed response awaiting */ - /* read values */ - s=rwList; - setmode=0; - do { - t=strchr(s, ','); - if (t==NULL) t=s+strlen(s); - if (*s=='[') { - s++; - setmode=1; + ERR_I(CocRecv(conn->fd, buf, COC_RESTMO, NULL)); + } + return(iret); + OnError: return(-1); +} + +static int interrupt, logFd=0; + +void CocIntSignal(int sig) { + char buf[4]; + int siz; + + if (logFd) { + interrupt=2; + buf[0]=COC_CLRLOG; + buf[1]=COC_SEP; /* send "clear log" message */ + printf("\nCLRLOG\n"); + CocSend(logFd, buf, 2); + } else { + printf("\ninterrupt\n"); + interrupt=1; + } +} + +int CocWatchLog(CocConn *conn, char *loglist) { + char cbuf[1024]; + StrBuf *buf; + int fd, iret; + int i, siz, n; + + sys_ctrl_init(); + fd=conn->fd; + CocReset(conn); + ERR_I(CocPutStr(conn, "loglist", loglist)); + ERR_I(CocDoIt(conn, cbuf, sizeof(cbuf))); + buf=&conn->resbuf; + interrupt=0; + logFd=fd; + signal(SIGINT, CocIntSignal); + + while (!interrupt) { + logFd=fd; + ERR_I(iret=CocRecv(fd, buf, 60, &logFd)); + if (iret>0) { + if (buf->buf[0]==COC_CLRLOG) { /* confirmed "clear log" message */ + interrupt=3; + } else { /* it's a log message */ + StrReset(buf); + while (!StrEnd(buf)) { + ERR_P(StrGet(buf, cbuf, COC_SEP)); + printf("%s", cbuf); + } + } } - i=t-s; - if (setmode) { - if (*(t-1)==']') setmode=0; - } else { - str_ncpy(nam, s, i+1); - ERR_I(CocGetVar(conn->varList, conn->resbuf, nam, 0)); - } - s=t+1; - } while (*t!='\0'); - ERR_I(str_get_end(conn->resbuf)); + } + signal(SIGINT, SIG_DFL); + logFd=0; + if (interrupt==1) { /* send "clear log" message */ + cbuf[0]=COC_CLRLOG; + cbuf[1]=COC_SEP; /* send "clear log" message */ + printf("\nclrlog\n"); + CocSend(fd, cbuf, 2); + do { + ERR_I(CocRecv(fd, buf, 10, NULL)); + } while (buf->buf[0]!=COC_CLRLOG); + } return(0); + OnError: + signal(SIGINT, SIG_DFL); + return(-1); +} - OnError: return(iret); +int CocShowLog(CocConn *conn, char *loglist, int start, int lines) { + char cbuf[1024]; + StrBuf *buf; + int fd, iret; + int i, siz, n; + + fd=conn->fd; + CocReset(conn); + if (start>0) { + ERR_I(CocPutInt(conn, "logstart", start)); + } + ERR_I(CocPutInt(conn, "loglines", lines)); + ERR_I(CocPutStr(conn, "logshow", loglist)); + ERR_I(CocDoIt(conn, cbuf, sizeof(cbuf))); + buf=&conn->resbuf; + + while (1) { + ERR_I(iret=CocRecv(fd, buf, 10, NULL)); + if (iret<=0) break; + if (buf->buf[0]==COC_CLRLOG) { /* end of log message */ + break; + } else { /* it's a log message */ + StrReset(buf); + while (!StrEnd(buf)) { + ERR_P(StrGet(buf, cbuf, COC_SEP)); + printf("%s", cbuf); + } + } + } + return(0); + OnError: + signal(SIGINT, SIG_DFL); + return(-1); } void CocCloseClient(CocConn *conn) { assert(conn!=NULL); close(conn->fd); - str_free_buf(conn->cmdbuf); - str_free_buf(conn->resbuf); - CocFreeVarList(&conn->varList); } + + +/*-------------------------------------------------------------------------*/ + +static char rbuf[256]; + +int CocSet(CocConn *conn, const char *name, const char *value) { + int iret; + + assert(conn!=NULL); + CocReset(conn); + ERR_I(CocPutStr(conn, name, value)); + ERR_I(iret=CocDoIt(conn, rbuf, sizeof(rbuf))); + if (iret) ERR_MSG(rbuf); + return(0); + OnError: return(-1); +} + +int CocGetN(CocConn *conn, const char *name, char *value, int reslen) { + int iret; + + assert(conn!=NULL); + CocReset(conn); + ERR_I(CocGetStr(conn, name, value, reslen)); + ERR_I(iret=CocDoIt(conn, rbuf, sizeof(rbuf))); + if (iret) ERR_MSG(rbuf); + return(0); + OnError: return(-1); +} + +int CocSetGetN(CocConn *conn, const char *name, const char *cmd, char *value, int reslen) { + int iret; + + assert(conn!=NULL); + CocReset(conn); + ERR_I(CocPutStr(conn, name, cmd)); + ERR_I(CocDoIt(conn, value, reslen)); + return(0); + OnError: return(-1); +} + diff --git a/tecs/coc_client.h b/tecs/coc_client.h index 0ad08e47..5ea34acb 100644 --- a/tecs/coc_client.h +++ b/tecs/coc_client.h @@ -1,17 +1,28 @@ #ifndef _COC_CLIENT_H_ #define _COC_CLIENT_H_ +#include "myc_buf.h" #include "coc_util.h" +typedef struct { + void *adr; + int type; + char *cmd; +} CocArg; + typedef struct { /* private */ int fd, port; - CocVar *varList; - Str_Buf *cmdbuf; /* for sending command */ - Str_Buf *resbuf; /* for response */ + StrBuf cmdbuf; /* for sending command */ + StrBuf resbuf; /* for response */ + char cmdbuf_[COC_CMD_LEN]; + char resbuf_[COC_RES_LEN]; + CocArg args[16]; + int nargs; char host[64]; char magic[32]; char startcmd[512]; + char synch; } CocConn; int CocInitClient(CocConn *conn, char *host, int port, char *magic, int bufsize, char *startcmd); @@ -22,33 +33,47 @@ int CocSendMagic(CocConn *conn, char *magic); /* send magic word to the server for changing access rights */ -int CocCmd(CocConn *conn, const char *rwList); -/* rwList consists of a list of variables to be read or written. - Variables must be separated with commas, variables to be written - must be enclosed in square brackets. +void CocReset(CocConn *conn); +int CocPutStr(CocConn *conn, const char *name, const char *value); +int CocPutFloat(CocConn *conn, const char *name, float value); +int CocPutInt(CocConn *conn, const char *name, int value); +int CocGetStr(CocConn *conn, const char *name, char *value, int value_len); +int CocGetFloat(CocConn *conn, const char *name, float *value); +int CocGetInt(CocConn *conn, const char *name, int *value); +int CocDoIt(CocConn *conn, char *error, int error_len); - Example (read p1 and p4, write p2 and p3): - CocCmd(&conn, "p1,[p2,p3],p4") - - see COC_UTIL.H for the definiton of variables -*/ int CocCheck(CocConn *conn); /* returns 1, if not yet open returns 0, if connection o.k. - retruns -1 (error message), if connection died + returns -1 (error message), if connection died */ + +int CocWatchLog(CocConn *conn, char *list); +/* + Watch indefinitely for log messages +*/ + int CocSet(CocConn *conn, const char *name, const char *value); /* set one variable */ + int CocGetN(CocConn *conn, const char *name, char *value, int reslen); #define CocGet(C,N,V) CocGetN(C,N,V,sizeof(V)) /* read one variable. Use the macro if value is a fixed length array */ + +int CocSetGetN(CocConn *conn, const char *name, const char *cmd, char *value, int reslen); +#define CocSetGet(C,N,S,V) CocSetGetN(C,N,S,V,sizeof(V)) +/* + set and get a variable. Use the macro if value is a fixed length array +*/ + void CocCloseClient(CocConn *conn); /* close the connection to the server */ + #endif /* _COC_CLIENT_H_ */ diff --git a/tecs/coc_logfile.c b/tecs/coc_logfile.c index 4b06d13d..dfc1200d 100644 --- a/tecs/coc_logfile.c +++ b/tecs/coc_logfile.c @@ -1,45 +1,35 @@ -/* switch off ANSI_C_SOURCE for VMS-extended fopen, even when compiling with /ANSI */ -#ifdef __VMS -#ifdef __HIDE_FORBIDDEN_NAMES -#undef __HIDE_FORBIDDEN_NAMES #include -#define __HIDE_FORBIDDEN_NAMES -#else -#include -#endif -#else -#include -#endif - #include -#include -#include #include #include #include #include "coc_logfile.h" -#include "err_handling.h" -#include "str_util.h" +#include "myc_time.h" +#include "myc_err.h" +#include "myc_str.h" static FILE *fil=NULL; -static char lnam[256]="", filnam[256]=""; +static char lnam[224]="", filnam[256]=""; static char ebuf[20000]=""; static char *statusBuf=NULL; static int statusSize; static char *eptr=&ebuf[0]; -static int lastStamp=0; -static int notDated=0; +static int dated=0; static int logMask=0; static int wrtMask=0; static int newLine=1; static int logfileStd; static int dirty, writeAll; +static int lastline=1; +static long int lastpos=0; +static int lastStamp=0; +static int openTime; +static int openDate; -int ftime (struct timeb *__timeptr); /* for some reason not defined in timeb.h with flag -std1 */ +void (*logfileOutRtn)(int, char *)=NULL; -void logfileOpen(int first) { - struct tm *tim; - struct timeb btim; +void logfileOpen(int append) { + int year; if (logfileStd) { fil=stdout; @@ -47,35 +37,35 @@ void logfileOpen(int first) { return; } assert(fil==NULL); - if (first) { - ftime(&btim); - tim=localtime(&btim.time); - if (notDated) { - if (lnam[0]=='\0') { - str_copy(filnam, "test.log"); - } else { - str_copy(filnam, lnam); - str_append(filnam, ".log"); - } + openTime = mycNow(); + openDate = mycDate(openTime); /* date in yyyymmdd decimal encoding */ + openTime = openTime % (24*3600); /* seconds since midnight */ + if (dated) { + sprintf(filnam, "%s%02d-%02d.log", lnam, openDate % 10000 / 100, openDate % 100); + } else { + if (lnam[0]=='\0') { + str_copy(filnam, "test.log"); } else { - sprintf(filnam, "%s%04d-%02d-%02d.log", lnam, tim->tm_year+1900, tim->tm_mon+1, tim->tm_mday); + str_copy(filnam, lnam); + str_append(filnam, ".log"); + } + } + if (dated) { + fil=fopen(filnam, "a+"); + if (fil != NULL) { + fseek(fil, 0, SEEK_SET); /* set position to start */ + year=0; + fscanf(fil, "%4d", &year); + if (year != openDate / 10000) { + fclose(fil); + fil=fopen(filnam, "w+"); /* overwrite old logfile */ + } else { + fseek(fil, 0, SEEK_END); /* set position to end */ + } } } else { - assert(filnam[0]!='\0'); + fil=fopen(filnam, "w+"); /* overwrite last logfile */ } -#ifdef __VMS - if (first && notDated) { - fil=fopen(filnam, "w", "SHR=UPD"); /* new version at restart */ - } else { - fil=fopen(filnam, "a", "SHR=UPD"); - } -#else - if (first && notDated) { - fil=fopen(filnam, "w"); /* overwrite at restart */ - } else { - fil=fopen(filnam, "a"); - } -#endif if (fil==NULL) { printf("Can not open %s\n", filnam); fil=stdout; @@ -83,10 +73,10 @@ void logfileOpen(int first) { return; } ErrSetOutFile(fil); - if (first) { - fprintf(fil, "%04d-%02d-%02d opened logfile\n" - , tim->tm_year+1900, tim->tm_mon+1, tim->tm_mday); - } + fprintf(fil, "%04d-%02d-%02d %02d:%02d:%02d opened logfile\n" + , openDate / 10000, openDate % 10000 / 100, openDate % 100 + , openTime / 3600, openTime / 60 % 60, openTime % 60); + lastStamp = openTime / 60; } void logfileStatusBuffer(char *buffer, int bufsize) { @@ -96,22 +86,20 @@ void logfileStatusBuffer(char *buffer, int bufsize) { char *logfileInit(char *path, int nodate, int use_stdout, int write_all) { str_copy(lnam, path); - lastStamp=-2; logfileStd=use_stdout; writeAll=write_all; - notDated=nodate; + dated=!nodate; logfileOpen(1); return(filnam); } void logfileOut(int mask, const char *fmt, ...) { va_list ap; - char buf[256], *p; + char buf[8192], *p; - assert(mask>0 && mask<32); va_start(ap, fmt); - if (mask & LOG_MAIN && statusBuf!=NULL) { + if (mask & LOG_STAT && statusBuf!=NULL) { if (newLine) { statusBuf[0]='\0'; newLine=0; @@ -119,17 +107,22 @@ void logfileOut(int mask, const char *fmt, ...) buf[statusSize]='\0'; vsprintf(buf, fmt, ap); assert(buf[statusSize]=='\0'); /* check for overflow */ - str_ncat(statusBuf, buf, statusSize); + if (buf[0]=='@') { + str_ncat(statusBuf, buf+1, statusSize); + } else { + str_ncat(statusBuf, buf, statusSize); + } p=strchr(statusBuf, '\n'); if (p!=NULL) { newLine=1; *p='\0'; } } + if (logfileOutRtn!=NULL) { + vsprintf(buf, fmt, ap); /* does not check for overflow! */ + logfileOutRtn(mask, buf); + } if (writeAll) { -#ifdef __VMS - if (fil==NULL) logfileOpen(0); -#endif vfprintf(fil, fmt, ap); wrtMask=LOG_ALL; } else { @@ -139,10 +132,14 @@ void logfileOut(int mask, const char *fmt, ...) eptr=NULL; } else { vsprintf(eptr, fmt, ap); - assert(NULL==strchr(eptr, '\1')); - eptr+=strlen(eptr); + p=strchr(eptr, '\1'); + if (p==NULL) { + eptr+=strlen(eptr); + } else { + eptr=p; /* is in fact an error */ + } eptr[0]='\1'; /* put \1 as separator between blocks */ - eptr[1]=mask; + eptr[1]=mask & 31; eptr[2]='\0'; eptr+=2; } @@ -157,33 +154,35 @@ void logfileMask(int mask) { } void logfileStamp(char *text) { - struct tm *tim; - struct timeb btim; - int stamp; + int time, date, stamp; - ftime(&btim); - tim=localtime(&btim.time); - stamp=tim->tm_hour*60+tim->tm_min; - if (stamp new day -> new logfile */ + time = mycNow(); + date = mycDate(time); /* date in yyyymmdd decimal encoding */ + time = time % (24*3600); /* seconds since midnight */ + + stamp=time / 60; + if (date != openDate ) { /* day has changed -> new logfile */ if (fil!=NULL) { fclose(fil); fil=NULL; } + lastpos=0; + lastline=1; logfileOpen(1); - lastStamp=-2; } - if (stamp>lastStamp+1) { -#ifdef __VMS - if (fil==NULL) logfileOpen(0); -#endif - lastStamp=stamp; - fprintf(fil, "%02d:%02d:%02d --- %s", tim->tm_hour, tim->tm_min, tim->tm_sec, text); - dirty=0; + if (text==NULL) { + if (stamp>lastStamp+1) { + fprintf(fil, "---\t%02d:%02d:%02d\n", stamp / 60, stamp % 60, time % 60, text); + } + } else { + fprintf(fil, "\t%02d:%02d:%02d %s", stamp / 60, stamp % 60, time % 60, text); } + dirty=0; + lastStamp=stamp; } void logfileWrite0(int mask) { char *s, *next; logMask=logMask | mask; - if (dirty) logfileStamp("\n"); /* there was something written since last time */ + if (dirty) logfileStamp(NULL); /* there was something written since last time */ s=ebuf; if (writeAll || *s!='\0' && wrtMask & logMask) { @@ -193,10 +192,9 @@ void logfileWrite0(int mask) { next++; if (*next & logMask) { if (*s=='@') { /* write out time */ - lastStamp-=2; /* force output */ logfileStamp(s+1); } else { - logfileStamp("\n"); /* write stamp before write something */ + logfileStamp(NULL); /* write stamp before write something */ fprintf(fil, "%s", s); dirty=1; } @@ -211,71 +209,131 @@ void logfileWrite0(int mask) { wrtMask=0; } +void logfileScan(int date, void (*scanLine)(void*, char*), void *arg) { + FILE *sFile; + char buf[256], *res; + + if (date == openDate) { + sFile=fil; + rewind(sFile); + } else { + sprintf(filnam, "%s%02d-%02d.log", lnam, date % 10000 / 100, date % 100); + sFile=fopen(filnam, "r+"); + if (sFile==NULL) return; + } + res=fgets(buf, sizeof(buf), sFile); + while (res!=NULL) { + if (res[0]=='\t') { + scanLine(arg, res+1); + } + res=fgets(buf, sizeof(buf), sFile); + } + if (sFile==fil) { + fseek(fil, 0, SEEK_END); + } else { + fclose(sFile); + } +} + void logfileWrite(int mask) { - -#ifdef __VMS - if (fil==NULL) logfileOpen(0); -#endif logfileWrite0(mask); -#ifdef __VMS - if (!logfileStd) { fclose(fil); fil=NULL; } -#else fflush(fil); -#endif - } void logfileShowErr(char *text) { -#ifdef __VMS - if (fil==NULL) logfileOpen(0); -#endif logfileWrite0(LOG_ALL); /* write all */ ErrShow(text); -#ifdef __VMS - if (!logfileStd) { fclose(fil); fil=NULL; } -#else fflush(fil); -#endif } void logfileClose() { -#ifdef __VMS - if (fil==NULL) logfileOpen(0); -#endif logfileWrite0(LOG_MAIN+LOG_INFO); lastStamp=-2; - logfileStamp("\n"); + logfileOut(LOG_MAIN, "closed\n"); + logfileStamp(NULL); if (fil!=NULL) { fclose(fil); fil=NULL; } filnam[0]='\0'; } -void logfileOutBuf(int mask, Str_Buf *buf) +void logfileOutBuf(int mask, StrBuf *buf) { char str[256]; - int rd0, sep; + int rd0; + char *ret; rd0=buf->rdpos; if (buf->rdpos < 0 || buf->rdpos >= buf->dsize || buf->wrpos < 0 || buf->wrpos >= buf->dsize) { logfileOut(mask, ""); return; } - sep=0; - while (buf->rdpos < buf->wrpos) { - str_get_str(buf, str); - if (buf->sep=='\0') { - if (sep) logfileOut(mask, " "); - if (*str=='\0') { - logfileOut(mask, "."); - } else { - logfileOut(mask, "%s", str); - } - sep=1; + while (!StrEnd(buf)) { + ret=StrGet(buf, str, '\0'); + if (ret==NULL) { + ret="..."; + buf->rdpos=buf->wrpos; + } + if (ret[0]<32 && ret[0]>0) { + logfileOut(mask, "[%d]%s;", ret[0], ret+1); } else { - if (sep) logfileOut(mask, "%c", buf->sep); - logfileOut(mask, "%s", str); - sep=1; + logfileOut(mask, "%s;", ret); } } buf->rdpos=rd0; } + +int logfileLength(void) { + char lin[256]; + int l, ll; + + if (logfileStd || fil==NULL) return 0; + fseek(fil, lastpos, SEEK_SET); + ll=lastpos; + l=lastline; + while (NULL!=fgets(lin, sizeof(lin), fil)) { + lastpos=ll; + ll=ftell(fil); + lastline=l; + l++; + } + return(lastline); +} + +long int logfilePos(int n) { + /* set file to the start of n-th last line n, if n<0 then position to the -n-th line */ + int i; + char lin[256]; + + if (logfileStd || fil==NULL) return 0; + if (n>0) { + n=logfileLength()-n+1; + } else { + n=-n; + } + fseek(fil, 0, SEEK_SET); + for (i=1; i #include +#include #include #include #include #include #include #include +#include +#include "myc_mem.h" #include "sys_util.h" -#include "err_handling.h" +#include "myc_err.h" #include "coc_logfile.h" +#include "coc_util.h" #include "coc_server.h" -#include "str_util.h" +#include "myc_str.h" +#include "myc_time.h" -static Str_Buf *buf, *bufo; +#define COC_NUL COC_SEP + +typedef struct _CocVar { + struct _CocVar *next; + char name[32]; + void *var; + int access; + int type; + void *strucType; + int (*hdl)(int, void *); + int pending; +} CocVar; + +CocVar *serverVarList=NULL; +static CocVar **varListHandle=&serverVarList; +static CocVar *lastDef=NULL; + +typedef struct { + CocVar *var; + void *base; + int mode; +} Pend; + +typedef struct _CocClient { + struct _CocClient *next; + int fd; + int mode; + Pend pend[16]; + int npend; + int logmask; + char synch; + void *data; +} CocClient; + +void *(*setData)(void *); + +/* +static CocClientData **clData; +static int clDataSize; +*/ + +DeclStrBuf(buf, COC_CMD_LEN); +DeclStrBuf(bufo, COC_RES_LEN); static fd_set mask, rmask; static int maxfd; -struct CocClient *cList, *cLastCmd=NULL; +CocClient *cList; static int mainFd; static int modified; +static char loglist[16]; -int CocInitServer(int bufsize, int port) { +void CocVarList(void **varList) { + if (varList==NULL) { + varListHandle=(CocVar **)varList; + } else { + varListHandle=&serverVarList; + } +} + +void CocList() { + CocVar *p; + + p=*varListHandle; + while (p!=NULL) { + printf("%s %d ", p->name, p->type); + p=p->next; + } + printf("\n"); +} + +CocVar *CocFindVar1(const char *name) { + CocVar *p; + + p=*varListHandle; + while (p!=NULL && 0!=strcasecmp(p->name,name)) p=p->next; + return(p); +} + +void *CocFindVar(const char *name, void **adr) { + CocVar *p, *t; + const char *f; + void *base; + char nam[32]; + + f=str_split(nam, name, '.'); + if (f==NULL) { + f=str_split(nam, name, '-'); + if (f!=NULL) { + if (f[0]!='>') { + f=NULL; + } else { + f++; + } + } + } + if (f!=NULL) { + if (adr!=NULL) *adr=NULL; + p=CocFindVar1(nam); + if (p==NULL) { return(NULL); } + t=p->strucType; + if (t==NULL) { return(NULL); } + str_copy(nam, t->name); + str_append(nam, ":"); + str_append(nam, f); + if (adr!=NULL) { + base=p->var; + if (p->type==COC_PTR) base=*(void **)base; + *adr=base; + } + } else if (adr!=NULL) { + *adr=NULL; + } + p=CocFindVar1(nam); + if (p!=NULL && p->type==COC_ALIAS) { /* recursive call for alias */ + p=CocFindVar(p->var, adr); + } + return(p); +} + +void *CocIntPtr(int *ptr) { return(ptr); } +void *CocFltPtr(float *ptr) { return(ptr); } +void *CocChrPtr(char *ptr) { return(ptr); } + +void *CocDefVar(const char *name, void *var, int type, int access) { + CocVar *p; + const char *f; + void *adr; + + assert(varListHandle!=NULL); + p=CocFindVar1(name); + if (p==NULL) { + NEW(p,CocVar); + p->next=*varListHandle; + *varListHandle=p; + str_copy(p->name, name); + p->type=type; + } else { + assert(p->type==type); + } + p->var=var; + p->access=access; +/* printf("define %s %d\n", name, (int)var); */ + lastDef=p; + return(p); + OnError: + assert(0); +} + +void CocHdl(int (*handler)(int, void *)) { + assert(lastDef!=NULL); + lastDef->hdl=handler; +} + +void CocDefVarS(const char *name, const char *tname, void *var, int type) { + CocVar *p, *t; + + assert(type==COC_PTR || type==COC_STRUCT); + p=CocDefVar(name, var, type, COC_RDONLY); + p->strucType=CocDefVar(tname, NULL, COC_TYPE, COC_RDONLY); +} + +char err_name[64]; + +int CocGetThisVar(CocVar *var, void *base, StrBuf *buf, int separator) { + void *adr; + int iret; + + if (base==NULL) { + adr=var->var; + if (adr==NULL) + ERR_MSG("NULL pointer accessed"); + } else { /* dereference */ + adr=(char *)base + (int)var->var; + } + /* printf("get %s %d\n", name, (int)adr); */ + if (var->type==-1) { + ERR_I(StrGetInt(buf, (int *)adr, separator)); + } else if (var->type==-2) { + ERR_I(StrGetFloat(buf, (float *)adr, separator)); + } else if (var->type>1) { + ERR_P(StrNGet(buf, (char *)adr, var->type, separator)); + } else { + ERR_MSG("unknown type"); + } + return(0); + OnError: return(-1); +} + +int CocPutThisVar(CocVar *var, void *base, StrBuf *buf, int separator) { + void *adr; + int iret; + + if (base==NULL) { + adr=var->var; + if (adr==NULL) + ERR_MSG("NULL pointer accessed"); + } else { /* dereference */ + adr=(char *)base + (int)var->var; + } + /* printf("put %s %d\n", name, (int)adr); */ + if (var->type==-1) { + ERR_I(StrPutInt(buf, *(int *)adr, separator)); + } else if (var->type==-2) { + ERR_I(StrPutFloat(buf, *(float *)adr, separator)); + } else if (var->type>1) { + ERR_I(StrPut(buf, adr, separator)); + } else { + ERR_MSG("unknown type"); + } + return(0); + OnError: return(-1); +} + +int CocGetVar(const char *name, StrBuf *buf, int separator) { + CocVar *var; + void *base; + + var=CocFindVar(name, &base); + if (var==NULL) ERR_MSG("undefined variable"); + ERR_I(CocGetThisVar(var, base, buf, separator)); + return(0); + OnError: str_copy(err_name, name); ErrTxt(err_name,0); return(-1); +} + +int CocPutVar(const char *name, StrBuf *buf, int separator) { + CocVar *var; + void *base; + + var=CocFindVar(name, &base); + if (var==NULL) ERR_MSG("undefined variable"); + ERR_I(CocPutThisVar(var, base, buf, separator)); + return(0); + OnError: str_copy(err_name, name); ErrTxt(err_name,0); return(-1); +} + +void CocFreeVarList(void) { + CocVar *p, *v; + + v=*varListHandle; + while (v!=NULL) { + p=v; + v=p->next; + p->next=NULL; + FREE(p); + } + *varListHandle=NULL; +} + +void CocToClients(int mask, char *str) { + int iret; + CocClient *cl; + + cl=cList->next; + while (cl!=NULL) { + if (cl->logmask & mask) { + iret=CocSend(cl->fd, str, strlen(str)+1); + if (iret<0) { + cl->logmask=0; /* disable logging for dead clients */ + logfileOut(LOG_MAIN, "(%d) disconnected while logging\n", cl->fd); + } + } + cl=cl->next; + } +} + +int CocInitServer(void *(*setDataRtn)(void *), int port) { int i; struct sockaddr_in sadr; char *err; - if (bufsize==0) bufsize=1024; - ERR_P(buf=str_create_buf(bufsize, '\0')); - ERR_P(bufo=str_create_buf(bufsize,'\0')); - NEW(cList); /* empty header */ - - /* first try to connect to an existing server */ + setData=setDataRtn; + /* + clDataSize=clientDataSize; + clData=clientData; + */ + NEW(cList,CocClient); /* empty header */ ERR_SI(mainFd=socket(AF_INET, SOCK_STREAM, 0)); i = 1; ERR_SI(setsockopt(mainFd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))); /* allow quick port reuse */ ERR_I(CocCreateSockAdr(&sadr, NULL, port)); ERR_SI(bind(mainFd, (struct sockaddr *)&sadr, sizeof(sadr))); + logfileOutRtn=CocToClients; logfileOut(LOG_INFO, "created server on port %d\n", port); ERR_SI(listen(mainFd, 8)); FD_ZERO(&mask); FD_SET(mainFd, &mask); maxfd=mainFd+1; + CocDefStr(loglist, COC_RDWR); return(0); OnError: return(-1); } +int CocHandleThis(CocVar *var, void *base, StrBuf *outBuf, int mode) { + int iret; + + if (var->hdl!=NULL) { + iret=var->hdl(mode, base); + if (iret<0) { /* error */ + ErrShow(var->name); + ERR_I(StrPut(outBuf, "", COC_ERR)); /* signal error message */ + ERR_I(StrPut(outBuf, ErrMessage, COC_SEP)); + return(0); + } + if (iret==COC_DRD) { + ERR_I(StrPut(outBuf, "", COC_DELAYED)); /* delayed response message */ + ERR_I(StrPut(outBuf, "", COC_SEP)); /* empty message */ + return(COC_DRD); + } + if (iret!=0 && iret!=COC_DWR) + ERR_MSG("illegal return value from handler"); + } else { + iret=0; + } + ERR_I(CocPutThisVar(var, base, outBuf, COC_NUL)); + return(iret); + OnError: return(-1); +} + +int CocPushThisHandler(CocVar *var, CocClient *cl, void *base, int mode) { + int n; + + if (mode==COC_DWR) { + if (var->pending) return(0); + var->pending=1; + } + n=cl->npend; + if (n>=sizeof(cl->pend)) { + ERR_MSG("too many commands") + } + cl->pend[n].var=var; + cl->pend[n].base=base; + cl->pend[n].mode=mode; + cl->npend=n+1; + return(0); + OnError: return(-1); +} + +int CocCallHandlers(void) { + CocClient *cl; + CocVar *var; + Pend *p; + int i, iret, mode, delayedRead; + char synch; + DeclStrBuf(bufr, COC_RES_LEN); + + cl=cList->next; + while (cl!=NULL) { + + delayedRead=0; + /* treat delayed write handlers first */ + for (i=0; inpend; i++) { + p=&cl->pend[i]; + mode=p->mode; + var=p->var; + assert(var!=NULL && var->hdl!=NULL); + if (mode==COC_DWR) { + var->pending=0; + ERR_I(var->hdl(mode, p->base)); + p->mode=0; + } else { + delayedRead=1; + } + } + if (delayedRead) { + StrClear(&bufr); + synch=cl->synch; + ERR_I(StrPut(&bufr, "", cl->synch)); + for (i=0; inpend; i++) { + p=&cl->pend[i]; + mode=p->mode; + var=p->var; + assert(var!=NULL && var->hdl!=NULL); + if (mode==COC_DRD) { + iret=var->hdl(mode, p->base); + if (iret<0) { /* error */ + ERR_I(StrPut(&bufr, "", COC_ERR)); /* signal error message */ + ERR_I(StrPut(&bufr, ErrMessage, COC_SEP)); + } + ERR_I(CocPutThisVar(var, p->base, &bufr, COC_NUL)); + } + } + if (cl->synch==synch) { /* send only if no new request from client received */ + assert(cl->fd!=0); + ERR_I(CocSend(cl->fd, bufr.buf, bufr.wrpos)); + } + } + cl->npend=0; + cl=cl->next; + } + return(0); + OnError: + cl->npend=0; + return(-1); +} + +void CocShowHandlers(char *buf, int buf_len) { + CocClient *cl; + Pend *p; + int i; + + buf[0]='\0'; + cl=cList->next; + while (cl!=NULL) { + for (i=0; inpend; i++) { + p=&cl->pend[i]; + if (p->mode==COC_DWR) { + assert(p->var!=NULL); + if (buf[0]!='\0') str_ncat(buf, ", ", buf_len); + str_ncat(buf, p->var->name, buf_len); + } + } + cl=cl->next; + } + return; +} + int CocHandle1Request(int tmo_msec, int fd) { struct sockaddr_in cadr; struct hostent *h; struct timeval tmo={0,1}; - struct CocClient *cl, *cl0; - int i, newfd, setmode; - size_t cadrlen; - char *err, *varname; + CocClient *cl, *cl0; + CocVar *var; + int i, lmask, newfd, n, iret; + sys_adr_len cadrlen; /* see sys_util.h */ + char *err, *cmd, *arg, *varname; + void *base; rmask=mask; if (fd>0) FD_SET(fd, &rmask); @@ -76,14 +458,18 @@ int CocHandle1Request(int tmo_msec, int fd) { ERR_SI(newfd=accept(mainFd, (struct sockaddr *)&cadr, &cadrlen)); FD_SET(newfd, &mask); if (newfd>=maxfd) maxfd=newfd+1; - cl=cList; + NEW(cl, CocClient); cl->fd=newfd; cl->mode=0; - cl->cmd[0]='\0'; - cl->res[0]='\0'; - NEW(cList); + if (setData!=NULL) { + ERR_P(cl->data = setData(NULL)); /* create new client data object */ + } + /* + ERR_SP(cList=calloc(1,sizeof(CocClient)+clDataSize)); + */ + cl->next=cList->next; cList->next=cl; - h=gethostbyaddr(&cadr.sin_addr, 4, AF_INET); + h=gethostbyaddr((void *)&cadr.sin_addr, 4, AF_INET); if (h==NULL) { logfileOut(LOG_INFO, "(%d) open from %s\n", newfd, "local"); } else { @@ -93,8 +479,8 @@ int CocHandle1Request(int tmo_msec, int fd) { cl0=cList; cl=cl0->next; while (cl!=NULL) { if (FD_ISSET(cl->fd, &rmask)) { - buf->wrpos=recv(cl->fd, buf->buf, buf->dsize, 0); - if (buf->wrpos<=0) { + iret=CocRecv(cl->fd, &buf, -1, NULL); + if (iret<=0) { logfileOut(LOG_INFO, "(%d) disconnected\n",cl->fd); close(cl->fd); FD_CLR(cl->fd, &mask); @@ -102,76 +488,81 @@ int CocHandle1Request(int tmo_msec, int fd) { FREE(cl); cl=cl0; } else { - - str_put_start(bufo); - str_get_start(buf); - ERR_I(str_put_str(bufo, "")); /* empty error message */ - setmode=0; + cl->logmask=0; /* stop output to log client */ + lmask=0; + StrReset(&buf); + StrClear(&bufo); err=NULL; - ERR_P(varname=str_get_str(buf, NULL)); logfileOut(LOG_NET, "(%d) ", cl->fd); - if (varname[0]=='#') { /* access code */ - if (0==strcmp(varname,"#rdacc")) { - logfileOut(LOG_INFO, "set read mode\n"); - cl->mode=1; - } else if (0==strcmp(varname,"#rwacs")) { - logfileOut(LOG_INFO, "set write mode\n"); - cl->mode=2; - } else { - err="bad access code"; - } - } else if (cl->mode==0) { - err="no access"; - } else { - while (1) { - if (varname[0]=='[') { - if (cl->mode<2) { err="no write access"; break; } - setmode=1; /* switch to set mode */ - } else if (varname[0]==']') { /* switch to read mode */ - setmode=0; - } else if (setmode) { - if (0==strcmp("$", varname)) { /* special case: command */ - ERR_P(str_get_str(buf, cl->cmd)); - cl->res[0]='\0'; - } else { - i=CocGetVar(serverVarList, buf, varname, 1); - if (i<0) { - err=ErrMessage; break; - } - } - modified=1; + logfileOutBuf(LOG_NET, &buf); + /* cl->npend=0; why that ? */ + logfileOut(LOG_NET, "\n"); + cl->synch=buf.buf[0]; + ERR_P(StrGet(&buf, NULL, cl->synch)); + ERR_I(StrPut(&bufo, "", cl->synch)); + while (!StrEnd(&buf)) { + ERR_P(varname=StrGet(&buf, NULL, ' ')); + if (cl->synch==COC_MAGIC) { /* access code */ + if (0==strcmp(varname,"rdacs")) { + logfileOut(LOG_INFO, "set read mode\n"); + cl->mode=1; + ERR_I(StrPut(&bufo, "", COC_SEP)); /* empty message */ + } else if (0==strcmp(varname,"rwacs")) { + logfileOut(LOG_INFO, "set write mode\n"); + cl->mode=2; + ERR_I(StrPut(&bufo, "", COC_SEP)); /* empty message */ } else { - if (0==strcmp("$", varname)) { /* special case: response */ - ERR_I(str_put_str(bufo, cl->res)); - cl->res[0]='\0'; + ERR_I(StrPut(&bufo, "", COC_ERR)); /* signal error message */ + ERR_I(StrPut(&bufo, "bad access code", COC_SEP)); + } + ERR_P(StrGet(&buf, NULL, COC_NUL)); /* skip separator */ + } else if (cl->mode==0) { + ERR_I(StrPut(&bufo, "", COC_ERR)); /* signal terminal error message */ + ERR_I(StrPut(&bufo, "no access", COC_SEP)); + ERR_P(StrGet(&buf, NULL, COC_NUL)); /* skip separator */ + } else { + if (cl->data!=NULL) { + setData(cl->data); + } + var=CocFindVar(varname, &base); + if (var==NULL) { + ERR_I(StrPut(&bufo, "", COC_ERR)); /* signal error message */ + ERR_I(StrPut(&bufo, "undefined variable", COC_SEP)); + ERR_P(StrGet(&buf, NULL, COC_NUL)); /* skip separator */ + } else if (buf.seen) { /* separator was there: set mode */ + if (var->access > cl->mode) { + ERR_I(StrPut(&bufo, "", COC_ERR)); /* signal error message */ + ERR_I(StrPut(&bufo, "no access", COC_SEP)); + ERR_P(StrGet(&buf, NULL, COC_NUL)); /* skip separator */ } else { - i=CocPutVar(serverVarList, bufo, varname, 0); - if (i<0) { - err=ErrMessage; break; + ERR_I(CocGetThisVar(var, base, &buf, COC_SEP)); + if (0==strcmp(var->name,"loglist")) { + str_upcase(loglist, loglist); + if (NULL!=strchr(loglist,'A')) lmask = lmask | LOG_ALL; + if (NULL!=strchr(loglist,'S')) lmask = lmask | LOG_SER; + if (NULL!=strchr(loglist,'N')) lmask = lmask | LOG_NET; + if (NULL!=strchr(loglist,'I')) lmask = lmask | LOG_INFO; + if (NULL!=strchr(loglist,'M')) lmask = lmask | LOG_MAIN; + ERR_I(StrPut(&bufo, "", COC_NUL)); /* o.k. */ + } else { + ERR_I(iret=CocHandleThis(var, base, &bufo, COC_WR)); + if (iret) ERR_I(CocPushThisHandler(var, cl, base, iret)); } + modified=1; } + } else { + ERR_P(StrGet(&buf, NULL, COC_NUL)); /* skip separator */ + ERR_I(iret=CocHandleThis(var, base, &bufo, COC_RD)); + if (iret) ERR_I(CocPushThisHandler(var, cl, base, iret)); } - if (buf->rdpos>=buf->wrpos) { - ERR_I(str_get_end(buf)); - break; - } - ERR_P(varname=str_get_str(buf, NULL)); } - str_get_start(buf); - logfileOutBuf(LOG_NET, buf); - str_get_start(bufo); - logfileOut(LOG_NET, " |"); - logfileOutBuf(LOG_NET, bufo); } - if (err==NULL) { - logfileOut(LOG_NET, "\n"); - } else { - str_put_start(bufo); /* reset output */ - str_put_str(bufo, err); /* put error message */ - logfileOut(LOG_NET, " (%s)\n", err); - /* logfileMask(LOG_NET); */ - } - ERR_SI(send(cl->fd, bufo->buf, bufo->wrpos, 0)); + ERR_I(StrGetEnd(&buf)); + logfileOut(LOG_NET, " "); + logfileOutBuf(LOG_NET, &bufo); + logfileOut(LOG_NET, "\n"); + ERR_I(CocSend(cl->fd, bufo.buf, bufo.wrpos)); + cl->logmask=lmask; } } cl0=cl; cl=cl->next; @@ -183,54 +574,30 @@ int CocHandle1Request(int tmo_msec, int fd) { } int CocHandleRequests(int tmo_msec, int fd) { - struct timeb tim1, tim0; - int tdif, iret; + int tdif, iret, tim0; if (modified && fd==0) { /* earlier modification */ modified=0; return(2); } - ftime(&tim0); + tim0=mycMsecSince(0); tdif=tmo_msec; while (tdif>=0) { ERR_I(iret=CocHandle1Request(tdif, fd)); if (fd==0) { - if (iret==2) return(2); /* modification of a varaible */ + if (iret==2) return(2); /* modification of a variable */ } else { if (iret==1) return(1); /* event on fd */ } if (iret==0) return(0); /* timeout */ - ftime(&tim1); - tdif=tmo_msec-((tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm); + tdif = tmo_msec - mycMsecSince(tim0); } return(0); /* timeout */ OnError: return(-1); } -struct CocClient *CocGetNextCmd() { - struct CocClient *cl; - - cl=cLastCmd; - while (cl!=NULL) { - if (cl->cmd[0]!='\0') { - cLastCmd=cl->next; - return(cl); - } - cl=cl->next; - } - cl=cList->next; - while (cl!=NULL && cl!=cLastCmd) { - if (cl->cmd[0]!='\0') { - cLastCmd=cl->next; - return(cl); - } - cl=cl->next; - } - return(NULL); -} - void CocCloseServer() { - struct CocClient *cl, *cl0; + CocClient *cl, *cl0; cl=cList->next; while (cl!=NULL) { @@ -241,6 +608,4 @@ void CocCloseServer() { } FREE(cList); close(mainFd); - str_free_buf(buf); str_free_buf(bufo); - logfileClose(); } diff --git a/tecs/coc_server.h b/tecs/coc_server.h index 3df226ef..f3986989 100644 --- a/tecs/coc_server.h +++ b/tecs/coc_server.h @@ -1,11 +1,78 @@ #ifndef _SERVER_H_ #define _SERVER_H_ -#include "coc_util.h" +#include "myc_buf.h" -struct CocClient { struct CocClient *next; int fd; int mode; char cmd[80]; char res[80]; }; +void CocVarList(void **varlist); +/* + instal a variable list +*/ -int CocInitServer(int bufsize, int port); +void CocFreeVarList(void); +/* + free variable list +*/ + +void *CocFindVar(const char *name, void **adr); +/* + find a variable. returns NULL if not found. +*/ + +int CocPutVar(const char *name, StrBuf *buf, int separator); +/* + put a variable named of variable list to the buffer +*/ + +int CocGetVar(const char *name, StrBuf *buf, int separator); +/* + get a variable named of variable list from the buffer +*/ + +void CocHdl(int (*handler)(int, void *)); +/* + define handler for last defined item +*/ + +void *CocIntPtr(int *ptr); +void *CocFltPtr(float *ptr); +void *CocChrPtr(char *ptr); +void *CocDefVar(const char *name, void *var, int type, int access); +void CocDefVarS(const char *name, const char *tname, void *var, int type); +/* + Define variables. Call this routines not directly, but through + one of the macros below. +*/ + +#define CocDefInt(V,A) CocDefVar(#V,CocIntPtr(&V),COC_INT,A) +#define CocDefFlt(V,A) CocDefVar(#V,CocFltPtr(&V),COC_FLT,A) +#define CocDefStr(V,A) CocDefVar(#V,CocChrPtr(V),sizeof(V),A) +#define CocDefPtr(V,S) CocDefVarS(#V,#S,&V,(V!=(S *)NULL,COC_PTR)); +#define CocDefStruct(V,S) CocDefVarS(#V,#S,&V,(&V!=(S *)NULL,COC_STRUCT)); +#define CocIntFld(S,V,A) CocDefVar(#S":"#V,CocIntPtr(&((S *)NULL)->V),COC_INT,A); +#define CocFltFld(S,V,A) CocDefVar(#S":"#V,CocFltPtr(&((S *)NULL)->V),COC_FLT,A); +#define CocStrFld(S,V,A) CocDefVar(#S":"#V,CocChrPtr(((S *)NULL)->V),sizeof(((S *)NULL)->V),A); +#define CocDefCmd(V) CocDefVar("$",V,sizeof(V),0) +#define CocDefStrPtr(V,S,A) CocDefVar(#V,V,S,A) +#define CocAlias(A,V) CocDefVar(#A, #V, COC_ALIAS,0); + +#define COC_RDONLY 3 +#define COC_RDWR 2 +#define COC_RDWRALL 1 + +#define COC_WR 1 +#define COC_RD 2 +#define COC_DWR 3 +#define COC_DRD 4 +#define COC_SHOW 5 + +#define COC_INT -1 +#define COC_FLT -2 +#define COC_PTR -3 +#define COC_STRUCT -4 +#define COC_TYPE -5 +#define COC_ALIAS -6 + +int CocInitServer(void *(*setDataRtn)(void *), int port); int CocHandleRequests(int tmo_msec, int fd); int CocHandle1Request(int tmo_msec, int fd); @@ -30,11 +97,13 @@ int CocHandle1Request(int tmo_msec, int fd); */ -struct CocClient *CocGetNextCmd(void); -/* - get next client with a pending command +/* server handlers removed +int CocPushHandler(const char *name); */ +int CocCallHandlers(void); +void CocShowHandlers(char *buf, int buf_len); + void CocCloseServer(void); #endif /* _SERVER_H_ */ diff --git a/tecs/coc_util.c b/tecs/coc_util.c index dd8a6e0f..10835eaf 100644 --- a/tecs/coc_util.c +++ b/tecs/coc_util.c @@ -1,24 +1,15 @@ #include -#include -#include #include -#include +#include #include #include #include -#include -#include "sys_util.h" -#include "err_handling.h" -#include "str_util.h" +#include "myc_err.h" +#include "myc_str.h" #include "coc_util.h" /*-------------------------------------------------------------------------*/ /* CreateSocketAddress stolen from Tcl. Thanks to John Ousterhout */ -CocVar *serverVarList=NULL; -static CocVar **varListHdl=&serverVarList; -int CocRD=0; -int CocWR=0; - int CocCreateSockAdr( struct sockaddr_in *sockaddrPtr, /* Socket address */ const char *host, /* Host. NULL implies INADDR_ANY */ @@ -55,202 +46,6 @@ int CocCreateSockAdr( /*-------------------------------------------------------------------------*/ -int CocRecv(int fd, Str_Buf *buf) -{ - struct timeval tmo={0,1}; - fd_set mask; - int i; - - tmo.tv_sec=5; /* timeout 5 sec. */ - - FD_ZERO(&mask); - FD_SET(fd, &mask); - ERR_SI(i=select(fd+1,&mask,NULL,NULL,&tmo)); - if (i==0) ERR_MSG("time out"); - - ERR_SI(buf->wrpos=recv(fd, buf->buf, buf->dsize, 0)); - if (buf->wrpos==0) { ERR_COD(ECONNRESET); } - str_get_start(buf); - return(buf->wrpos); - OnError: return(-1); -} - -void CocVarList(CocVar **varList) { - assert(varList!=NULL); - varListHdl=varList; -} - -void CocList() { - CocVar *p; - - p=*varListHdl; - while (p!=NULL) { - printf("%s %d ", p->name, p->type); - p=p->next; - } - printf("\n"); -} - -CocVar *CocFindVar1(CocVar *varList, const char *name) { - CocVar *p; - - p=varList; - while (p!=NULL && 0!=strcasecmp(p->name,name)) p=p->next; - return(p); -} - -CocVar *CocFindVar(CocVar *varList, const char *name, void **adr) { - CocVar *p, *t; - const char *f; - void *base; - char nam[32]; - - f=str_split(nam, name, '.'); - if (f==NULL) { - f=str_split(nam, name, '-'); - if (f!=NULL) { - if (f[0]!='>') { - f=NULL; - } else { - f++; - } - } - } - if (f!=NULL) { - if (adr!=NULL) *adr=NULL; - p=CocFindVar1(varList, nam); - if (p==NULL) { return(NULL); } - t=p->strucType; - if (t==NULL) { return(NULL); } - str_copy(nam, t->name); - str_append(nam, ":"); - str_append(nam, f); - if (adr!=NULL) { - base=p->var; - if (p->type==COC_PTR) base=*(void **)base; - *adr=base; - } - } else if (adr!=NULL) { - *adr=NULL; - } - p=CocFindVar1(varList, nam); - if (p!=NULL && p->type==COC_ALIAS) { /* recursive call for alias */ - p=CocFindVar(varList, p->var, adr); - } - return(p); -} - -CocVar *CocDefVar(const char *name, void *var, int type, int *flag) { - CocVar *p; - const char *f; - void *adr; - - assert(varListHdl!=NULL); - p=CocFindVar1(*varListHdl, name); - if (p==NULL) { - NEW(p); - p->next=*varListHdl; - *varListHdl=p; - str_copy(p->name, name); - p->type=type; - } else { - assert(p->type==type); - } - p->var=var; - p->flag=flag; -/* printf("define %s %d\n", name, (int)var); */ - return(p); - OnError: - assert(0); -} - -void CocDefVarS(const char *name, const char *tname, void *var, int type) { - CocVar *p, *t; - - assert(type==COC_PTR || type==COC_STRUCT); - p=CocDefVar(name, var, type, &CocRD); - p->strucType=CocDefVar(tname, NULL, COC_TYPE, &CocRD); -} - -char err_name[64]; - -int CocGetVar(CocVar *varList, Str_Buf *buf, const char *name, int secure) { - CocVar *var; - void *adr; - - var=CocFindVar(varList, name, &adr); - if (var==NULL) ERR_MSG("undefined variable"); - if (adr==NULL) { - adr=var->var; - } else { - adr=(char *)adr + (int)var->var; - } - if (secure) { /* we are the server */ - if (var->flag==&CocRD) ERR_MSG("variable is read only"); - } - /* printf("get %s %d\n", name, (int)adr); */ - if (var->type==-1) { - ERR_I(str_get_int(buf, (int *)adr)); - } else if (var->type==-2) { - ERR_I(str_get_float(buf, (float *)adr)); - } else if (var->type>1) { - ERR_P(str_nget_str(buf, (char *)adr, var->type)); - } else { - ERR_MSG("unknown type"); - } - if (secure) { /* we are the server */ - (*var->flag)++; - } - return(0); - OnError: str_copy(err_name, name); ErrTxt(err_name,0); return(-1); -} - -int CocPutVar(CocVar *varList, Str_Buf *buf, const char *name, int secure) { - CocVar *var; - void *adr; - char *c; - - var=CocFindVar(varList, name, &adr); - if (var==NULL) ERR_MSG("undefined variable"); - if (adr==NULL) { - adr=var->var; - } else { - adr=(char *)adr + (int)var->var; - } - if (secure) { /* check access */ - if (var->flag==&CocRD) ERR_MSG("variable is read only"); - } - /* printf("put %s %d\n", name, (int)adr); */ - if (var->type==-1) { - ERR_I(str_put_int(buf, *(int *)adr)); - } else if (var->type==-2) { - ERR_I(str_put_float(buf, *(float *)adr)); - } else if (var->type>1) { - ERR_I(str_put_str(buf, adr)); - } else { - ERR_MSG("unknown type"); - } - if (secure) { /* we are a client */ - if (var->flag!=NULL) (*var->flag)++; - } - return(0); - OnError: str_copy(err_name, name); ErrTxt(err_name,0); return(-1); -} - -void CocFreeVarList(CocVar **varList) { - CocVar *p, *v; - - if (varList==NULL) varList=&serverVarList; - v=*varList; - while (v!=NULL) { - p=v; - v=p->next; - p->next=NULL; - FREE(p); - } - *varList=NULL; -} - void CocDelay(int msec) { struct timeval tmo; @@ -258,3 +53,59 @@ void CocDelay(int msec) { tmo.tv_usec=(msec % 1000)*1000+1; select(1,NULL,NULL,NULL,&tmo); } + +/*-------------------------------------------------------------------------*/ + +int CocSend(int fd, char *str, int size) { + int siz; + siz=htonl(size); + ERR_SI(send(fd, &siz, 4, 0)); + ERR_SI(send(fd, str, size, 0)); + return(0); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +int CocRecv(int fd, StrBuf *buf, int timeout, int *flag) { + struct timeval tmo={0,1}; + fd_set mask; + int i, l; + int siz, n; + + if (timeout>=0) { + tmo.tv_sec=timeout; + + FD_ZERO(&mask); + FD_SET(fd, &mask); + ERR_SI(i=select(fd+1,&mask,NULL,NULL,&tmo)); + if (flag!=NULL) { + *flag=0; + if (i==0) return(0); + } else { + if (i==0) { ERR_MSG("time out"); } + } + } + + n=0; + ERR_SI(i=recv(fd, &n, 4, 0)); + if (i!=4) { + ERR_COD(ECONNRESET); + } + siz=ntohl(n); + if (siz > buf->dsize) + ERR_MSG("buffer too small"); + ERR_SI(l=recv(fd, buf->buf, siz, 0)); + buf->wrpos=l; + while (buf->wrposbuf+buf->wrpos, siz, 0)); + buf->wrpos+=l; + } + StrReset(buf); + return(buf->wrpos); + OnError: return(-1); +} + diff --git a/tecs/coc_util.h b/tecs/coc_util.h index 727d45e9..04af7c18 100644 --- a/tecs/coc_util.h +++ b/tecs/coc_util.h @@ -2,7 +2,10 @@ #define _COC_UTIL_H_ #include -#include "str_buf.h" +#include "myc_buf.h" + +#define COC_CMD_LEN 256 +#define COC_RES_LEN 8192 int CocCreateSockAdr( struct sockaddr_in *sockaddrPtr, /* Socket address */ @@ -12,76 +15,34 @@ int CocCreateSockAdr( compose internet address */ -int CocRecv(int fd, Str_Buf *buf); -/* - receive data -*/ - -typedef struct { - /* private */ - void *next; - char name[32]; - void *var; - int *flag; - int type; - void *strucType; -} CocVar; - -extern int CocRD; /* readonly variable (used as argument for CocDefXXX) */ -extern int CocWR; /* read/write variable (used as argument for CocDefXXX) */ -CocVar *serverVarList; /* variable list for the server process */ - -CocVar *CocDefVar(const char *name, void *var, int type, int *flag); -void CocDefVarS(const char *name, const char *tname, void *var, int type); -/* - Define variables. Call this routines not directly, but through - one of the macros below. -*/ - -void CocVarList(CocVar **varlist); -/* - print a variable list (for debugging purposes) -*/ -void CocFreeVarList(CocVar **varList); -/* - free a variable list -*/ -CocVar *CocFindVar(CocVar *varList, const char *name, void **adr); -/* - find a variable. returns NULL if not found. -*/ -int CocPutVar(CocVar *varList, Str_Buf *buf, const char *name, int secure); -/* - put a variable named of variable list to the buffer - if , access rights are checked -*/ -int CocGetVar(CocVar *varList, Str_Buf *buf, const char *name, int secure); -/* - get a variable named of variable list from the buffer - if , access rights are checked -*/ void CocDelay(int msec); /* system independent delay function with msec resolution */ + +int CocSend(int fd, char *buf, int size); +/* + send a message +*/ + +int CocRecv(int fd, StrBuf *buf, int timeout, int *flag); +/* + receive message + if flag is NULL, a timeout generates an error + else *flag is set to zero between the select and the recv command +*/ + #define COC_INT -1 #define COC_FLT -2 #define COC_PTR -3 -#define COC_STRUCT -4 -#define COC_TYPE -5 -#define COC_ALIAS -6 -/* macros to define variables */ -#define CocDefInt(V,F) CocDefVar(#V,&V,COC_INT,&F) -#define CocDefFlt(V,F) CocDefVar(#V,&V,COC_FLT,&F) -#define CocDefStr(V,F) CocDefVar(#V,V,sizeof(V),&F) -#define CocDefPtr(V,S) CocDefVarS(#V,#S,&V,COC_PTR*(V!=(S *)NULL)); -#define CocDefStruct(V,S) CocDefVarS(#V,#S,&V,COC_STRUCT*(&V!=(S *)NULL)); -#define CocIntFld(S,V,F) CocDefVar(#S":"#V,&((S *)NULL)->V,COC_INT,&F); -#define CocFltFld(S,V,F) CocDefVar(#S":"#V,&((S *)NULL)->V,COC_FLT,&F); -#define CocStrFld(S,V,F) CocDefVar(#S":"#V,((S *)NULL)->V,sizeof(((S *)NULL)->V),&F); -#define CocDefCmd(V) CocDefVar("$",V,sizeof(V),&CocWR) -#define CocDefStrPtr(V,S,F) CocDefVar(#V,V,S,&F) -#define CocAlias(A,V) CocDefVar(#A, #V, COC_ALIAS, &CocRD); +#define COC_SEP '\0' +#define COC_DELAYED '\1' +#define COC_ERR '\2' +#define COC_TRM '\3' +#define COC_SYN0 '\4' +#define COC_SYN1 '\5' +#define COC_MAGIC '\6' +#define COC_CLRLOG '\7' #endif /* _COC_UTIL_H_ */ diff --git a/tecs/myc_buf.c b/tecs/myc_buf.c new file mode 100644 index 00000000..a5f2f901 --- /dev/null +++ b/tecs/myc_buf.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include "sys_util.h" +#include "myc_err.h" +#include "myc_str.h" +#include "myc_buf.h" + +char *StrNGet(StrBuf *buf, char *result, int reslen, int sep) { + char *b, *f, *e, quote; + int res, l, ll; + + if (buf->rdpos < 0 || buf->rdpos >= buf->dsize || buf->buf==NULL) + ERR_MSG("buffer corrupt"); + b=buf->buf + buf->rdpos; + if (*b=='"' || *b=='\'') { /* take string within quotes (single or double) */ + quote=*b; b++; + f=strchr(b, quote); + if (f==NULL) + ERR_MSG("missing '""'"); + l=f-b; + e=strchr(f+1, sep); + if (e==NULL) { + buf->rdpos = f - buf->buf + 1 + strlen(f+1); + buf->seen=0; + } else { + buf->rdpos = e - buf->buf + 1; + buf->seen=1; + } + } else { + f=strchr(b, sep); + if (f==NULL) { + l=strlen(b); + f=b+l; + buf->rdpos+=l; + buf->seen=0; + } else { + l=f-b; + buf->rdpos+=l+1; + buf->seen=1; + } + } + if (result==NULL) { + if (reslen==-1) { /* special case for StrGetBuf */ + return(f); + } + *f='\0'; + return(b); + } else { + if (l>=reslen) l=reslen-1; /* ERR_MSG("result too short"); */ + strncpy(result, b, l); + result[l]='\0'; + return(result); + } + OnError: + buf->rdpos=buf->dsize; /* illegal value */ + return(NULL); +} + +int StrGetBuf(StrBuf *buf, StrBuf *res, int sep) { + char *b, *f; + + b = buf->buf + buf->rdpos; + ERR_P(f=StrNGet(buf, NULL, -1, sep)); + res->buf = b; + res->wrpos = f-b; + res->rdpos = 0; + res->dsize = f-b; + return(0); + OnError: + buf->rdpos=buf->dsize; /* illegal value */ + return(-1); +} + +int StrGetInt(StrBuf *buf, int *res, int sep) { + char num[32]; + int i, l, p; + + p=buf->rdpos; + ERR_P(StrGet(buf, num, sep)); + i=sscanf(num, "%d%n", res, &l); + if (i==0) + ERR_MSG("illegal number"); + if (sep==StrNONE) { + buf->rdpos=p+l; + } + return(0); + OnError: + buf->rdpos=buf->dsize; /* illegal value */ + return(0); +} + +int StrGetFloat(StrBuf *buf, float *res, int sep) { + char num[32]; + int i, l, p; + + p=buf->rdpos; + ERR_P(StrGet(buf, num, sep)); + if (num[0]=='N' && num[1]=='a' && num[2]=='N') { + l=3; + *res = MYC_NAN; + } else { + i=sscanf(num, "%f%n", res, &l); + if (i==0) { + ERR_MSG("illegal number"); + } + } + if (sep==StrNONE) { + buf->rdpos=p+l; + } + return(0); + OnError: + buf->rdpos=buf->dsize; /* illegal value */ + return(-1); +} + +int StrGetEnd(StrBuf *buf) { + if (buf->buf!=NULL) { + if (buf->rdpos < 0 || buf->rdpos >= buf->dsize) + ERR_MSG("buffer corrupt"); + if (buf->rdpos != buf->wrpos) + ERR_MSG("superflous content in buffer"); + } + return(0); + OnError: + return(-1); +} + +int StrPut(StrBuf *buf, const char *str, int sep) { + int l, pos; + char quote; + + pos=buf->wrpos; + if (pos < 0 || pos >= buf->dsize || buf->buf==NULL) + ERR_MSG("buffer corrupt"); + l=strlen(str); + quote='\0'; + if (sep>0) { + if (strchr(str, sep)!=NULL) { + if (strchr(str, '"')!=NULL) { + quote='"'; l+=2; + } + if (strchr(str, '\'')!=NULL) { + if (quote!='\0') + ERR_MSG("str must not contain separator and both kind of quotes"); + quote='\''; l+=2; + } + } + } + if (pos+l >= buf->dsize) + ERR_MSG("buffer too short"); + if (quote!='\0') { + buf->buf[pos]=quote; pos++; + strcpy(buf->buf + pos, str); + buf->buf[pos]=quote; pos++; + } else { + strcpy(buf->buf + pos, str); + } + pos+=l; + if (sep!=StrNONE) { + buf->buf[pos]=sep; + pos++; + } else { + buf->buf[pos]='\0'; + } + buf->wrpos=pos; + return(0); + OnError: + buf->wrpos=-1; + return(-1); +} + +int StrPutInt(StrBuf *buf, int val, int sep) { + char num[32]; + + sprintf(num, "%d", val); + ERR_I(StrPut(buf, num, sep)); + return(0); + OnError: + return(-1); +} + +int StrPutFloat(StrBuf *buf, float val, int sep) { + char num[32]; + int l; + + if (val == MYC_NAN) { + ERR_I(StrPut(buf, "NaN", sep)); + } else { + sprintf(num, "%g", val); + ERR_I(StrPut(buf, num, sep)); + } + return(0); + OnError: + return(-1); +} + +void StrReset(StrBuf *buf) { + buf->rdpos=0; +} + +void StrClear(StrBuf *buf) { + buf->rdpos=0; + buf->wrpos=0; +} + +void StrNLink(StrBuf *buf, char *str, int length) { + int l; + buf->buf=str; + buf->rdpos=0; + l=strlen(str); + if (lwrpos=l; + buf->dsize=buf->wrpos; +} diff --git a/tecs/myc_buf.h b/tecs/myc_buf.h new file mode 100644 index 00000000..ec28b39a --- /dev/null +++ b/tecs/myc_buf.h @@ -0,0 +1,58 @@ +#ifndef _STR_BUF_H_ +#define _STR_BUF_H_ + +/* + This module is used to write and read from character strings + It is a simplified, safe replacement for sprintf/sscanf. + + DeclStrBuf(buf, size) declares and initializes a buffer of a given size. + Use this macro in the declaration part of a function. +*/ +typedef struct { char *buf; int dsize, rdpos, wrpos, seen; } StrBuf; + +#define DeclStrBuf(BUF,SIZ) static char STR__##BUF[SIZ]; StrBuf BUF={STR__##BUF,SIZ} + +/*------------------------------------------------------------------------ + Write content to the buffer, and add separator sep, if sep!=StrNONE +*/ +#define StrNONE -1 +int StrPut(StrBuf *buf, const char *str, int sep); +int StrPutInt(StrBuf *buf, int val, int sep); +int StrPutFloat(StrBuf *buf, float val, int sep); + +/*------------------------------------------------------------------------ + Read from the buffer until separator sep. + Use the StrGet macro if the result is a fixed size. + Special case sep=StrNONE: + - StrGet reads until the end of the buffer + - StrGetInt and StrGetFloat read until the end of a legal number +*/ +char *StrNGet(StrBuf *buf, char *result, int reslen, int sep); +#define StrGet(BUF,RES,SEP) StrNGet(BUF,RES,sizeof(RES),SEP) +int StrGetInt(StrBuf *buf, int *res, int sep); +int StrGetFloat(StrBuf *buf, float *res, int sep); +#define StrEnd(BUF) ((BUF)->rdpos>=(BUF)->wrpos) + +/*------------------------------------------------------------------------ + reset the buffer to read from the beginning +*/ +void StrReset(StrBuf *buf); + +/*------------------------------------------------------------------------ + Clear the buffer +*/ +void StrClear(StrBuf *buf); + +/*------------------------------------------------------------------------ + Verify that the end is reached +*/ + int StrGetEnd(StrBuf *buf); + +/*------------------------------------------------------------------------ + Link the buffer to a string. The buffer length is set to + sizeof(STR) or strlen(STR), whichever is greater +*/ +#define StrLink(BUF, STR) StrNLink(BUF, STR, sizeof(STR)) +void StrNLink(StrBuf *buf, char *str, int size); + +#endif /* _STR_BUF_H_ */ diff --git a/tecs/myc_err.c b/tecs/myc_err.c new file mode 100644 index 00000000..ec890c5a --- /dev/null +++ b/tecs/myc_err.c @@ -0,0 +1,144 @@ +#include +#include +#include + +#include "sys_util.h" +#include "myc_str.h" +#include "myc_err.h" + +#define SLEN 64 +#define MLEN 64 + +static char *txt[SLEN]; +static int sp=0; +static int stack_empty=1; + +int ErrCode; +char *ErrMessage=NULL; +void (*outrtn)()=NULL; +void *outarg; + +void ErrTxt(char *text, int systemError) +{ + if (systemError) { + sp=0; ErrCode=errno; ErrMessage=strerror(errno); + } + if (stack_empty && sp>0) { + sp=0; + stack_empty=0; + } + if (sp +#include + +/* ErrHDL Error handling utilities + ------------------------------- + Makes code more readable by hiding annoying error condition checks. + +Macros and routines: + + Spelling in uppercase indicates, that it the program flow + may be modified (jump to OnError label or program exit). + + + ERR_x + + Usage Error condition Error message taken from + ----------------------------------------------------------------------------------------- + ERR_SI(res=routine1(...)) res<0 errno + ERR_SP(ptr=routine2(...)) ptr==NULL errno + ERR_I(res=routine3(...)) res<0 stored by routine3 using errhdl mechanism + ERR_P(ptr=routine4(...)) ptr==NULL stored by routine4 using errhdl mechanism + + The result assignment "res=" or "ptr=" is optional. + + Description: + The routine routineX is called. + If the result indicates an error, the source text is saved and the + program continues at the OnError label. + The error message and the source code of the calling instructions is + saved for a later call to ErrShow or ErrExit. + + ERR_EXIT("program_name") + + Show error and exit program. + + ERR_MSG("message") + + Signals an error condition. If "message" is replaced by a variable, + take care that it is not modified until ErrShow is called. + + ERR_COD(cod) + + Signals an error condition as code from errno.h + + ErrShow("program_name") + + Show actual error message with traceback information to stdout + or a file fil + +Global Variables (read only) + + int ErrCode + + actual error message code + = errno for system errors or + = -1 for custom errors signaled by ERRMSG + + char *ErrMessage + + actual error message +*/ + +#define ERR_SI(R) { if(0>(R)) { ErrTxt(#R,1); goto OnError; }; } +#define ERR_SP(R) { if(NULL==(R)) { ErrTxt(#R,1); goto OnError; }; } +#define ERR_I(R) { if(0>(R)) { ErrTxt(#R,0); goto OnError; }; } +#define ERR_P(R) { if(NULL==(R)) { ErrTxt(#R,0); goto OnError; }; } +#define ERR_MSG(R) { ErrMsg(R); goto OnError; } +#define ERR_COD(R) { ErrCod(R); goto OnError; } + +void ErrTxt(char *text, int systemError); +void ErrMsg(char *msg); +void ErrCod(int code); +void ErrShow(char *text); /* write out error message with stack info */ +void ErrShort(char *msg); /* write out short error message */ +void ERR_EXIT(char *text); +void ErrSetOutRtn(void (*rtn)(), void *arg); +void ErrSetOutFile(FILE *file); + +extern int ErrCode; +extern char *ErrMessage; + +#endif /* _ERR_HANDLING_H_ */ diff --git a/tecs/myc_mem.h b/tecs/myc_mem.h new file mode 100644 index 00000000..c9f91b56 --- /dev/null +++ b/tecs/myc_mem.h @@ -0,0 +1,30 @@ +#ifndef _MEM_UTIL_H_ +#define _MEM_UTIL_H_ + +#include +#include + +#ifdef FORTIFY +#include "fortify.h" +#endif + +/* ------------------------------------------------------------ + these macros help for safer dynamic memory + you may change these macros if you want to log dynamic memory access + +*/ + +#define NEW(PTR,TYP) {TYP _0_={0}; ERR_SP(PTR=malloc(sizeof(*PTR))); *PTR=_0_; } +/* + allocates and initializes an object of type TYP and make PTR point to it + TYP must be defined with an appropriate typedef declaration, and + INIT(TYP) must follow the declaration to initialize a dummy initializer + object. +*/ + +#define NEW_STR(TO,FROM) {ERR_SP(TO=malloc(strlen(FROM)+1)); strcpy(TO,FROM); } + +#define MALLOC(SIZE) malloc(SIZE) +#define FREE(PTR) free(PTR) + +#endif /* _MEM_UTIL_H_ */ diff --git a/tecs/myc_str.c b/tecs/myc_str.c new file mode 100644 index 00000000..b538f432 --- /dev/null +++ b/tecs/myc_str.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include +#include +#include +#include "sys_util.h" +#include "myc_err.h" +#include "myc_str.h" +#include "myc_mem.h" + +char *str_splitx(char *str, char sep, char *list[], int *n) { + int i; + char *s, *e; + + s=str; + for (i=0; i<*n; i++) { + list[i]=s; + e=strchr(s, sep); + if (e==NULL) { *n=i+1; return(NULL); } + s=e+1; + e--; + while (e>str && *e==' ') e--; /* trim sequence */ + e[1]='\0'; + } + return(s); +} + +char *str_split1(char *str, char sep) { + char *s, *e; + + e=strchr(str, sep); + if (e==NULL) { + s=NULL; + e=str+strlen(str); + } else { + s=e+1; + } + e--; + while (e>str && *e==' ') e--; /* trim sequence */ + e[1]='\0'; + return(s); +} + +int str_ntrim(char *dest, const char *src, int ldest, int lsrc) { + int i; + + if (lsrc>=ldest) lsrc=ldest-1; + if (dest!=src) strncpy(dest, src, lsrc); + dest[lsrc]='\0'; + i=strlen(dest)-1; + while (i>=0 && dest[i]==' ') i--; /* trim sequence */ + i++; + dest[i]='\0'; + return(i); +} + +int str_npad(char *dest, const char *src, int ldest) { + int i, lsrc; + + lsrc=strlen(src); + if (lsrc>=ldest) { + if (dest!=src) strncpy(dest, src, ldest); + lsrc=ldest; + } else { + if (dest!=src) strcpy(dest, src); + for (i=lsrc; i=dstlen) { + str_copy(dst, src); + } else { + strncpy(dst, src, i); + dst[i]='\0'; + } + return(s); +} + +char *str_read_until(FILE *fil, char *term, char *buf, char *end) { + char *s; + char fmt[24]; + int i, l, siz; + char ch; + + siz=end-buf-1; + if (siz<1) return(NULL); + sprintf(fmt, "%s%d[^%s%s", "%", siz, term, "]%n%c"); + i=fscanf(fil, fmt, buf, &l, &ch); + if (i<0) { /* eof */ + buf[0]='\0'; + return(&buf[0]); + } else if (i==0) { /* fscanf returns 0 if first char is terminator */ + buf[0]=fgetc(fil); + return(&buf[0]); + } else if (i==1) { /* terminator not found -> read until eof */ + buf[l]='\0'; + return(&buf[l]); + } else { + buf[l]=ch; + if (l==siz && NULL==strchr(term, ch)) return(NULL); + return(&buf[l]); + } +} + +char *str_read_file(char *file) { + FILE *fil; + char *str, *s, *e, *p, *q; + char ch; + int i, l, size; + struct stat statbuf; + + i=stat(file, &statbuf); + if (i<0) ERR_MSG("file not found"); + size=statbuf.st_size+4; + ERR_SP(str=MALLOC(size)); + e=&str[size-1]; + ERR_SP(fil=fopen(file, "r")); + s=str; + while (1) { + p=str_read_until(fil, "!", s, e); + if (p==NULL) break; + if (*p=='!') { + q=str_read_until(fil, "\n", p, e); + if (q==NULL) { p=NULL; break; } + s=p; *s='\n'; s++; + } else { + assert(*p=='\0'); + break; + } + } + ERR_SI(fclose(fil)); + assert(strlen(str)reslen) ERR_MSG("result buffer too short"); + strncpy(r, p, l); + r+=l; reslen-=l; + if (ln>reslen) ERR_MSG("result buffer too short"); + strncpy(r, new, reslen); + r+=ln; reslen-=ln; + p=s+lo; + s=strstr(p, old); + } + l=strlen(p); + if (l>reslen) ERR_MSG("result buffer too short"); + strncpy(r, p, l); + r+=l; + *r='\0'; + return(r-result); + OnError: + result[0]='\0'; + return(-1); +} + +void str_nupcase(char *dst, const char *src, int dstlen) { + dstlen--; /* space for trailing nul */ + while (*src!='\0' && dstlen>0) { + *dst=toupper(*src); + dst++; src++; + dstlen--; + } + *dst='\0'; +} + +void str_nlowcase(char *dst, const char *src, int dstlen) { + dstlen--; /* space for trailing nul */ + while (*src!='\0' && dstlen>0) { + *dst=tolower(*src); + dst++; src++; + dstlen--; + } + *dst='\0'; +} + +int strcasecmp(const char *str1, const char *str2) { + int i; + char ch1, ch2; + ch1=tolower(*(str1++)); ch2=tolower(*(str2++)); + i=1; + while (ch1!='\0' && ch2!='\0' && ch1==ch2) { + ch1=tolower(*(str1++)); ch2=tolower(*(str2++)); i++; + } + if (ch1ch2) { + return(i); + } + return(0); +} + +int str_ncpy(char *dst, const char *src, int maxdest) { + strncpy(dst, src, maxdest); + if (dst[maxdest-1]!='\0') { + dst[maxdest-1]='\0'; + ERR_MSG("destination string too short"); + } + return(0); + OnError: return(-1); +} + +int str_ncat(char *dst, const char *src, int maxdest) { + strncat(dst, src, maxdest-strlen(dst)-1); + if (dst[maxdest-1]!='\0') { + dst[maxdest-1]='\0'; + ERR_MSG("destination string too short"); + } + return(0); + OnError: return(-1); +} diff --git a/tecs/myc_str.h b/tecs/myc_str.h new file mode 100644 index 00000000..95bdbfaf --- /dev/null +++ b/tecs/myc_str.h @@ -0,0 +1,122 @@ +#ifndef _MYC_STR_H_ +#define _MYC_STR_H_ + +#define MYC_NAN (-1.125/1024./1024./1024.) + +/* + use these macros if DST is a fixed length character array +*/ + +#define str_trim(DST,SRC,L) str_ntrim(DST,SRC,sizeof(DST),L) +#define str_pad(DST,SRC) str_npad(DST,SRC,sizeof(DST)) +#define str_split(DST,SRC,SEP) str_nsplit(DST,SRC,SEP,sizeof(DST)) +#define str_substitute(DST,SRC,OLD,NEW) str_nsubstitute(DST,SRC,OLD,NEW,sizeof(DST)) +#define str_upcase(DST,SRC) str_nupcase(DST,SRC,sizeof(DST)) +#define str_lowcase(DST,SRC) str_nlowcase(DST,SRC,sizeof(DST)) +#define str_copy(DST,SRC) str_ncpy(DST,SRC,sizeof(DST)) +#define str_append(DST,SRC) str_ncat(DST,SRC,sizeof(DST)) + + +char *str_split1(char *str, char separator); +/* + trims text before separator in *str and returns + a pointer to the first character after separator +*/ + +char *str_splitx(char *str, char sep, char *list[], int *n); +/* + split string into *n strings using separator sep. + spaces at the end of the elements are trimmed + attention: *str is modified ('\0' placed at the end of the elements) + + if *n separators are found, result points to string after *n-th separator + else result is NULL + *n contains number of elements stored in list +*/ + +int str_ntrim(char *dest, const char *src, int ldest, int lsrc); +/* + copy characters 0 to lsrc-1 from src to dest (max ldest chars). +*/ + +int str_npad(char *dest, const char *src, int ldest); +/* + copy src to dest and fill with spaces (fortran string format) +*/ + +char *str_nsplit(char *dst, const char *src, char sep, int dstlen); +/* + returns a pointer to the text after the separator sep in *src + and copies the text before the separator to *dst + when *src does not contain the separator sep + NULL is returned, and *dst is a copy of *src +*/ + +char *str_read_file(char *file); +/* + return one string containing the contents of file *file + comments separated by '!' are omitted. The caller must + free the result after use. +*/ + +void str_replace_char(char *str, char ch, char rep); +/* + replace all occurences of character ch by character rep in string *str +*/ + +int str_nsubstitute(char *result, char *str, char *old, char *new, int reslen); +/* + replace every instance of old in str by new. + the result must not overlap + if the result would be longer than reslen, the result is en empty string + and the return value is -1; + else the return value is the length of the result. + return one string containing the contents of file *file + the contents are treated in the following way: + - #0,#1,...#n is replaced by the corresponding argument *args[n] (n=0..nargs-1, nargs<10) + - at the end of each line spaces and comments separated by ! are trimmed +*/ + +void str_nupcase(char *dst, const char *src, int dstlen); +/* + convert *str to uppercase +*/ + +void str_nlowcase(char *dst, const char *src, int dstlen); +/* + convert *str to lowercase +*/ + +#ifdef __VMS_VER +#if __VMS_VER<70000000 + +int strcasecmp(const char *str1, const char *str2); +/* + compare *str1 with *str2 + the comparison is not case sensitive + if result=0: strings are equal + else + result>0 <==> *str1>*str2 + first different character is at position abs(result)-1 +*/ + +#else +#include +#endif /* __VMS_VER<70000000 */ +#else +#include +#endif /* __VMS_VER */ + +int str_ncpy(char *dst, const char *src, int maxdest); +/* + copy *src to *dest, maximal maxdest characters, + it is guaranteed, that dst contains '\0' +*/ + +int str_ncat(char *dst, const char *src, int maxdest); +/* + append *src to *dest, maximal maxdest characters, + it is guaranteed, that dst contains '\0' +*/ + +#endif /* _MYC_STR_H_ */ diff --git a/tecs/myc_time.c b/tecs/myc_time.c new file mode 100644 index 00000000..d959a98a --- /dev/null +++ b/tecs/myc_time.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include "sys_util.h" +#include "myc_time.h" + +int ftime (struct timeb *__timeptr); /* for some reason not defined in timeb.h with flag -std1 */ + +static time_t my_base=0; + +void initBase(void) { + struct tm tim; + time_t now; + + time(&now); + tim = *localtime(&now); + tim.tm_year = MYC_TIME_BASE / 10000 - 1900; + tim.tm_mon = (MYC_TIME_BASE % 10000) / 100 - 1; + tim.tm_mday = MYC_TIME_BASE % 100; + tim.tm_hour = 12; + tim.tm_min = 0; + tim.tm_sec = 0; +/* take daylight saving time flag and gmt offset from today */ + my_base=mktime(&tim) - 12*3600; + assert(tim.tm_wday == 1); /* time base must be a monday */ +} + +int mycNow(void) { + time_t now; + + if (my_base == 0) initBase(); + time(&now); + return (int)(now-my_base); +} + +int mycMsecSince(int since) { + struct timeb now; + int msec; + + if (my_base == 0) initBase(); + ftime(&now); + msec = (now.time - my_base) % (24*3600) * 1000 + now.millitm - since; + if (msec < 0) msec+=24*3600000; + return msec; +} + +int mycDate(int time) { + struct tm tim; + time_t t; + + if (my_base == 0) initBase(); + t = time + my_base; + tim=*localtime(&t); + return (tim.tm_year + 1900) * 10000 + (tim.tm_mon + 1) * 100 + tim.tm_mday; +} + +int mycTime(int date) { + struct tm tim; + time_t t, now; + int y, m, d; + + if (my_base == 0) initBase(); + time(&now); + tim=*localtime(&now); + tim.tm_hour=0; + tim.tm_min=0; + tim.tm_sec=0; + if (date != 0) { + d = date % 100; + date = date / 100; + m = date % 100; + y = date / 100; + if (y == 0) { + if (m == 0) { + if (d > tim.tm_mday) { + if (tim.tm_mon == 0) { /* jan */ + tim.tm_mon=11; /* dec */ + tim.tm_year--; + } else { + tim.tm_mon--; /* last month */ + } + } + } else { + tim.tm_mon = m - 1; + } + } else { + tim.tm_year = y - 1900; + if (m == 0) { + if (d == 0) { + tim.tm_mon = 0; + } + } else { + tim.tm_mon = m - 1; + } + } + if (d == 0) d = 1; + tim.tm_mday = d; + } + return (int)(mktime(&tim)-my_base); +} + + +/* fortran routines -------------------------------------------------- +*/ + +#ifdef F_CHAR +/* compile only when fortran c interface stuff is defined */ + + +#ifdef __VMS +#define myc_date_ myc_date +#define myc_time_ myc_time +#define myc_now_ myc_now +#endif + +int myc_now_(void) { return mycNow(); } +int myc_date_(int *time) { return mycDate(*time); } +int myc_time_(int *date) { return mycTime(*date); } + +#endif diff --git a/tecs/myc_time.h b/tecs/myc_time.h new file mode 100644 index 00000000..80142b78 --- /dev/null +++ b/tecs/myc_time.h @@ -0,0 +1,42 @@ +#ifndef _MYC_TIME_H_ +#define _MYC_TIME_H_ + +#define MYC_TIME_BASE 20010101 + +int mycNow(void); +/* + return seconds since a Monday specified by MYC_TIME_BASE + mycNow() % (24*3600) is always 0 at 00:00 even in daylight saving time +*/ + +int mycMsecSince(int since); +/* + mycMsecSince(0) return milliseconds since midnight + mycMsecSince(x) return milliseconds since x (x is time since midnight) +*/ + +int mycDate(int time); +/* + return year * 10000 + month * 100 + day_of_month of a time obtained by mycNow + year > 1900 + 1 <= month <= 12 + 1 <= day_of_month <= 31 +*/ + +int mycTime(int date); +/* + does the inverse of MycDate. Chooses the last possible date not later than today +*/ + +/* the following subroutines are to be called from FORTRAN + +integer function myc_now() +real function myc_date(time) +integer function myc_time(date) + +integer time +real date + +*/ + +#endif /* _MYC_TIME_H_ */ diff --git a/tecs/str.f b/tecs/str.f new file mode 100644 index 00000000..5bd82c10 --- /dev/null +++ b/tecs/str.f @@ -0,0 +1,131 @@ +!! string handling +!! + subroutine STR_TRIM(RETSTR, STR, RETLEN) !! +!! +!! if RETSTR=STR then RETSTR is not touched +!! +!! Arguments: + character*(*) STR, RETSTR !! in,out + integer RETLEN !! out + integer i + + i=len(str) + if (str(1:1) .gt. ' ') then +10 if (str(i:i) .le. ' ') then + i=i-1 + goto 10 + endif + else +20 if (str(i:i) .le. ' ') then + if (i .gt. 1) then + i=i-1 + goto 20 + endif + endif + endif + retlen=min(len(retstr),i) + if (retstr .ne. str) then ! avoid copy to retstr if equal + retstr=str(1:i) + endif + end + +!! + subroutine STR_UPCASE(RETSTR, STR) !! +!! +!! Arguments: + character STR*(*), RETSTR*(*) !! in,out + integer i, ch + + retstr=str + do i=1,len(retstr) + ch=ichar(retstr(i:i)) + if (ch .ge. ichar('a') .and. ch .le. ichar('z')) then + retstr(i:i)=char(ch-(ichar('a')-ichar('A'))) + endif + enddo + end + +!! + subroutine STR_LOWCASE(RETSTR, STR) !! +!! +!! Arguments: + character STR*(*), RETSTR*(*) !! in,out + integer i, ch + + retstr=str + do i=1,len(retstr) + ch=ichar(retstr(i:i)) + if (ch .ge. ichar('A') .and. ch .le. ichar('Z')) then + retstr(i:i)=char(ch+(ichar('a')-ichar('A'))) + endif + enddo + end + +!! + subroutine STR_APPEND(str, length, add) !! +!! + implicit none + + character*(*) str, add !! + integer length !! + + if (len(add)+length .gt. len(str)) then + if (length .lt. len(str)) then + str(length+1:)=add + length=len(str) + endif + else + str(length+1:length+len(add))=add + length=length+len(add) + endif + end + +!! + integer function STR_CMP(str1, str2) !! +!! +!! if strings are equal: return 0 +!! else return position of first different character + + character str1*(*), str2*(*) !! + + integer i + + do i=0,min(len(str1),len(str2))-1 + if (str1(i+1:i+1) .ne. str2(i+1:i+1)) then + str_cmp=i+1 + return + endif + enddo + do i=len(str1),len(str2)-1 + if (str2(i+1:i+1) .ne. ' ') then + str_cmp=i+1 + return + endif + enddo + do i=len(str2),len(str1)-1 + if (str1(i+1:i+1) .ne. ' ') then + str_cmp=i+1 + return + endif + enddo + str_cmp=0 + return + end + +!! + subroutine STR_FIRST_NONBLANK(STR, POS) !! +!! +!! Arguments: + character*(*) STR !! in + integer POS !! out + integer i + + do i=1,len(str) + if (str(i:i) .gt. ' ') then + pos=i + return + endif + enddo + pos=0 + end + diff --git a/tecs/sys_aunix.f b/tecs/sys_aunix.f index f26bb820..ca4cea7e 100644 --- a/tecs/sys_aunix.f +++ b/tecs/sys_aunix.f @@ -292,7 +292,7 @@ integer L !! integer i - integer lnblnk + integer lnblnk, iargc l=0 str=' ' diff --git a/tecs/sys_aunix_c.c b/tecs/sys_aunix_c.c index 4b69f695..6f8d656a 100644 --- a/tecs/sys_aunix_c.c +++ b/tecs/sys_aunix_c.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -18,16 +18,13 @@ int usleep(time_t delay); void sys_rd_line_(char *cmd, int *retlen, char *prompt, int clen, int plen) { - char *line_read, *p; - int l; - - l = lnblnk_(prompt, clen); - p = malloc((unsigned) l+2); if( p == NULL ) return; - strncpy(p+1,prompt,l); p[0]='\n'; p[l] = '\0'; + char *line_read, p[64]; + + assert(plen < sizeof(p)); + strncpy(p,prompt,plen); p[plen] = '\0'; if (last_line == NULL) { last_line =malloc(1); last_line[0] = '\0';}; line_read = readline(p); - free(p); if (line_read) { @@ -156,10 +153,10 @@ int ilen1, ilen2; return(rc); } -struct termios atts; void sys_rd_tmo_(char *prompt, char *result, int *reslen, int p_len, int r_len) { + struct termios atts; struct termios attr; int ires, i, ntmo, chr; diff --git a/tecs/sys_util.c b/tecs/sys_util.c index 11f48afb..1b684461 100644 --- a/tecs/sys_util.c +++ b/tecs/sys_util.c @@ -1,5 +1,6 @@ +#include #include -#include "str_util.h" +#include "myc_str.h" #include "sys_util.h" #if __VMS @@ -16,10 +17,17 @@ int sys_gmt_off() { return(0); } +void sys_ctrl_init(void) { + static int init=1; + if (init) { + init=0; + DECC$CRTL_INIT(); + } +} + #else #include -#include int sys_remove_file_(F_CHAR(file), int file_len) { char buf[128]; @@ -27,12 +35,4 @@ int sys_remove_file_(F_CHAR(file), int file_len) { return(unlink(buf)); } -int sys_gmt_off_() { - struct tm *timp; - time_t tim; - time(&tim); - timp=localtime(&tim); - return(timp->tm_gmtoff); -} - #endif diff --git a/tecs/sys_util.h b/tecs/sys_util.h index 9e1394b2..f7a40085 100644 --- a/tecs/sys_util.h +++ b/tecs/sys_util.h @@ -1,33 +1,35 @@ #ifndef _SYS_UTIL_H_ #define _SYS_UTIL_H_ -#ifdef FORTIFY -#include "fortify.h" -#endif +/* -/* secure allocation stuff ---------------------------------- - change these macros if you want to log dynamic memory access -*/ + fortran interface stuff -#define NEW(PTR) ERR_SP(PTR=calloc(1,sizeof(*PTR))) -#define MALLOC(SIZ) calloc(1,SIZ) -#define FREE(PTR) free(PTR) + declare fortran character arguments as F_CHAR(arg) + and at at the end for each character argument add + int _len to the argument list -/* fortran interface stuff ---------------------------------- + Use macros STR_TO_C and STR_TO_F to convert from Fortran character strings + to C character arrays and vice versa. - declare fortran character arguments as CHAR(arg) - and at at the end for each character argument add - int _len to the argument list + sys_adr_len (argument of accept and gethostbyadr, system dependent) + + sys_ctrl_init() (needed in VMS only) */ + #if defined __VMS +typedef struct { short size, dummy; char *text; } SysVmsChar; + #define F_CHAR(VAR) SysVmsChar *VAR##_desc #define STR_TO_C(DST,SRC) str_ntrim(DST, SRC##_desc->text, sizeof(DST), SRC##_len=SRC##_desc->size) #define STR_TO_F(DST,SRC) str_npad(DST##_desc->text, SRC, DST##_len=DST##_desc->size) -typedef struct { short size, dummy; char *text; } SysVmsChar; +typedef size_t sys_adr_len; /* argument of accept and gethostbyadr */ + +void sys_ctrl_init(void); #elif defined __alpha @@ -35,9 +37,13 @@ typedef struct { short size, dummy; char *text; } SysVmsChar; #define STR_TO_C(DST,SRC) str_ntrim(DST, SRC, sizeof(DST), SRC##_len) #define STR_TO_F(DST,SRC) str_npad(DST, SRC, DST##_len) +typedef int sys_adr_len; /* argument of accept and gethostbyadr */ + +#define sys_ctrl_init(DUMMY) + #else -/* other machines are not yet supported */ +/* other machines are not supported */ #endif diff --git a/tecs/tecs.c b/tecs/tecs.c index 611e00f3..d4d210e3 100644 --- a/tecs/tecs.c +++ b/tecs/tecs.c @@ -2,23 +2,26 @@ #include #include #include -#include -#include +#include #include #include -#include "sys_util.h" -#include "err_handling.h" +#include "myc_mem.h" +#include "myc_err.h" +#include "coc_util.h" #include "coc_server.h" #include "coc_logfile.h" -#include "str_util.h" +#include "myc_str.h" +#include "myc_time.h" #include "tecs_lsc.h" -#include "tecs_dlog.h" +#include "tecs_data.h" -int ftime (struct timeb *__timeptr); /* for some reason not defined in timeb.h with flag -std1 */ +/* --- non ANSI signal --- */ +#ifndef SIGPIPE +#define SIGPIPE 13 +#endif -#define TABLE_FILE "tecs.tab" -#define Progress(I) if (configuring) { configuring+=I; } -#define undef -65535. +#define TABLE_FILE "tecs.cfg" +#define LOGLIFETIME 24*3600 static SerChannel *ser=NULL; static char *serverId=NULL; @@ -26,65 +29,83 @@ static char *binDir=NULL; static char *logDir=NULL; typedef struct { - float t, t1, t2, min, max, band; /* temperatures */ + char ch[4]; + float t, t0, t1, t2, min, max, band; /* temperatures */ + float scale; /* scale for extreme ranges */ + float lim; /* range limit (used when two sensors present) */ int stat1, stat2; /* reading status summary */ - int present; /* sensor is present */ + int present; /* 0: sensor inactive, 1: sensor configured, -1: sensor parameters read */ int readStat; /* reading status */ - char ch[2]; /* channels */ + char type; } SensorT; -SensorT - sens1, sens2, sens3, sens4, - *sensors[5]={NULL, &sens1, &sens2, &sens3, &sens4 }, - *sensor=&sens1; +static SensorT + sensA={"A"}, + sensB={"B"}, + sensC={"C"}, + sensD={"D"}, + *sensors[4]={&sensA, &sensB, &sensC, &sensD }, + *ctlSens=NULL, /* control sensor */ + *heliumSens=NULL, + *auxSens=NULL, + *sens=&sensA; 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]; + float t1, t2; /* minimum and maximum temperatures since ... */ } 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 */ +static Testpoint /* C standard guarantees initialization to zero */ + cryo, /* = {&sensA, &sensB }, /* data for heat exchanger, or the only sensors */ + samp, /* = {&sensC, &sensD }, /* data for sensors on sample stick */ *tpoints[2]={&cryo, &samp}, *tpoint=&cryo; +typedef struct _Plug { + SensorT *sensor1, *sensor2; + int manual; /* manual device */ + 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 */ +} 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 - tempC, /* set T (for sample) */ - tempH, /* set T on heat exchanger */ - htr, /* heater current percentage */ + set, /* set T */ + setH, /* set T on heat exchanger */ + htr, power=DATA_UNDEF, /* heater current percentage, heater power */ 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 */ + tm=DATA_UNDEF, /* main temperature */ + ts=DATA_UNDEF, /* sample temperature */ + tr=DATA_UNDEF, /* set temperature (read back) */ + he=DATA_UNDEF, /* helium level value */ + aux=DATA_UNDEF, /* auxiliary value */ + ramp=0, + slope=0, fbuf, /* float buffer */ + r1, r2, /* temporary values */ 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 */ + settingsFlag, /* settings to be done */ 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 */ @@ -92,39 +113,37 @@ static int 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 */ + loop=1, /* active loop */ + touched, /* user touched keys */ + tim0, /* msec Time */ + per, /* effective period */ mmInt, mmTime, /* interval and time for next min-max logging */ tableTime; /* last time when table was read */ +int tim, rdTim; /* actual time, read Time */ + static int decod[8]={21,20,17,16,5,4,1,0}; /* for code conversion */ static char - status[160], /* status buffer */ + statusBuf[132], /* phase status */ + status[1000], /* status 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[2], /* actual channel */ alarms[20], /* alarm status */ + alarmChannels[4]=" ", alarmList[4], /* alarm list */ - chanS[4], chanM[4], /* channels in input routine */ helium[80], /* helium level status */ - dlogfile[128], + /* send[256], */ controlChannel[2]="A"; static char @@ -132,72 +151,92 @@ static char *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", - }; +static int logMask; -struct timeb tim0; -int logMask; +typedef struct { + char cmd[COC_CMD_LEN]; + int logstart; + long int logpos; + char logline[COC_RES_LEN]; + char pltdata[COC_RES_LEN]; +} ClientData; -void idleHdl(int tmo, int fd) { +/* +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 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); +void *SetClientData(void *data) { + ClientData *cl; + if (data==NULL) { + NEW(cl, ClientData); + return cl; } - if (cryo.manual) { + 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.manual)) { + str_append(device, "/"); + str_append(device, plug1.device); + } + if (plug0.manual) { str_append(device, " (manual"); } else { str_append(device, " (auto"); } - if (samp.manual==cryo.manual) { + if (plug1.manual==plug0.manual) { str_append(device, ")"); - } else if (samp.manual) { + } else if (plug1.manual) { str_append(device, "/manual)"); } else { str_append(device, "/auto)"); } } -int putPermanentData(FILE *fil) { +int PutPermanentData(FILE *fil) { char buf[256]; char *d1, *d2; - if (cryo.manual) { + if (plug0.manual) { d1="*"; } else { d1=""; } - if (samp.manual) { + if (plug1.manual) { d2="*"; } else { d2=""; } - sprintf(buf, "%s%s/%s%s/%d/%d\n", d1, cryo.device, d2, samp.device, cryo.code, samp.code); + 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 instCurve(char *nam, char *channel, int dispFld) { +int InstalCurve(SensorT *sensor, char *dev) { /* - install sensor nam on channel + install sensor */ - char buf[256], chead[64], nbuf[256], lbuf[16]; + 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 */ @@ -205,19 +244,35 @@ int instCurve(char *nam, char *channel, int dispFld) { int i, n, c1, c2; char used[60]; FILE *fil; - int retstat; + + sens=sensor; + str_copy(chan, sens->ch); + sens->present=0; + if (sens->type=='x' || sens->type=='h') { + if (chan[0]>='C') { + ERR_P(LscCmd(ser, "INTYPE [chan]:0,1,2,1,13;MNMX [chan]:1,3")); /* 7.5 V Range */ + } else { + ERR_P(LscCmd(ser, "INTYPE [chan]:0,1,2,1,12;MNMX [chan]:1,3")); /* 5 V Range */ + } + if (sens->type=='h') { + /* helium */ + } + if (settingsFlag==0) sens->present=1; + return(0); + } fil=NULL; crv=NULL; e=NULL; - str_copy(chan, channel); - logfileOut(LOG_MAIN, "install curve %s\n", nam); + sprintf(nam, "%s_%c", dev, sens->type); + logfileOut(LOG_MAIN+LOG_STAT, "install curve %s\n", nam); /* read curve file */ str_copy(nbuf, binDir); str_append(nbuf, nam); - retstat=-2; /* an error would be severe */ + str_append(nbuf, ".crv"); + ERR_P(crv=str_read_file(nbuf)); t=str_split(chead, crv, '\n'); @@ -237,9 +292,8 @@ int instCurve(char *nam, char *channel, int dispFld) { 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, ":"); @@ -260,7 +314,9 @@ int instCurve(char *nam, char *channel, int dispFld) { if (entry !=NULL) entry++; } if (n>0) { - for (num=60;num>20;num--) { if (used[num]==0) break; } + for (num=60;num>20;num--) { + if (used[num]==0) break; + } s=NULL; e=NULL; } else { @@ -277,40 +333,32 @@ int instCurve(char *nam, char *channel, int dispFld) { 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); + ERR_P(LscCmd(ser, "INTYPE?[chan]>buf1;INCRV?[chan]>buf2")); + if (!LscEqPar(buf1, intype) || atoi(buf2)!=num) { + ERR_P(LscCmd(ser, "ANALOG 2:0,3")); + 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 */ - 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); + logfileOut(LOG_MAIN+LOG_STAT, "download curve %d\n", num); + /* select sensor type first */ + ERR_P(LscCmd(ser, "ANALOG 2:0,3")); + ERR_P(LscCmd(ser, "RANGE:0;INTYPE [chan]:[intype]")); n=3; do { @@ -321,6 +369,12 @@ int instCurve(char *nam, char *channel, int dispFld) { } 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 */ @@ -329,41 +383,42 @@ int instCurve(char *nam, char *channel, int dispFld) { 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); + if (i%10==0) sprintf(statusBuf, "downloading curve at line %d", i); } 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); + ERR_P(LscCmd(ser, "CRVHDR [num]:[head];INCRV [chan]:[num];MNMX [chan]:1,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 */ + if (sens->scale!=1.0) + ERR_P(LscCmd(ser, "LINEAR [chan]:1,[sens.scale],1,1,0")); /* scaling for display */ + + if (settingsFlag==0) sens->present=1; + /* + 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+"); + str_append(nbuf, "lsc.tmp"); + fil=fopen(nbuf, "w+"); if (fil==NULL) ERR_SP(fil=fopen(nbuf, "w")); - ERR_I(putPermanentData(fil)); + 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)); + if (num>20) { + ERR_SI(fputs("\n", fil)); + } ERR_SI(fputs(start, fil)); } if (e!=NULL) { /* write content after replaced entry */ @@ -372,33 +427,37 @@ int instCurve(char *nam, char *channel, int dispFld) { } 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 */ + logfileOut(LOG_MAIN, buf); fil=NULL; FREE(cache); /* re-read it */ - ERR_P(cache=str_read_file(nbuf)); + 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(retstat); + return(-1); } -int configInput(void) { +int PrepInput(char *label) { 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; + char buf[80], nam[16], chans[8], nbuf[256], typ; + int i, j, l; + StrBuf sbuf; + SensorT *s; - 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); @@ -406,32 +465,38 @@ int configInput(void) { ERR_P(table=str_read_file(nbuf)); tableTime=tim; } - t=strstr(table, buf); + 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 (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; + if (plug==&plug0) { + sensA.present=0; + sensB.present=0; + sensA.scale=1; + sensB.scale=1; + sensA.lim=0; + sensB.lim=0; controlMode=0; - heliumMode=0; + } else { + sensC.present=0; + sensD.present=0; + sensC.scale=1; + sensD.scale=1; + sensC.lim=0; + sensD.lim=0; } - chanS[0]='\0'; - chanM[0]='\0'; + loop=1; + resist=10; 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, "%4s%n", chans, &l); + if (i<1) ERR_MSG("missing chans"); + t+=l; /* interprete settings until '+' appeares */ i=sscanf(t, "%64s%n", buf, &l); @@ -440,70 +505,39 @@ int configInput(void) { 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)); + StrLink(&sbuf, e+1); + ERR_I(CocGetVar(buf, &sbuf, ' ')); 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); + if (loop!=2) loop=1; + if (strlen(chans)>4) ERR_MSG("no more than 4 channels allowed"); + + j=0; + if (plug==&plug1) j=2; + + for (i=j; ipresent=-1; } + s->type=typ; + s->band=10; + if (s->scale==0.0) s->scale=1.0; } - 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; + if (!plug->manual) { /* set device name */ + str_copy(plug->device, nam); + ConcatDevice(); } return(0); - OnError: return(retstat); + OnError: return(-1); } -int loadCache(void) { +int LoadCache(void) { int i, j, k; char *res; char buf[256], nbuf[256], lbuf[16]; @@ -515,19 +549,18 @@ int loadCache(void) { str_copy(nbuf, logDir); str_append(nbuf, lbuf); ERR_SP(fil=fopen(nbuf, "w")); - ERR_I(putPermanentData(fil)); + 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 */ + 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)); @@ -543,12 +576,19 @@ int loadCache(void) { return(-1); } -float WeightedAverage(float tH, float tL) { - float p,q; +float WeightedAverage(float tH, float tL, Testpoint *t) { + float p,q, tLow, tHigh; + SensorT *s1, *s2; + s1=t->sensor1; + s2=t->sensor2; + tH = tH * s1->scale; + tL = tL * s2->scale; if (tH!=0.0) { if (tL!=0.0) { - if (tLlim; + tHigh=s2->lim; + if (tL<=tLow) { return(tL); } else if (tHsensor1; - 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); + 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; + } + + sprintf(buf, "@Tm %.5g _ %.5g", cryo.t1, cryo.t2); + if (cryo.sensor1!=samp.sensor1) { + sprintf(buf1, " Ts %.5g _ %.5g", samp.t1, samp.t2); str_append(buf, buf1); } - logfileOut(LOG_MAIN, "%s\n", buf); + if (tr!=DATA_UNDEF) { + sprintf(buf1, " Tr %.5g", tr); + 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; + } } - 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; + char buf[256], typ, *err; + int i, doit, stat; + int tfill, dfill; + float hlev; + SensorT *s; 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); + doit=0; + for (i=0; i<4; i++) { + s=sensors[i]; + s->stat1=0; + s->stat2=0; + if (s->present) { + if (s->type=='h' || s->type=='x') { + typ='S'; + } else { + typ='K'; + } + if (doit) ERR_P(LscCmd(ser, buf)); + str_substitute(buf + , "KRDG?#>sens#.t0;MDAT?#>sens#.t1,sens#.t2;MDATST?#>sens#.stat1,sens#.stat2" + , "#", s->ch); + buf[0]=typ; /* change KRDG to SRDG */ + doit=1; } } - if (ls>0) { - buf[l-1]='\0'; /* strip off ';' */ + if (doit) { + if (ramp!=0) { + str_append(buf, ";SETP?[loop]>tr"); + } else { + tr=set; + if (tr==0) tr=DATA_UNDEF; + } + str_append(buf, ";MNMXRST"); 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); + for (i=0; i<4; i++) { + s=sensors[i]; + if (s->present) { + + if (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-2); /* ignore "old reading" */ + if (stat != s->readStat) { + s->readStat=stat; + 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); + } } 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 (s->type=='h') { + hlev = s->t1; /* take minimum only */ + if (full>0) { + if (hlev0) { + he=hlev*100.0/full; + s->t=he; + tfill = tim % (24*3600) / 60; /* min since midnight */ + dfill = mycDate(tim) % 10000; /* fill date without year */ + sprintf(helium, "%5.1f %% (%02d.%02d., %02d:%02d)", he + , 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 (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; + 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; } } else { - sensor->t=0; + s->t=0; } } else { - sensor->t=0; + s->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; + 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==0.0) { + samp.temp=cryo.temp; + } + } + if (auxSens != NULL) { + aux=auxSens->t * auxSens->scale; + } else { + aux=DATA_UNDEF; + } + if (heliumSens == NULL) { + he=DATA_UNDEF; } return(0); OnError: return(-1); } -int SetTemp(int switchOn) { - char *ch; - float scale; +int ReadHeater(void) { + if (loop==1) { + ERR_P(LscCmd(ser, "HTR?>htr;HTRST?>htrst;RELAYST?1>relay")); + } else { + ERR_P(LscCmd(ser, "AOUT?2>htr")); + htrst=0; + } + if (set == 0) { + power=DATA_UNDEF; + } else { + power=htr*htr*maxPower*1e-4; + } + return 0; + OnError: return(-1); +} - if (tempC>tLimit) { - tempC=tLimit; - logfileOut(LOG_MAIN, "set point too high, reset to %f\n", tempC); +int SetTemp(int switchOn) { + int showSet; + + 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(1); + LogMinMax(switchOn); } - 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; + if (cryo.sensor1==NULL) return(0); + if (ctlSens==NULL) ctlSens=cryo.sensor1; + if (controlMode==1) { + tShift=0; + 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; } } 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 (controlMode!=2) tShift=0; + 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; + } } + str_copy(chan, ctlSens->ch); 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; + setH=(set+tShift)/ctlSens->scale; + if (setH>tLimit) setH=tLimit; + 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 (set==0) { + ERR_P(LscCmd(ser, "CSET [loop]:[chan],1,1,0")); + if (loop==1) { + ERR_P(LscCmd(ser, "RANGE:0")); + } else { + ERR_P(LscCmd(ser, "ANALOG 2:0,0")); + } + setH=0; + } else if (remoteMode==1) { + /* in local mode: do not switch on heater */ } 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; + ERR_P(LscCmd(ser, "CSET [loop]:[chan],1,1,0")); + if (loop==1) { + ERR_P(LscCmd(ser, "RANGE:[iRange]")); + } else { + ERR_P(LscCmd(ser, "ANALOG 2:0,3")); } } else { - ERR_P(LscCmd(ser, "CSET 1:[chan],1")); + ERR_P(LscCmd(ser, "CSET [loop]:[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); + showSet=(0!=strcmp(ctlSens->ch, controlChannel) || switchOn); + if (ramp==0) { + ERR_P(LscCmd(ser, "RAMP [loop],0,0;SETP?[loop]>fbuf")); + if (fabsf(setH-fbuf) >= (fbuf+setH)*1.0e-5) { + ERR_P(LscCmd(ser, "SETP [loop]:[setH]")); + if (controlMode!=2 && !showSet) { + logfileOut(LOG_MAIN, "set %g (on %s) (was changed)\n", set, ctlSens->ch); + } + } else { + setH=fbuf; } + } else { + if (ramp < 0) ramp=-ramp; + if (ramp < 0.1) ramp=0.1; + ERR_P(LscCmd(ser, "RAMP [loop]:1,[ramp];SETP [loop],[setH];SETP?[loop]>tr")); } - if (0!=strcmp(ch, controlChannel) || switchOn) { - str_copy(controlChannel, ch); - logfileOut(LOG_MAIN, "set %f (on %s)\n", tempC, ch); + if (showSet) { + str_copy(controlChannel, ctlSens->ch); + if (ramp==0) { + logfileOut(LOG_MAIN, "set %g (on %s)\n", set, ctlSens->ch); + } else { + logfileOut(LOG_MAIN, "set %g (on %s) %g K/min\n", set, ctlSens->ch, ramp); + } + relay=0; + ERR_I(ReadHeater()); } return(0); OnError: return(-1); } +int SetMaxPower(void) { + int i, j; + float pa, pr, pw, dif; + + if (loop == 1) { + 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<=0 || s->type=='h') return '\0'; + if (s->type=='x') { + return '3'; + } else { + if (s->scale==1.0) { + return '1'; + } else { + return '4'; + } + } +} + +int Settings(void) { + char nbuf[256], buf[256], typ; + char flds[6], fmt[6]; + int i,k,l; + SensorT *s; + + remoteMode=2; /* set to remote mode */ + ERR_P(LscCmd(ser, "MODE:[remoteMode]")); + ERR_P(LscCmd(ser, "PID?[loop]>prop,integ,deriv")); + for (i=0; i<4; i++) { + s=sensors[i]; + plug=plugs[i/2]; + if (s->present < 0) { + if (settingsFlag) return(0); + ERR_I(InstalCurve(s, plug->device)); + } + } + + cryo.sensor1=NULL; + cryo.sensor2=NULL; + samp.sensor1=NULL; + samp.sensor2=NULL; + heliumSens=NULL; + auxSens=NULL; + for (i=0; i<4; i++) { + s=sensors[i]; + if (s->present==1) { + typ=s->type; + 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) { + auxSens=s; + } + s->band=10; + } + } + if (cryo.sensor1==NULL) { + cryo.sensor1=samp.sensor1; + cryo.sensor2=samp.sensor2; + } else if (samp.sensor1==NULL) { + samp.sensor1=cryo.sensor1; + samp.sensor2=cryo.sensor2; + } + + if (settingsFlag) return(0); + str_copy(statusBuf, "alarms"); + + /* alarms */ + alarmList[0]='\0'; + alarmList[1]='\0'; + alarmList[2]='\0'; + s=cryo.sensor1; + if (s!=NULL) { + ERR_I(SetMaxPower()); + r1=tLimit/s->scale; + str_copy(buf1, s->ch); + str_copy(buf, "ALARM [buf1]:1,1,[r1],0,1,1;RELAY 1:1;BEEP:0"); + alarmList[0]=s->ch[0]; + if (samp.sensor1!=cryo.sensor1) { + s=samp.sensor1; + r2=tLimit/s->scale; + str_copy(buf2, s->ch); + str_append(buf, ";ALARM [buf2]:1,1,[r2],0,1,1"); + alarmList[1]=s->ch[0]; + } + ERR_P(LscCmd(ser, buf)); + } + + /* switch off alarm 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 */ + + if (settingsFlag) return(0); + str_copy(statusBuf, "display"); + + /* display */ + k=1; + + fmt[k]=DisplayFmt(cryo.sensor1); + if (fmt[k]!='\0') { + flds[k]=cryo.sensor1->ch[0]; + k++; + } + fmt[k]=DisplayFmt(samp.sensor1); + if (fmt[k]!='\0') { + flds[k]=samp.sensor1->ch[0]; + k++; + } + if (cryo.sensor2 != cryo.sensor1) { + fmt[k]=DisplayFmt(cryo.sensor2); + if (fmt[k]!='\0') { + flds[k]=cryo.sensor2->ch[0]; + k++; + } + } + if (samp.sensor2 != samp.sensor1) { + fmt[k]=DisplayFmt(samp.sensor2); + if (fmt[k]!='\0') { + flds[k]=samp.sensor2->ch[0]; + k++; + } + } + fmt[k]=DisplayFmt(auxSens); + if (fmt[k]!='\0' && k<=4) { + flds[k]=auxSens->ch[0]; + k++; + } + 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,%c,%c;", k, flds[k], fmt[k]); + l=strlen(buf); + } + str_append(buf, "DISPLAY:[maxfld]"); + ERR_P(LscCmd(ser, buf)); + } + + if (settingsFlag) return(0); + str_copy(statusBuf, "reading temperatures"); + + if (cryo.sensor1!=NULL) { + ERR_I(SetTemp(2)); + } else { + ERR_I(ReadTemp()); + } + return(0); + logTime=(rdTim / logPeriod + 2) * logPeriod; /* wait before logging "dirty" temperatures */ + OnError: + return(-1); +} + +int ConfigByCode(int plugNr) { + char buf[16]; + + plug=plugs[plugNr]; + str_copy(plug->device,""); + plug->manual=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 { + logfileOut(LOG_MAIN+LOG_STAT ,"configure plug%d for cod %+d\n", plugNr, plug->code); + sprintf(buf, "%+d,", plug->code); + ERR_I(PrepInput(buf)); + } + settingsFlag=1; + return(0); + OnError: return(-1); +} + +int ConfigByName(int plugNr) { + char buf[20]; + + plug=plugs[plugNr]; + plug->manual=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); +} + 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) { + ERR_P(LscCmd(ser, "DIOST?>cod1,out1;DOUT 3,29;BUSY?>busy")); + if (plug0.codDefined && plug1.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; + */ + 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()); + 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; + 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, '/'); - cryo.code=atoi(buf3); - cryo.codChanged=0; + plug0.code=atoi(buf3); + plug0.codChanged=plug0.code != 0; if (next!=NULL) { next=str_split(buf3, next, '\n'); - samp.code=atoi(buf3); - samp.codChanged=0; + plug1.code=atoi(buf3); + plug1.codChanged=plug1.code != 0; } } } if (buf1[0]=='*') { - str_copy(cryo.device, buf1+1); - cryo.manual=1; + str_copy(plug0.device, buf1+1); + ConfigByName(0); } else { - if (cryo.code!=0) str_copy(cryo.device, buf1); - cryo.manual=0; + if (plug0.code!=0) str_copy(plug0.device, buf1); + plug0.manual=0; } - if (buf2[0]=='*' && buf2[1]!='\0') { - str_copy(samp.device, buf2+1); - samp.manual=1; + if (buf2[0]=='*') { + str_copy(plug1.device, buf2+1); + ConfigByName(1); } else { - if (samp.code!=0) str_copy(samp.device, buf2); - samp.manual=0; + if (plug1.code!=0) str_copy(plug1.device, buf2); + plug1.manual=0; } - concatDevice(); - if (cryo.manual || cryo.code!=0) { cryo.dirty=1; } - if (samp.manual || samp.code!=0) { samp.dirty=1; } + ConcatDevice(); + + settingsFlag=1; } noResp=0; } - if (relay) { + ERR_I(ReadHeater()); + + if (relay || loop !=1) { if (alarmList[0]!='\0') { str_copy(buf, "ALARMST?*"); buf[8]=alarmList[0]; @@ -857,21 +1242,34 @@ int PeriodicTask(void) { 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"); + str_copy(alarmChannels, " "); + if (alms[ 0]!='0' || alms[ 2]!='0') alarmChannels[0]=alarmList[0]; + if (alms[ 4]!='0' || alms[ 6]!='0') alarmChannels[1]=alarmList[1]; + if (0==strcmp(alarmChannels," ")) { + if (loop == 1) { + logfileOut(LOG_MAIN, "No more alarms, but relay is on!\n"); + } else { + logfileOut(LOG_MAIN, "No more alarms\n"); + relay=0; + } } else { - logfileOut(LOG_MAIN, "Alarm on channel %s\n", buf); + logfileOut(LOG_MAIN, "Alarm on channel %s\n", alarmChannels); + if (loop != 1) { + ERR_P(LscCmd(ser, "CSET 2:[chan],1,0,0")); + if (!relay) { + logfileOut(LOG_MAIN, "Switch off heater\n"); + relay=1; + } + } } str_copy(alarms, alms); } - } else { + } else if (loop == 1) { if (!relay0) logfileOut(LOG_MAIN, "Relay is on!\n"); alarms[0]='\0'; } - } else { + } else if (loop == 1) { + str_copy(alarmChannels, " "); if (relay0) logfileOut(LOG_MAIN, "No more alarms, relay is off\n"); alarms[0]='\0'; } @@ -881,55 +1279,23 @@ int PeriodicTask(void) { if (htrst!=htrst0) { LogMinMax(0); - if (htrst<0 || htrst>6) { - sprintf(buf, "heater status %d\n", htrst); - logfileOut(LOG_MAIN, buf); + if (htrst==0) { + logfileOut(LOG_MAIN, "heater o.k.\n"); } else { - logfileOut(LOG_MAIN, heaterStatus[htrst]); + logfileOut(LOG_MAIN, "%s\n", LscHtrStat(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>=logTime && cryo.sensor1!=NULL) { + ERR_I(DataPutAll(NULL, rdTim)); + logTime=(rdTim / 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 */ + if (set!=0) { + if (cryo.sensor1!=samp.sensor1 && controlMode==2) { + t=ctlSens->t; + d=(setH-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; @@ -941,14 +1307,12 @@ int PeriodicTask(void) { } tShift=tShift*(1.0-p)+p*(cryo.temp-samp.temp); ERR_I(SetTemp(0)); - } else if (remoteMode==2 && sens1.present) { + } else if (remoteMode==2) { ERR_I(SetTemp(0)); } } - ERR_P(LscCmd(ser, "KEYST?>key")); - ERR_P(LscCmd(ser, "DIOST?>cod2,out2")); - ERR_P(LscCmd(ser, "DOUT 3,30")); + ERR_P(LscCmd(ser, "KEYST?>key;DIOST?>cod2,out2;DOUT 3,30")); if (busy==0) { if (out1!=30) { @@ -957,90 +1321,70 @@ int PeriodicTask(void) { } if (out2!=29) { ERR_P(LscCmd(ser, "DOUT:3,29")); - ERR_P(LscCmd(ser, "DIOST?>cod2,out2")); - ERR_P(LscCmd(ser, "DOUT 3,30")); + ERR_P(LscCmd(ser, "DIOST?>cod2,out2;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]); + plug0.code1=3*decod[cod2 % 8] ^ 2*decod[cod1 % 8]; /* ^ is exclusive OR */ + plug1.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; + 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 { - tpoint->code2=tpoint->code1; + plug->code=plug->code1; + plug->codChanged=1; } } 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; - } + 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); } else { - logfileOut(LOG_MAIN, "plugged %d on %s\n", tpoint->code1, tpoint->tname); + logfileOut(LOG_MAIN, "plugged %d on plug%d\n", plug->code1, i); } - tempC=0; - remoteMode=2; /* set to remote mode */ - LscCmd(ser, "MODE:[remoteMode]"); - tpoint->dirty=1; - if (!configuring) configuring=1; + set=0; + ERR_I(ConfigByCode(i)); } - tpoint->codDefined=1; + plug->codDefined=1; } } } } if (key!=0) { - if (!(cryo.dirty || samp.dirty)) { + ERR_P(LscCmd(ser, "MODE?>remoteMode")); + if (!touched) { + touched=1; 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 (remoteMode==2) { + logfileOut(LOG_MAIN ,"user switched to remote\n"); + touched=0; + ERR_P(LscCmd(ser, "PID?[loop]>prop,integ,deriv")); if (controlMode==2) { ERR_P(LscCmd(ser, "RANGE?>iRange")); - if (iRange==0) tempC=0; + if (iRange==0) set=0; } else { - ERR_P(LscCmd(ser, "RANGE?>iRange")); - ERR_P(LscCmd(ser, "CSET?1>,cod1,")); - ERR_P(LscCmd(ser, "SETP?1>tempC")); + ERR_P(LscCmd(ser, "RAMP?[loop]>fbuf,ramp")); + if (fbuf==0.0) ramp=0.0; + ERR_P(LscCmd(ser, "RANGE?>iRange;CSET?[loop]>,cod1,;SETP?[loop]>set")); if (cod1!=1) { - tempC=0; + set=0; logfileOut(LOG_MAIN, "set point was not in K, set to 0\n"); } } - setFlag=(iRange>0); + settingsFlag=1; } } - 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 */ + IdleHdl(200, 0); /* wait 200 ms */ ERR_P(LscCmd(ser, "BUSY?>busy")); } saveTime=0; @@ -1049,291 +1393,322 @@ int PeriodicTask(void) { 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) { +int DeviceHdl(int mode, void *base) { char *t, *res; - struct CocClient *client; - float p; + int do0, do1; - if (readTemp) ERR_I(ReadTemp()); - if (remoteMode==2) ERR_I(Settings()); - if (maxPowerFlag) { - maxPowerFlag=0; - ERR_I(SetMaxPower()); + if (mode==COC_WR) { + set=0; + t=strchr(device, '/'); + if (t==NULL) { + if (0==strcmp(device, "0") || 0==strcasecmp(device, "auto")) { + settingsFlag=1; + 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(); } - if (pidFlag) { - pidFlag=0; - ERR_P(LscCmd(ser,"PID 1:[prop],[integ],[deriv]")); - } - if (setFlag) { - setFlag=0; - if (sens1.present) { + return(0); + OnError: return(-1); +} + +int SetHdl(int mode, void *base) { + if (mode==COC_WR) { + 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 (cryo.sensor1!=NULL) { 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 PidHdl(int mode, void *base) { + if (mode==COC_WR) { + return(COC_DWR); + } else if (mode==COC_DWR) { + ERR_P(LscCmd(ser,"PID [loop]:[prop],[integ],[deriv]")); } return(0); OnError: return(-1); } -int mainBody(void) -{ +int MaxPowerHdl(int mode, void *base) { + if (mode==COC_WR) { + return(COC_DWR); + } else if (mode==COC_DWR) { + ERR_I(SetMaxPower()); + ERR_I(SetTemp(1)); + } + return(0); + OnError: return(-1); +} + +int SendHdl(int mode, void *base) { + 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) { + 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); + OnError: return(-1); +} + +int PltHdl(int mode, void *base) { + ClientData *data; + int l; + char names[64]; + long startTime, endTime, step; + + if (mode==COC_RD) { + data=base; + ERR_SI(sscanf(data->pltdata, "%ld %ld %ld %n", &startTime, &endTime, &step, &l)-2); + str_copy(names, data->pltdata+l); + ERR_I(l=DataGetCoded(names, startTime, endTime, step, 30, data->pltdata, sizeof(data->pltdata))); + } + return(0); + OnError: return(-1); +} + +int PutFloat(StrBuf *buf, int prec, float f) { + char num[32], fmt[32]; + int l; + + if (f == DATA_UNDEF) { + return(StrPut(buf, "NaN", StrNONE)); + } else { + sprintf(fmt, "%%.%dg", prec); + sprintf(num, fmt, f); + return(StrPut(buf, num, StrNONE)); + } +} + +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, s->t * s->scale)); + ERR_I(StrPut(buf, units, StrNONE)); + } + } else { + ERR_I(StrPut(buf, LscReadStat(s->readStat), StrNONE)); + } + if (s==ctlSens && tr!=DATA_UNDEF) { + ERR_I(StrPut(buf, ", setpoint", '=')); + ERR_I(PutFloat(buf, 5, tr)); + 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 StatusHdl(int mode, void *base) { + int i, stat, typ; + StrBuf buf; + float tM, tS; + SensorT *s; + char pendAct[256]; + + StrLink(&buf, status); + StrClear(&buf); + if (statusBuf[0]!='\0') { + ERR_I(StrPut(&buf, "configuring:", ' ')); + ERR_I(StrPut(&buf, statusBuf, 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 (noResp==3) { + ERR_I(StrPut(&buf, "\nno connection or controller switched off", StrNONE)); + goto EndStatus; + } + if (device[0]!='\0') { + ERR_I(StrPut(&buf, "\ndevice:", ' ')); + ERR_I(StrPut(&buf, device, StrNONE)); + } + if (set==0) { + ERR_I(StrPut(&buf, "\ntemperature control is off", StrNONE)); + } else { + ERR_I(StrPut(&buf, "\ntarget", '=')); + ERR_I(PutFloat(&buf, 5, set)); + if (ramp==0 || tr==setH) { + ERR_I(StrPut(&buf, " K", StrNONE)); + } else { + ERR_I(StrPut(&buf, " K ramping at", ' ')); + ERR_I(PutFloat(&buf, 4, ramp)); + ERR_I(StrPut(&buf, " K/min", StrNONE)); + } + if (relay) { + ERR_I(StrPut(&buf, ", heater off (alarm)", StrNONE)); + } else if (htrst!=0) { + ERR_I(StrPut(&buf, ",", ' ')); + ERR_I(StrPut(&buf, LscHtrStat(htrst), StrNONE)); + } else { + ERR_I(StrPut(&buf, ", htr power", '=')); + if (power>=0.5 || power==DATA_UNDEF) { + 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, " ", '%')); + } + } + if (0!=strcmp(alarmChannels," ")) { + ERR_I(StrPut(&buf, "\nalarm on channel",' ')); + ERR_I(StrPut(&buf, alarmChannels, 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 (heliumSens!=NULL) { + ERR_I(StrPut(&buf, "\nhelium", ':')); + ERR_I(ShowSensor(&buf, heliumSens, "level", " %", 0)); + } + if (auxSens!=NULL) { + ERR_I(StrPut(&buf, "\nauxilliary", ':')); + ERR_I(ShowSensor(&buf, auxSens, "U", " V", 0)); + } +EndStatus: + ERR_I(StrPut(&buf, "", '\0')); + return(0); + OnError: + return(-1); +} + +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 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 */ + tdif = per - mycMsecSince(tim0); + if (tdif<0) { tim = mycNow(); break; } /* timeout */ ERR_I(iret=CocHandleRequests(tdif, 0)); - if (iret==0) { time(&tim); break; } /* timeout */ - tim=tim1.time; + tim=mycNow(); + if (iret==0) { /* timeout */ + break; + } 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); + tdif = mycMsecSince(tim0); + if (tdif>60000) { + logfileOut(LOG_MAIN ,"%d seconds lost\n", tdif/1000); } + tim0 = mycMsecSince(0)/period*period; if (ser!=NULL) { ERR_I(PeriodicTask()); + ERR_I(ExecuteRequest()); } - if (remoteMode==2) ERR_I(Settings()); return(0); OnError: @@ -1343,9 +1718,8 @@ int mainBody(void) cryo.temp=0; samp.temp=0; remoteMode=1; - configuring=0; + noResp=3; } else { - /* logfileShowErr("error"); */ logfileOut(LOG_ALL ,"no response\n"); noResp=1; per=100; /* try again soon */ @@ -1362,17 +1736,7 @@ int main(int argc, char *argv[]) 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; - + signal(SIGPIPE, ignore_forever); logMask=LOG_MAIN; binDir="bin/"; logDir="log/"; @@ -1423,131 +1787,144 @@ int main(int argc, char *argv[]) logfileOut(LOG_MAIN ,"%s ", argv[i]); } } - if (port==0) port=9753; - if (msecTmo==0) msecTmo=2000; + if (port==0) port=9757; + if (msecTmo==0) msecTmo=5000; if (logPeriod==0) logPeriod=5; str_copy(buf, logDir); str_append(buf, serverId); - str_copy(status, "starting up"); - logfileStatusBuf(status); + str_copy(statusBuf, "starting up"); + logfileStatusBuf(statusBuf); logfile=logfileInit(buf, logIt, use_stdout, logIt && use_stdout); logfileOut(LOG_MAIN ,"\n"); logfileWrite(logMask); - ERR_I(CocInitServer(1024, port)); + ERR_I(CocInitServer(SetClientData, port)); + +#define RD COC_RDONLY +#define RW COC_RDWR +#define RA COC_RDWRALL CocDefStruct(cryo, Testpoint); CocDefStruct(samp, Testpoint); CocDefPtr(tpoint, Testpoint); - CocFltFld(Testpoint, temp, CocRD); - CocFltFld(Testpoint, scale, CocRD); - CocFltFld(Testpoint, tMin, CocRD); - CocFltFld(Testpoint, tMax, CocRD); + CocFltFld(Testpoint, temp, RD); + CocFltFld(Testpoint, t1, RD); + CocFltFld(Testpoint, t2, RD); - CocDefStruct(sens1, SensorT); - CocDefStruct(sens2, SensorT); - CocDefStruct(sens3, SensorT); - CocDefStruct(sens4, SensorT); - CocDefPtr(sensor, SensorT); + CocDefStruct(sensA, SensorT); + CocDefStruct(sensB, SensorT); + CocDefStruct(sensC, SensorT); + CocDefStruct(sensD, SensorT); + CocDefPtr(sens, SensorT); - CocFltFld(SensorT, t, CocRD); - CocFltFld(SensorT, t1, CocRD); - CocFltFld(SensorT, t2, CocRD); - CocIntFld(SensorT, readStat, CocRD); - CocIntFld(SensorT, stat1, CocRD); - CocIntFld(SensorT, stat2, CocRD); - CocStrFld(SensorT, ch, CocRD); + CocFltFld(SensorT, t, RD); + CocFltFld(SensorT, t0, RD); + CocFltFld(SensorT, t1, RD); + CocFltFld(SensorT, t2, RD); + CocFltFld(SensorT, lim, RD); + CocFltFld(SensorT, scale, RD); + CocIntFld(SensorT, readStat, RD); + CocIntFld(SensorT, stat1, RD); + CocIntFld(SensorT, stat2, RD); + CocStrFld(SensorT, ch, RD); - CocDefFlt(htr, CocRD); - CocDefFlt(maxPower, maxPowerFlag); - CocDefFlt(prop, pidFlag); - CocDefFlt(integ, pidFlag); - CocDefFlt(deriv, pidFlag); - CocDefFlt(tempC, setFlag); - CocDefFlt(tempH, CocRD); - CocDefFlt(aux, CocRD); - CocDefFlt(full, CocWR); - CocDefFlt(tLimit, CocRD); - CocDefFlt(tLow, CocRD); - CocDefFlt(tHigh, CocRD); - CocDefFlt(maxShift, CocWR); - CocDefFlt(fbuf, CocRD); + CocDefFlt(maxPower, RW); CocHdl(MaxPowerHdl); + 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(htr, RD); + CocDefFlt(power, RD); + CocDefFlt(setH, RD); + CocDefFlt(full, RW); + CocDefFlt(tLimit, RD); + CocDefFlt(maxShift, RW); + CocDefFlt(tm, RD); + CocDefFlt(ts, RD); + CocDefFlt(tr, RD); + CocDefFlt(aux, RD); + CocDefFlt(he, RD); + CocDefFlt(fbuf, RD); + CocDefFlt(r1, RD); + CocDefFlt(r2, RD); - CocDefStr(device, deviceFlag); + CocDefPtr(clData, ClientData); + CocStrFld(ClientData, cmd, RW); CocHdl(SendHdl); + CocIntFld(ClientData, logstart, RA); + CocStrFld(ClientData, logline, RA); CocHdl(LogHdl); + CocStrFld(ClientData, pltdata, RA); CocHdl(PltHdl); - CocDefStr(buf1, CocRD); - CocDefStr(buf2, CocRD); - CocDefStr(buf3, CocRD); - CocDefStr(buf4, CocRD); - CocDefStr(head, CocRD); - CocDefStr(chan, CocRD); - CocDefStr(chanS, CocRD); - CocDefStr(chanM, CocRD); - CocDefStr(helium, CocRD); - CocDefStr(intype, CocRD); - CocDefStr(status, CocRD); - CocDefStr(dlogfile, CocRD); - CocDefStr(logfile, CocRD); + CocAlias(send, clData.cmd); + CocAlias(logstart, clData.logstart); + CocAlias(logline, clData.logline); + CocAlias(pltdata, clData.pltdata); - CocDefInt(cod1, CocRD); - CocDefInt(cod2, CocRD); - CocDefInt(out1, CocRD); - CocDefInt(out2, CocRD); - CocDefInt(num, CocRD); - CocDefInt(fld, CocRD); - CocDefInt(key, CocRD); - CocDefInt(maxfld, CocRD); - CocDefInt(resist, CocRD); - CocDefInt(iAmp, CocRD); - CocDefInt(iRange, CocRD); - CocDefInt(remoteMode, CocRD); - CocDefInt(heliumMode, CocRD); - CocDefInt(htrst, CocRD); - CocDefInt(tuning, CocRD); + 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(intype, RD); + CocDefStr(status, RD); CocHdl(StatusHdl); + CocDefStr(logfile, RD); - CocDefInt(logPeriod, CocWR); - CocDefInt(readTemp, CocWR); - CocDefInt(controlMode, CocWR); - CocDefInt(cmode, CocWR); - CocDefInt(int2, CocWR); - CocDefInt(busy, CocRD); - CocDefInt(relay, CocRD); - CocDefInt(serialNo, CocRD); - CocDefInt(configuring, CocRD); - CocDefInt(quit, CocWR); + CocDefInt(cod1, RD); + CocDefInt(cod2, RD); + CocDefInt(out1, RD); + CocDefInt(out2, RD); + CocDefInt(num, RD); + CocDefInt(key, RD); + CocDefInt(maxfld, RD); + CocDefInt(resist, RD); + CocDefInt(iAmp, RD); + CocDefInt(iRange, RD); + CocDefInt(remoteMode, RD); + CocDefInt(htrst, RD); + CocDefInt(loop, RD); + CocDefInt(rdTim, RD); + CocDefInt(tim0, RD); + + CocDefInt(logPeriod, RW); + CocDefInt(readTemp, RW); + CocDefInt(controlMode, RW); + CocDefInt(int2, RW); + CocDefInt(busy, RD); + CocDefInt(relay, RD); + CocDefInt(serialNo, RD); + CocDefInt(quit, RW); CocAlias(tempX,cryo.temp); CocAlias(tempP,samp.temp); - CocAlias(tX,cryo.temp); - CocAlias(tS,samp.temp); - CocAlias(t1,sens1.t); - CocAlias(t2,sens2.t); - CocAlias(t3,sens3.t); - CocAlias(t4,sens4.t); - CocAlias(set,tempC); + CocAlias(Ta,sensA.t); + CocAlias(Tb,sensB.t); + CocAlias(Tc,sensC.t); + CocAlias(Td,sensD.t); + CocAlias(P,power); + CocAlias(tempC, set); CocAlias(int,integ); - ser=SerOpen(host, msecTmo, idleHdl); + ser=SerOpen(host, msecTmo, IdleHdl); if (ser==NULL) { logfileShowErr("error in SerOpen"); } ERR_I(iret=CocHandleRequests(100, 0)); - ftime(&tim0); - tim=tim0.time; - if (period>1000) { /* 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); + tim0=mycMsecSince(0)/period*period; + tim=mycNow(); + + ERR_P(DataCreateSet(NULL, "Tm", &tm, 5, LOGLIFETIME, tim)); + ERR_P(DataCreateSet(NULL, "Ts", &ts, 5, LOGLIFETIME, tim)); + ERR_P(DataCreateSet(NULL, "Tr", &tr, 5, LOGLIFETIME, tim)); + ERR_P(DataCreateSet(NULL, "He", &he, 5, LOGLIFETIME, tim)); + ERR_P(DataCreateSet(NULL, "Aux", &aux, 5, LOGLIFETIME, tim)); + ERR_P(DataCreateSet(NULL, "P", &power, 5, LOGLIFETIME, tim)); remoteMode=2; prop=50; @@ -1555,30 +1932,34 @@ int main(int argc, char *argv[]) deriv=0; if (ser!=NULL) { LscCmd(ser, "MODE?>remoteMode"); - LscCmd(ser, "PID?1>prop,integ,deriv"); + LscCmd(ser, "PID?[loop]>prop,integ,deriv"); } - if (remoteMode!=2) configuring=0; per=1; /* advance fast when initializing */ cntError=0; while (!quit) { - iret=mainBody(); + iret=MainBody(); if (iret<0 || ser==NULL) { cntError++; + ser=SerCheck(ser); if (0==strcmp(ErrMessage, "asynsrv error")) { if (ser!=NULL) SerClose(ser); ser=NULL; } if (cntError<4) { - logfileShowErr("error in TecsServer/mainBody"); + 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); + ser=SerOpen(host, msecTmo, IdleHdl); if (ser!=NULL) { LscCmd(ser, "MODE?>remoteMode"); - LscCmd(ser, "PID?1>prop,integ,deriv"); + LscCmd(ser, "PID?[loop]>prop,integ,deriv"); } } } else { @@ -1594,9 +1975,11 @@ int main(int argc, char *argv[]) logfileWrite(logMask); ERR_MSG("got quit command"); OnError: + printf("TecsServer exited: %s\n", ErrMessage); logfileShowErr("exit TecsServer"); - dlog_close_w_(); - SerClose(ser); + if (ser!=NULL) SerClose(ser); CocCloseServer(); - return(0); + logfileClose(); + if (quit) return 0; + return -1; } diff --git a/tecs/tecs_cli.c b/tecs/tecs_cli.c index 32637b18..59ea8418 100644 --- a/tecs/tecs_cli.c +++ b/tecs/tecs_cli.c @@ -1,98 +1,65 @@ +#include #include #include +#include "myc_mem.h" +#include "myc_err.h" +#include "myc_str.h" +#include "myc_time.h" #include "sys_util.h" -#include "err_handling.h" -#include "str_util.h" +#include "coc_util.h" #include "tecs_cli.h" +#include "tecs_data.h" -static char device[80], command[80]; -static int readTemp, configuring; -static float tempX, tempP, tempC; +static char response[COC_RES_LEN]; pTecsClient TeccInit(char *startcmd, int port) { CocConn *conn; + static char *rwCode="rwacs"; + static char *rdCode="rdacs"; - NEW(conn); + NEW(conn, CocConn); if (startcmd[0]=='#') { - ERR_I(CocInitClient(conn, startcmd+1, port, "#rwacs", 0, "")); + ERR_I(CocInitClient(conn, startcmd+1, port, rdCode, 0, "")); } else { - ERR_I(CocInitClient(conn, "", port, "#rwacs", 0, startcmd)); + ERR_I(CocInitClient(conn, "", port, rwCode, 0, startcmd)); } - CocDefFlt(tempC, CocRD); - CocDefFlt(tempP, CocRD); - CocDefFlt(tempX, CocRD); - CocDefStr(device, CocWR); - CocDefInt(configuring, CocRD); - CocDefInt(readTemp, CocWR); - CocDefCmd(command); - return((pTecsClient)conn); OnError: return(NULL); } int TeccGet3(pTecsClient conn, float *tC, float *tX, float *tP) { - readTemp=1; - ERR_I(CocCmd(conn, "tempC,tempX,tempP,[readTemp],configuring")); - *tC=tempC; - *tX=tempX; - *tP=tempP; - return(configuring); + int iret; + + CocReset(conn); + ERR_I(CocGetFloat(conn, "set", tC)); + ERR_I(CocGetFloat(conn, "tempX", tX)); + ERR_I(CocGetFloat(conn, "tempP", tP)); + ERR_I(CocPutInt(conn, "readTemp", 1)); + ERR_I(iret=CocDoIt(conn, response, sizeof(response))); + if (iret) ERR_MSG(response); + return(0); OnError: return(-1); } int TeccGet(pTecsClient conn, float *temp) { - readTemp=1; - ERR_I(CocCmd(conn, "tempP,[readTemp],configuring")); - *temp=tempP; - return(configuring); - OnError: return(-1); -} + int iret; -int TeccWait(pTecsClient conn) { - int last, cnt; - - last=0; - cnt=0; - do { - CocDelay(250); - ERR_I(CocCmd(conn, "configuring")); - if (configuring==last || configuring>1000) { - cnt++; - if (cnt>20) ERR_MSG("configuring timeout"); - } else { - cnt=0; - last=configuring; - } - } while (configuring>0); + CocReset(conn); + ERR_I(CocGetFloat(conn, "tempP", temp)); + ERR_I(CocPutInt(conn, "readTemp", 1)); + ERR_I(iret=CocDoIt(conn, response, sizeof(response))); + if (iret) ERR_MSG(response); return(0); OnError: return(-1); } int TeccSet(pTecsClient conn, float temp) { - tempC=temp; - ERR_I(CocCmd(conn, "[tempC]")); - return(0); - OnError: return(-1); -} + int iret; -int TeccSend(pTecsClient conn, char *cmd, char *reply, int replyLen) { - char *res; - int cnt; - - str_copy(command, cmd); - ERR_I(CocCmd(conn, "[$]")); - cnt=40; - CocDelay(100); - while (cnt>0) { - ERR_I(CocCmd(conn, "$")); - if (command[0]!='\0') { - str_ncpy(reply, command, replyLen); - return(0); - } - CocDelay(250); - cnt--; - } - str_ncpy(reply, "", replyLen); + CocReset(conn); + ERR_I(CocPutFloat(conn, "set", temp)); + ERR_I(iret=CocDoIt(conn, response, sizeof(response))); + if (iret) ERR_MSG(response); return(0); OnError: return(-1); } @@ -102,7 +69,9 @@ int TeccQuitServer(pTecsClient conn) { ERR_I(iret=CocCheck(conn)); if (iret==0) { - ERR_I(CocSet(conn, "quit", "1")); + CocReset(conn); + ERR_I(CocPutInt(conn, "quit", 1)); + ERR_I(CocDoIt(conn, response, sizeof(response))); cnt=50; while (iret==0 && cnt>0) { CocDelay(100); @@ -110,12 +79,15 @@ int TeccQuitServer(pTecsClient conn) { cnt--; } } - if (iret==1) return(0); ERR_MSG("Does not quit within 5 seconds"); OnError: return(-1); } +int TeccSend(pTecsClient conn, char *cmd, char *reply, int replyLen) { + return(CocSetGetN(conn, "send", cmd, reply, replyLen)); +} + void TeccClose(pTecsClient conn) { if (conn!=NULL) { CocCloseClient(conn); @@ -136,48 +108,86 @@ void TeccClose(pTecsClient conn) { #ifdef __VMS #define tecs_get_par_ tecs_get_par +#define tecs_get_mult_ tecs_get_mult #define tecs_set_par_ tecs_set_par -#define tecs_send_ tecs_send #define tecs_init_ tecs_init #define tecs_get3_ tecs_get3 +#define tecs_get_ tecs_get #define tecs_set_ tecs_set -#define tecs_wait_ tecs_wait #define tecs_is_open_ tecs_is_open #define tecs_close_ tecs_close #define tecs_quit_server_ tecs_quit_server +#define tecs_watch_log_ tecs_watch_log +#define tecs_get_data_ tecs_get_data +#define tecs_date_ tecs_date +#define tecs_time_ tecs_time #endif static pTecsClient conn=NULL; -int tecs_set_par_(F_CHAR(name), F_CHAR(par), int name_len, int par_len) { - char nbuf[64], pbuf[256]; +int tecs_set_par_(F_CHAR(name), F_CHAR(par), int *show, int name_len, int par_len) { + char nbuf[64], pbuf[COC_CMD_LEN]; int iret=-1; STR_TO_C(nbuf, name); STR_TO_C(pbuf, par); - ERR_I(iret=CocSet(conn, nbuf, pbuf)); - + CocReset(conn); + ERR_I(CocPutStr(conn, nbuf, pbuf)); + ERR_I(CocDoIt(conn, response, sizeof(response))); + if (*show) { + printf("%s", response); + } return(0); - OnError: return(iret); + OnError: return(-1); } -int tecs_get_par_(F_CHAR(name), F_CHAR(par), int name_len, int par_len) { - char nbuf[64], pbuf[256]; +int tecs_get_par_(F_CHAR(name), F_CHAR(par), int *show, int name_len, int par_len) { + char *b, nbuf[64], pbuf[COC_RES_LEN]; int iret=-1; STR_TO_C(nbuf, name); - ERR_I(iret=CocGet(conn, nbuf, pbuf)); + CocReset(conn); + ERR_I(CocGetStr(conn, nbuf, pbuf, sizeof(pbuf))); + ERR_I(CocDoIt(conn, response, sizeof(response))); + if (*show==2) { + b=response; + } else { + b=strchr(response,'='); + if (b==NULL) { + b=response; + } else { + b++; + } + } + if (*show) { + printf("%s", b); + } return(STR_TO_F(par, pbuf)); - OnError: return(iret); + OnError: return(-1); } -int tecs_send_(F_CHAR(cmd), F_CHAR(reply), int cmd_len, int reply_len) { - char cbuf[80], rbuf[80]; +int tecs_get_mult_(F_CHAR(names), int *time, int *nvalues, float values[], int names_len) { + char *b, nbuf[64], pbuf[COC_RES_LEN]; + char *nams, nam[32]; + int i; - STR_TO_C(cbuf, cmd); - ERR_I(TeccSend(conn, cbuf, rbuf, sizeof(rbuf))); - return(STR_TO_F(reply, rbuf)); + STR_TO_C(nbuf, names); + CocReset(conn); + + ERR_I(CocGetInt(conn, "rdTim", time)); + i=0; + nams=nbuf; + while (nams!=NULL && i < *nvalues) { + nams=str_split(nam, nams, ' '); + if (nam[0]!='\0') { + ERR_I(CocGetFloat(conn, nam, values+i)); + i++; + } + } + + ERR_I(CocDoIt(conn, response, sizeof(response))); + return(0); OnError: return(-1); } @@ -191,19 +201,21 @@ int tecs_init_(F_CHAR(startcmd), int *port, int startcmd_len) { } int tecs_get_(float *temp) { - return(TeccGet(conn, temp)); + ERR_I(TeccGet(conn, temp)); + return(0); + OnError: return(-1); } int tecs_get3_(float *t1, float *t2, float *t3) { - return(TeccGet3(conn, t1, t2, t3)); + ERR_I(TeccGet3(conn, t1, t2, t3)); + return(0); + OnError: return(-1); } int tecs_set_(float *temp) { - return(TeccSet(conn, *temp)); -} - -int tecs_wait_(void) { - return(TeccWait(conn)); + ERR_I(TeccSet(conn, *temp)); + return(0); + OnError: return(-1); } int tecs_is_open_() { @@ -216,7 +228,141 @@ void tecs_close_(void) { } int tecs_quit_server_(void) { - return(TeccQuitServer(conn)); + ERR_I(TeccQuitServer(conn)); + return(0); + OnError: return(-1); } +int tecs_watch_log_(F_CHAR(list), int list_len) { + char buf[16]; + STR_TO_C(buf, list); + ERR_I(CocWatchLog(conn, buf)); + return(0); + OnError: return(-1); +} + +static char *encode=DATA_CODE; + +int DataDecode(float *data, int dataSize, char *coded, int *retSize) { + int i, p, gap, dig1, dig2; + float minD, range; + char ch, *q; + static int decode[256]; + static int init=1; + + if (coded[0] == '\0') { + *retSize=0; + return 0; + } + if (init) { + init=0; + for (i=0; i<256; i++) { + decode[i]=-1; + } + i=0; + while (encode[i]!=0) { + decode[encode[i]]=i; + i++; + } + } + p=0; + ERR_SI(sscanf(coded, "%d %e %e %n", retSize, &minD, &range, &p)-3); + if (*retSize < dataSize) dataSize = *retSize; + i=0; + while (i < dataSize) { + ch=coded[p++]; + dig1=decode[ch]; + if (dig1 < 0) { /* code is no 64-digit */ + if (ch=='\0' || ch==',') break; + if (ch=='/') { data[i++] = DATA_UNDEF; } + } else { + ch=coded[p++]; + dig2=decode[ch]; + while (dig2<0) { + if (ch=='\0' || ch==',') break; + ch=coded[p++]; + dig2=decode[ch]; + } + if (ch=='\0' || ch==',') break; + data[i++] = (dig1 + dig2 * 64) / 4095.0 * range + minD; + } + } + while (i < dataSize) { + data[i++] = DATA_UNDEF; + } + if (ch=='\0') { + return p-1; + } else if (ch!=',') { + q=strchr(coded+p, ','); + if (q==NULL) return strlen(coded); + return q-coded+1; + } + return p; + OnError: + *retSize=0; + return -1; +} + + +int tecs_get_data_(F_CHAR(names), int *startTime, int *endTime, int *step, float data[], int *maxLen, int *width + , int retLen[], int names_len) { + char nam[64]; + char str[128]; + char res[COC_RES_LEN]; + char *cod; + int i, l, iret, retSize; + + if (*endTime - *startTime > *step * (*maxLen-1)) { + printf("maxLen too small\n"); + } + STR_TO_C(nam, names); + if (*step <= 0) { + *step = 60; + } + sprintf(str, "%d %d %d %s", *startTime, *endTime, *step, nam); + + CocReset(conn); + ERR_I(CocPutStr(conn, "pltdata", str)); + ERR_I(CocGetStr(conn, "pltdata", res, sizeof(res))); + ERR_I(iret=CocDoIt(conn, response, sizeof(response))); + if (iret) ERR_MSG(response); + cod=res; + for (i=0; i < *width; i++) { + ERR_I(l=DataDecode(data + i * *maxLen, *maxLen, cod, retLen+i)); + cod+=l; + } + return 0; + OnError: + return -1; +} + +/* +float tecs_date_(time_t *time) { + struct tm tim; + + tim=*localtime(time); + return(tim.tm_mday+(tim.tm_mon+1)*0.01); +} + +time_t tecs_time_(float *date) { + struct tm tim; + time_t t, now; + int m; + + time(&now); + tim=*localtime(&now); + tim.tm_hour=0; + tim.tm_min=0; + tim.tm_sec=0; + tim.tm_mday=(int)*date; + m=(int)(*date*100+0.1) % 100; + if (m > 0) tim.tm_mon=m-1; + t=mktime(&tim); + if (t > now) { + tim.tm_year--; + t=mktime(&tim); + } + return t; +} +*/ #endif diff --git a/tecs/tecs_cli.h b/tecs/tecs_cli.h index 7029d802..380302dc 100644 --- a/tecs/tecs_cli.h +++ b/tecs/tecs_cli.h @@ -20,9 +20,6 @@ int TeccGet(pTecsClient conn, float *temp); int TeccSet(pTecsClient conn, float temp); /* set temperature */ -int TeccWait(pTecsClient conn); -/* wait until the controller is configured */ - int TeccSend(pTecsClient conn, char *cmd, char *reply, int replyLen); /* send a command transparently to the controller replyLen is the maximal length of reply */ diff --git a/tecs/tecs_client.f b/tecs/tecs_client.f index 56bb3410..ca426ea7 100644 --- a/tecs/tecs_client.f +++ b/tecs/tecs_client.f @@ -1,26 +1,33 @@ program tecs_client - real*4 temp(4) - character device*32, init*80, line*80, cmd*16, par*80, response*80 + real temp + character device*32, init*80, line*80, cmd*16, par*80, response*1024 integer i,j,k,iret,l - character file*128, cmdpar*128 + character cmdpar*128 + character prompt*32/'tecs>'/ + integer promptlen/6/ logical oneCommand + character logarg*4/'25'/ + character defcmd*8/'status'/ ! functions - integer tecs_get_par, tecs_quit_server, tecs_send, tecs_set_par + integer tecs_get_par, tecs_quit_server, tecs_set_par, tecs_watch_log + integer tecs_get, show_log call sys_getenv('TECS_INIT', init) call sys_get_cmdpar(line, l) if (l .ne. 0) then - if (line .eq. 'off' .or. line .eq. 'OFF') init=' ' oneCommand=.true. else oneCommand=.false. endif - if (init .eq. ' ') then - call tecs_open(0, ' ', iret) + if (oneCommand .and. line(1:1) .eq. '#') then + call tecs_open(0, line, iret) + oneCommand=.false. + else if (init .eq. ' ') then + call tecs_open(0, line, iret) else call tecs_open(1, init, iret) endif @@ -38,7 +45,8 @@ print *,'device set cryo device' print *,' show parameter' print *,' set parameter' - print *,'plot temperature and power chart' + print *,'plot chart for temperature and ' + 1 ,' var = P (default), He, Aux' print *,'log show last n lines of logfile' print *,'kill close TecsServer and exit' print *,'exit,quit exit, but do not close TecsServer' @@ -47,7 +55,7 @@ l=0 1 if (oneCommand) goto 99 - call sys_rd_line(line, l, 'tecs> ') + call sys_rd_line(line, l, prompt(1:promptlen)) if (l .lt. 0) goto 99 11 l=l+1 line(l:l)=' ' @@ -61,44 +69,54 @@ cmd(k:k)=char(ichar(cmd(k:k))+32) endif elseif (k .gt. 0) then ! end of command - goto 2 + par=' ' + do i=j,l + if (line(i:i) .gt. ' ') then + par=line(i:l) + goto 3 ! command with parameter + endif + enddo + goto 2 ! parameterless command endif enddo - if (k .eq. 0) then ! empty line - call tecs_get_t(6, temp, iret) - if (iret .ne. 0) goto 1 - iret=tecs_get_par('device', device) - if (iret .lt. 0) goto 19 - print '(x,3(a,f8.3),2a)','tempX=', temp(3),', tempP=',temp(2) - 1 ,', set=',temp(1), ', device=',device + if (k .ne. 0) then + print *,'command too long' goto 1 endif - print *,'command too long' - goto 1 - -2 par=' ' - do i=j,l - if (line(i:i) .gt. ' ') then - par=line(i:l) - goto 3 - endif - enddo + ! empty command - ! simple query +12 cmd=defcmd - if (cmd .eq. 'kill' .or. cmd .eq. 'off') then +2 continue ! parameterless command + + defcmd='status' + + if (cmd(1:1) .eq. '#') then + call tecs_close + call tecs_open(0, cmd, iret) + if (iret .lt. 0) goto 91 + prompt='tecs/'//cmd(2:) + promptlen=1 + do i=1,len(prompt)-2 + if (prompt(i:i) .ne. ' ') promptlen=i + enddo + promptlen=promptlen+1 + prompt(promptlen:promptlen)='>' + promptlen=promptlen+1 + else if (cmd .eq. 'kill') then iret=tecs_quit_server() elseif (cmd .eq. 'exit' .or. cmd .eq. 'quit') then goto 99 - elseif (cmd .eq. 'on') then + elseif (cmd .eq. 'status') then + iret=tecs_get_par('status', response, 1) + if (iret .lt. 0) goto 19 + elseif (cmd .eq. 'on' .or. cmd .eq. 'off') then l=0 goto 11 elseif (cmd .eq. 'plot') then - iret=tecs_get_par('dlogfile', file) - if (iret .lt. 0) goto 19 - call tecs_plot(file) + call tecs_plot('Tm Ts Tr P', 1) elseif (cmd .eq. 'help') then print * print *,'Writeable parameters:' @@ -116,9 +134,9 @@ print * print *,'Read only parameters:' print * - print *,'tX heat exchanger temperature' - print *,'tS sample temperature' - print *,'tempH set-point on regulation' + print *,'Tm main temperature' + print *,'Ts sample temperature' + print *,'setH set-point on regulation' print *,'tLimit temperature limit' print *,'htr heater current percentage' print *,'resist heater resistance' @@ -126,10 +144,7 @@ print *,'remoteMode 1: local, 2: remote ' 1 ,'(switch on with device command)' print * - print *,'t1 regulation temperature (hi-T sensor)' - print *,'t2 regulation temperature (low-T sensor)' - print *,'t3 sample temperature (hi-T sensor)' - print *,'t4 sample temperature (low-T sensor)' + print *,'Ta,Tb,Tc,Td values of channels A,B,C,D' print * print *,'Temperature devices:' print * @@ -139,33 +154,43 @@ print *,'ccr4k (4K closed cycle), hef4c (TriCS 4circle cryo)' print *,'sup4t (supra.magnet 4T)' print *,'rdr11, rdr12 (LTF dilution 1 & 2, 20kOhm)' - 1 ,', rdrn11_2, rdr12_2 (2kOhm)' print * elseif (cmd .eq. 'log') then - iret=tecs_get_par('logfile', file) + if (line(1:l) .eq. ' ') then + print '(x,a)' + 1 ,char(27)//'[A'//char(13)//char(27)//'[K'//char(27)//'[2A' + endif + if (show_log(logarg) .le. 0) then + logarg='25' + print *,'-------- end of logfile --------' + goto 12 + endif + defcmd='log' + logarg=' ' + elseif (cmd .eq. 'watch') then + iret=tecs_watch_log('M') if (iret .lt. 0) goto 19 - call show_log(50, file) else - iret=tecs_get_par(cmd, response) + iret=tecs_get_par(cmd, response, 2) if (iret .lt. 0) goto 19 - print '(7x,3a)',cmd(1:k),'=',response endif goto 1 -3 if (cmd .eq. 'send') then - iret=tecs_send(par, response) +3 continue ! command with parameter + + if (cmd .eq. 'log') then + if (show_log(par) .gt. 0) then + defcmd='log' + endif + logarg=' ' + elseif (cmd .eq. 'plot') then + call tecs_plot('Tm Ts Tr '//par, 1) + elseif (cmd .eq. 'watch') then + iret=tecs_watch_log(par) if (iret .lt. 0) goto 19 - print '(7x,2a)','response: ',response - elseif (cmd .eq. 'log') then - i=50 - read(par, *, err=31) i -31 iret=tecs_get_par('logfile', file) - if (iret .lt. 0) goto 19 - call show_log(i, file) else - iret=tecs_set_par(cmd, par) + iret=tecs_set_par(cmd, par, 2) if (iret .lt. 0) goto 19 - print '(7x,3a)',cmd(1:k),':=',par endif goto 1 @@ -182,27 +207,21 @@ 99 end - subroutine show_log(lines, file) + integer function show_log(lines) - integer lines + character*(*) lines integer i,l - character str*132, file*(*) + character str*8192 - print * - print * - open(1, name=file, status='old', readonly, shared, err=39) - i=0 -31 read(1,'(a)',end=32) - i=i+1 - goto 31 -32 rewind(1) - do i=1,i-lines - read(1,*,end=39) - enddo -33 read(1,'(q,a)',end=39) l,str - print *,str(1:min(len(str),max(1,l))) - goto 33 -39 continue - close(1) +! functions + integer tecs_get_par, tecs_set_par + + if (lines .ne. ' ') then + l=tecs_set_par('logstart', lines, 0) + print *,'line: ',lines + print * + endif + + show_log=tecs_get_par('logline', str, 1) end diff --git a/tecs/tecs_data.c b/tecs/tecs_data.c new file mode 100644 index 00000000..e2e5c19d --- /dev/null +++ b/tecs/tecs_data.c @@ -0,0 +1,585 @@ +#include +#include +#include +#include +#include "myc_mem.h" +#include "myc_str.h" +#include "myc_err.h" +#include "myc_time.h" +#include "coc_logfile.h" +#include "tecs_data.h" + +#define RUN_SIZE 1024 +#define SET_LEN 1024 + +typedef struct { + int tmin, tmax, tlim; + float dmin, dmax; + int reset; +} Summary; + +typedef struct _Run { + struct _Run *next; + int size, step; + int startTime, endTime; + float data[RUN_SIZE]; +} Run; + +typedef struct _Set { + DataSet set; + struct _Set *next; + int nRuns; + int step, lifetime; + int start, end; + float *var; + Run *runs; + Summary sum; +} Set; + +typedef struct { + Set *head; +} Base; + +typedef struct { + Base *base; + int tim, from, to; + int stdStep; +} ScanData; + +static Base database; + +void InsSum(Summary *sum, int t, float d) { + if (sum->tmin == 0) { + sum->tmin = t; + sum->tmax = t; + sum->dmin = d; + sum->dmax = d; + } else { + if (d <= sum->dmin) { + sum->dmin = d; + sum->tmin = t; + } else if (d >= sum->dmax) { + sum->dmax = d; + sum->tmax = t; + } + } +} + +void ResetSum(Summary *sum) { + sum->reset = 1; + sum->tmin = 0; + sum->dmin = DATA_UNDEF; + sum->dmax = DATA_UNDEF; +} + +void PutSum(Summary *sum, float *data) { + if (sum->tmin == 0) { + data[1] = sum->dmin; + data[0] = sum->dmax; + } else if (sum->tmin > sum->tmax) { + data[1] = sum->dmin; + data[0] = sum->dmax; + sum->dmin = sum->dmax; + } else if (sum->tmin < sum->tmax) { + data[1] = sum->dmax; + data[0] = sum->dmin; + sum->dmax = sum->dmin; + } else { + data[1] = sum->dmin; + data[0] = sum->dmax; + } + sum->tmin = 0; + if (sum->reset) { + sum->dmin = DATA_UNDEF; + sum->dmax = DATA_UNDEF; + sum->reset = 0; + } +} + +Set *FindSet(Base *base, char *name) { + Set *s; + int total; + + total=0; + s = base->head; + while (s!=NULL && 0!=strcmp(name, s->set.name)) { + s = s->next; + } + return s; +} + +Set *CreateSet(Base *base, char *name, float *var, int step, int lifetime, int start) { + Set *s; + char *nam; + + s = FindSet(base, name); + if (s != NULL) ERR_MSG("dataset exists"); + NEW(s, Set); + s->next = base->head; + base->head = s; + NEW_STR(nam, name); + s->set.name = nam; + s->runs = NULL; + s->nRuns = 0; + s->lifetime = lifetime; + s->start = start; + s->step = step; + s->var = var; + ResetSum(&s->sum); + return s; + OnError: + return NULL; +} + +DataSet *DataFindSet(DataBase *dBase, char *name) { + Base *base; + if (dBase==NULL) { + base=&database; + } else { + base=(Base *)dBase; + } + return (DataSet *) FindSet(base, name); +} + +DataSet *DataCreateSet(DataBase *dBase, char *name, float *var, int step, int lifetime, int start) { + Base *base; + if (dBase==NULL) { + base=&database; + } else { + base=(Base *)dBase; + } + return (DataSet *) CreateSet(base, name, var, step, lifetime, start); +} + +int DataSetStep(DataSet *set, int step) { + Set *s; + + ERR_P(set); + ERR_I(step-1); /* step > 0 */ + s = (Set *)set; + s->step = step; + return 0; + OnError: return -1; +} + +int DataSetLifetime(DataSet *set, int lifetime) { + Set *s; + + ERR_P(set); + s = (Set *)set; + s->lifetime = lifetime; + return 0; + OnError: return -1; +} + +Run *InsertRun(Set *s, int time) { + Run *r, *next, *last; + + NEW(r, Run); + r->next = s->runs; + s->runs = r; + r->step = s->step; + s->nRuns++; + if (s->nRuns * s->step > s->lifetime) { + next=r->next; + last=r; + while (next!=NULL && next->endTime > time - s->lifetime) { + last = next; + next = last->next; + } + while (next!=NULL) { + last->next = next->next; + FREE(next); + s->nRuns--; + next = last->next; + } + } + return r; + OnError: + return NULL; +} + +int Put(Set *set, int time, float value) { + Run *r; + int t, try = 1; + int size; + float last; + + ERR_P(set); + if (value == DATA_UNDEF) return 0; + r = set->runs; + if (r == NULL || r->step != set->step || r->size+3 > RUN_SIZE) { + ERR_P(r = InsertRun(set, time)); + r->startTime = time; + r->endTime = time - r->step; + size = 0; + t = 1; + } else { + size = r->size; + t = (time - r->endTime) / r->step; + last = r->data[size-1]; + } + if (t<0) { + if (t<-1) { + logfileOut(LOG_MAIN, "%s %d set.name, time, r->endTime); + ERR_MSG("back in time not possible"); + } + t=0; + } + if (t == 0) { + InsSum(&set->sum, time, value); + } else { + if (size % 2) { + PutSum(&set->sum, r->data+size-1); size++; + r->endTime += r->step; + t--; + } + if (t > 2) { + r->data[size]=t-1; size++; + r->data[size]=DATA_UNDEF; size++; + set->sum.reset = 1; + r->endTime += r->step * (t-1); + t=1; + } + InsSum(&set->sum, time, value); + if (t % 2) { + r->data[size]=value; size++; /* put a provisory value */ + r->endTime += r->step; + } else { + PutSum(&set->sum, r->data+size); size+=2; + r->endTime += r->step * 2; + } + } + r->size = size; + return 0; + OnError: + return -1; +} + +int DataPut(DataSet *set, int time, float value) { + return Put((Set *)set, time, value); +} + +int DataPutAll(DataBase *base, int time) { + Set *s; + + if (base == NULL) { + s=database.head; + } else { + s=((Base *)base)->head; + } + while (s!=NULL) { + if (s->var!=NULL) { + ERR_I(Put(s, time, *s->var)); + } + s=s->next; + } + return 0; + OnError: + return -1; +} + +int Start(Set *s) { + Run *r; + int t1, t2; + + r = s->runs; + t1 = s->start; + if (r != NULL) { + t2 = r->endTime - s->lifetime; + if (t1 < t2) { + while (r != NULL) { + t1 = r->startTime; + r = r->next; + } + if (t1 > t2) { + t1 = t2; + } + } + } + return t1; +} + +void FreeBase(Base *base) { + Set *s, *sFree; + Run *r, *rFree; + + s = base->head; + while (s != NULL) { + r = s->runs; + while (r != NULL) { + rFree = r; + r = r->next; + FREE(rFree); + } + sFree=s; + s = s->next; + FREE(sFree); + } +} + +int GetSet(Set *s, int startTime, int endTime, int size, float *data) { + Run *r; + int t, tlim, tmin; + float d; + int i, idx; + Summary sum; + + if (size<=0 || size%2 != 0) ERR_MSG("size must be even and positive"); + ERR_P(s); + ERR_P(data); + + r = s->runs; + + ResetSum(&sum); + idx = size - 2; + tlim = (endTime - startTime) * idx / size + startTime; + + while (r != NULL) { + if (startTime > r->endTime) break; + if (endTime >= r->startTime) { + t = r->endTime; + d = 0; + for (i = r->size - 1; i>=0; i--, t-=r->step) { + d = r->data[i]; + if (d == DATA_UNDEF) { + i--; + t -= (int)(r->data[i] + 0.5) * r->step; + sum.reset = 1; + } else { + if (t < startTime) break; + if (t < endTime) { + while (t < tlim) { + PutSum(&sum, data+idx); idx-=2; + tlim = (endTime - startTime) * idx / size + startTime; + } + InsSum(&sum, t, d); + } + } + } + } + r = r->next; + } + sum.reset = 1; + while (idx >= 0) { + PutSum(&sum, data+idx); idx-=2; + } + return 0; + OnError: + return -1; +} + +void Scan(void *sData, char *line) { + Set *set; + Run *run; + Base *base; + char str[64], nam[64]; + int l, iret, hh, mm, ss; + float num; + int tim, tshift, t0; + + base=((ScanData *)sData)->base; + tim=((ScanData *)sData)->tim; + + /* read time */ + l=0; iret=sscanf(line, "%d:%d:%d%n", &hh, &mm, &ss, &l); line+=l; + if (iret!=3) return; + tim+=hh*3600+mm*60+ss; + if (tim < ((ScanData *)sData)->from || tim > ((ScanData *)sData)->to) return; + + set=NULL; + l=0; iret=sscanf(line, "%64s%n", str, &l); line+=l; + while (iret==1) { + if (str[0] >= 'A') { + str_copy(nam, str); + l=0; iret=sscanf(line, "%64s%n", str, &l); line+=l; + if (iret==1) { + iret=sscanf(str, "%f", &num); + if (iret==1) { + tshift = 0; + if (0 != strcmp(nam, "_")) { + set=FindSet(base, nam); + if (set!=NULL) tshift = 1; + } + if (set!=NULL && tim < set->end) { + if (tshift) { + t0 = tim - ((ScanData *)sData)->stdStep*2; + run = set->runs; + if (run != NULL && run->endTime >= t0) { + t0 = run->endTime; + } + t0 += set->step; + if (t0 > tim) t0 = tim; + Put(set, t0, num); + } else { + Put(set, tim, num); + } + } + } + } + } else { + l=0; iret=sscanf(line, "%64s%n", str, &l); line+=l; + } + } +} + +void Load(Base *base, int from, int to, int stdStep) { + Set *set; + ScanData scanData; + int t, date; + + scanData.base = base; + scanData.stdStep = stdStep; + scanData.from = from; + scanData.to = to; + + /* round down "from" and "to" to 00:00 local time */ + from = from - (from % (24*3600)); + to = to - (to % (24*3600)); + + for (t=from; t<=to; t+=24*3600) { + scanData.tim=t; + logfileScan(mycDate(t), Scan, &scanData); + } +} + +static char *encode=DATA_CODE; + +int DataEncode(float *data, int dataSize, char *coded, int codedLen) { + int i, n, p, gap; + float minD, maxD, range; + + if (dataSize >= (codedLen-26)/2) ERR_MSG("codedLen too small"); + minD=DATA_UNDEF; + maxD=DATA_UNDEF; + for (i=0; i maxD) maxD=data[i]; + if (data[i] < minD) minD=data[i]; + } + } + } + range = maxD - minD; + if (range == 0) range=1; + ERR_SI(p=sprintf(coded, "%d %5g %5g ", dataSize, minD, range)); + gap=0; + for (i=0; i=0 && n <4096); + coded[p++]=encode[n % 64]; + coded[p++]=encode[n / 64]; + } + } + coded[p++]=','; + coded[p]='\0'; + assert(p < codedLen); + return p; + OnError: + return -1; +} + +int DataGetCoded(char *names, int startTime, int endTime, int step, int stdStep, char *coded, int codedLen) { + Base base; + Set *set, *s; + int stp, minStep, period, s1; + char *nams, nam[32]; + int p, l, n, i, j, siz1, siz2, halfsiz, start; + float data[SET_LEN]; + + base.head = NULL; + period = endTime - startTime; + n=0; nams = names; + while (nams != NULL) { + nams = str_split(nam, nams, ' '); + if (nam[0] != '\0') n++; + } + + stp=step; + if (stp startTime) { + set=CreateSet(&base, nam, NULL, stp, period, startTime); + set->end = start; + } + } + } + if (base.head != NULL) { + Load(&base, startTime, endTime, stdStep); + } + p=0; + nams=names; + coded[0]='\0'; + while (nams!=NULL) { + nams=str_split(nam, nams, ' '); + if (nam[0]!='\0') { + s = FindSet(&database, nam); + set = FindSet(&base, nam); + s1 = startTime; + if (s == NULL) { + if (set == NULL) { + s1 = 0; + } else { + s = set; + } + } else { + minStep = s->step; + if (set != NULL) { + s1 = Start(s); + if (s1 >= endTime) { + s = set; + s1 = startTime; + } else if (s1 < startTime || s1 <= Start(set)) { + s1 = startTime; + } + } + } + if (s1 == 0) { + data[0]=DATA_UNDEF; + ERR_I(l=DataEncode(data, 1, coded+p, codedLen-p)); + } else { + minStep = s->step; + stp = step; + halfsiz = period / (2 * stp) + 1; + if (startTime + minStep * halfsiz * 2 > endTime) { + if (stp < minStep) stp = minStep; + halfsiz = period / (2 * stp) + 1; + if (halfsiz * 2 > SET_LEN) halfsiz = SET_LEN / 2; + if (halfsiz * 4 + 32 * n > codedLen) { + halfsiz = ((codedLen - p) / n - 32) / 4; + } + } + siz1 = (s1 - startTime) * halfsiz / period * 2; + siz2 = halfsiz * 2 - siz1; + s1 = startTime + (siz1 * period + halfsiz) / halfsiz / 2; + if (siz1 > 0) { + ERR_I(GetSet(set, startTime, s1, siz1, data)); + } + if (siz2 > 0) { + ERR_I(GetSet(s, s1, endTime, siz2, data+siz1)); + } + ERR_I(l=DataEncode(data, siz1+siz2, coded+p, codedLen-p)); + } + p+=l; + n--; + } + } + FreeBase(&base); + return (0); + OnError: + return(-1); +} diff --git a/tecs/tecs_data.h b/tecs/tecs_data.h new file mode 100644 index 00000000..f6c5d2a8 --- /dev/null +++ b/tecs/tecs_data.h @@ -0,0 +1,47 @@ +#ifndef TECS_DATA_H_ +#define TECS_DATA_H_ + +typedef struct { + char *name; +} DataSet; + +typedef struct { + void *private; +} DataBase; + +DataSet *DataCreateSet(DataBase *dBase, char *name, float *var, int step, int lifetime, int start); +/* + create a new dataset + if the dataset already exists, or memory allocation failed, NULL is returned + set to NULL to use the common database +*/ + +DataSet *DataFindSet(DataBase *dBase, char *name); +/* + find a previously created dataset. + returns NULL if dataset not found + set to NULL to use the common database +*/ + +int DataSetStep(DataSet *set, int step); +int DataSetLifetime(DataSet *set, int lifetime); +int DataPut(DataSet *set, int time, float value); +/* + put one value to dataset +*/ + +int DataPutAll(DataBase *dBase, int time); +/* + put all variables in a set to their dataset +*/ + +int DataDecode(float *data, int dataSize, char *coded, int *retLen); +int DataGetCoded(char *names, int startTime, int endTime, int step, int stdStep, char *coded, int codedLen); + +/* + define DATA_UNDEF as a binary and decimal well defined, hopefully rarely used number +*/ +#define DATA_UNDEF MYC_NAN +#define DATA_CODE "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]abcdefghijklmnopqrstuvwxyz" + +#endif /* TECS_DATA_H_ */ diff --git a/tecs/tecs_for.f b/tecs/tecs_for.f index 608adf9f..9d2fa1e3 100644 --- a/tecs/tecs_for.f +++ b/tecs/tecs_for.f @@ -9,7 +9,7 @@ c M. Zolliker, March 2000 c Updates: c V01A 21-Mar-2000 DM. Integrate into TASMAD c 05-Apr-2000 M.Z. modifed error handling/changed arguments in TeccGet3 -c 01-May-2000 M.Z. renamed source, TECS_OPEN is now in a separate, system dependend file +c 01-May-2000 M.Z. renamed source, TECS_OPEN is now in a separate, system dependent file c V01C 11-May-2000 DM. Split into modules. c V01D 12-May-2000 M.Z. Changed error handling, no longer automatic call to TECS_OPEN c------------------------------------------------------------------------------ @@ -102,11 +102,18 @@ c extract the port number from the start command i=index(init, '-p ') if (i .eq. 0) i=index(init, '-P ') if (i .ne. 0) then - read(init,*,iostat=ios) port + read(init(min(len(init),i+3):),*,iostat=ios) port endif if (port .eq. 0) port=9753 - iret=tecs_init(init, port) + + if (init(1:1) .eq. '#') then + i=index(init, '-')-1 + if (i .le. 0) i=len(init) + else + i=len(init) + endif + iret=tecs_init(init(1:i), port) else @@ -131,7 +138,7 @@ c if INIT exists, read it to get the port number and the start command end SUBROUTINE TECS_GET_T (IOLUN, TEMP, IRET) !! -!! ============================================ +!! ========================================= !! !! Get temperatures and wait if TECS is configuring !! @@ -152,18 +159,18 @@ c------------------------------------------------------------------------------ return endif if (iret .gt. 0) then - write(iolun, *) 'configuring temperature controller ...' - iret=tecs_wait() - if (iret .lt. 0) then - call err_txt('tecs_wait'//char(10)//'tecs_get_t') - return - endif - write(iolun, *) '... done' - iret=tecs_get3(temp(1), temp(3), temp(2)) ! temp(2) and temp(3) are exchanged in MSHOWT - if (iret .lt. 0) then - call err_txt('tecs_get3(2)'//char(10)//'tecs_get_t') - return - endif +! write(iolun, *) 'configuring temperature controller ...' +! iret=tecs_wait() +! if (iret .lt. 0) then +! call err_txt('tecs_wait'//char(10)//'tecs_get_t') +! return +! endif +! write(iolun, *) '... done' +! iret=tecs_get3(temp(1), temp(3), temp(2)) ! temp(2) and temp(3) are exchanged in MSHOWT +! if (iret .lt. 0) then +! call err_txt('tecs_get3(2)'//char(10)//'tecs_get_t') +! return +! endif endif temp(4)=0.0 ! no auxilliary sensor end diff --git a/tecs/tecs_lsc.c b/tecs/tecs_lsc.c index 8e18a8f1..99097d6e 100644 --- a/tecs/tecs_lsc.c +++ b/tecs/tecs_lsc.c @@ -3,11 +3,11 @@ #include #include #include -#include "err_handling.h" +#include "myc_err.h" #include "coc_logfile.h" -#include "coc_util.h" +#include "coc_server.h" #include "tecs_lsc.h" -#include "str_util.h" +#include "myc_str.h" #define MAX_PAR 16 #define MAX_ARG 9 @@ -46,15 +46,14 @@ char *LscCmd(SerChannel *ser, const char *cmds) { char *blank, *colon, *qu, *res; const char *p, *this, *next, *cmd_ptr, *retreq; const char *list[nLIST]; - char seg[SER_BUF_LEN], buf[SER_BUF_LEN], result[SER_BUF_LEN], par[SER_BUF_LEN]; + char seg[SER_BUF_LEN], result[SER_BUF_LEN], par[SER_BUF_LEN]; char cmd[SER_BUF_LEN]; char varname[32]; - Str_Buf sbuf; + DeclStrBuf(sbuf, SER_BUF_LEN); int nres, i, j, response; nres=0; response=0; - str_link_buf(&sbuf, buf, sizeof(buf), STR_NOSEPARATOR); this=cmds; while (this!=NULL) { next=str_split(cmd, this, ';'); @@ -67,13 +66,13 @@ char *LscCmd(SerChannel *ser, const char *cmds) { } cmd_ptr=sbuf.buf+sbuf.wrpos; /* pointer to command in buffer */ p=str_split(seg, cmd, '['); - ERR_I(str_put_str(&sbuf, seg)); + ERR_I(StrPut(&sbuf, seg, StrNONE)); while (p!=NULL) { /* substitute variables */ p=str_split(varname, p, ']'); if (p==NULL) ERR_MSG("missing ']'"); - ERR_I(CocPutVar(serverVarList, &sbuf, varname, 0)); + ERR_I(CocPutVar(varname, &sbuf, StrNONE)); p=str_split(seg, p, '['); - ERR_I(str_put_str(&sbuf, seg)); + ERR_I(StrPut(&sbuf, seg, StrNONE)); } ERR_I(str_copy(cmd, cmd_ptr)); colon=strchr(cmd_ptr, ':'); @@ -86,16 +85,15 @@ char *LscCmd(SerChannel *ser, const char *cmds) { } list[nres]=colon+1; nres++; assert(nres<=nLIST); /* pointer to parameters */ list[nres]=cmd_ptr; nres++; assert(nres<=nLIST); /* pointer to command */ - ERR_I(str_put_str(&sbuf, ";")); + ERR_I(StrPut(&sbuf, ";", StrNONE)); cmd[blank-cmd_ptr]='?'; /* build query */ if (colon==blank) colon++; cmd[colon-cmd_ptr]='\0'; - ERR_I(str_put_str(&sbuf, cmd)); /* put query */ - ERR_I(str_put_str(&sbuf, ";")); + ERR_I(StrPut(&sbuf, cmd, ';')); /* put query */ response=1; } else { qu=strchr(cmd, '?'); - ERR_I(str_put_str(&sbuf, ";")); + ERR_I(StrPut(&sbuf, ";", StrNONE)); if (qu!=NULL) { /* command is a query */ response=1; if (retreq==NULL) { @@ -110,11 +108,11 @@ char *LscCmd(SerChannel *ser, const char *cmds) { } if (!response) { - ERR_I(str_put_str(&sbuf, "busy?")); + ERR_I(StrPut(&sbuf, "busy?",'\0')); } else { - buf[sbuf.wrpos-1]='\0'; /* strip off trailing ";" */ + sbuf.buf[sbuf.wrpos-1]='\0'; /* strip off trailing ";" */ } - ERR_P(res=SerCmd(ser, buf)); + ERR_P(res=SerCmd(ser, sbuf.buf)); if (0==strncmp("?TMO", res, 4)) ERR_MSG("timeout"); /* list[0..nres-1] contains a now: @@ -158,18 +156,19 @@ char *LscCmd(SerChannel *ser, const char *cmds) { } } if (retreq!=NULL) { /* query */ - str_link_buf(&sbuf, result, 0, ','); + StrLink(&sbuf, result); str_split(par, retreq+1, ';'); p=par; while (p!=NULL) { p=str_split(varname, p, ','); if (varname[0]!='\0') { if (p==NULL) { /* last element: get rest of line */ - sbuf.sep='\0'; + ERR_I(CocGetVar(varname, &sbuf, '\0')); + } else { + ERR_I(CocGetVar(varname, &sbuf, ',')); } - ERR_I(CocGetVar(serverVarList, &sbuf, varname, 0)); } else { - ERR_P(str_get_str(&sbuf, NULL)); + ERR_P(StrGet(&sbuf, varname, ',')); } } } @@ -177,3 +176,33 @@ char *LscCmd(SerChannel *ser, const char *cmds) { return(res); OnError: return(NULL); } + + +char *LscReadStat(int stat) { + if (stat &128) return("units overrange"); + if (stat & 64) return("units zero"); + if (stat & 32) return("temp overrange"); + if (stat & 16) return("temp underrange"); + if (stat & 2) return("old reading"); + if (stat & 1) return("invalid reading"); + return (""); +} + +static char + *heaterStatus[7]={ + "", + "heater supply over V", + "heater supply under V", + "heater output DAC error", + "heater Ilimit DAC error", + "open heater load", + "heater load < 10 Ohm", + }; + +char *LscHtrStat(int stat) { + if (stat<0 || stat>sizeof(heaterStatus)) { + return("unknown heater status"); + } else { + return(heaterStatus[stat]); + } +} diff --git a/tecs/tecs_lsc.h b/tecs/tecs_lsc.h index 1cace358..10db37f7 100644 --- a/tecs/tecs_lsc.h +++ b/tecs/tecs_lsc.h @@ -40,7 +40,7 @@ char *LscCmd(SerChannel *ser, const char *cmds); name="CTI5" head="R10410 ,3,+330.000E+0,2" - All used variables have to be declared with CocDef... (see coc_util.h) + All used variables have to be declared with CocDef... (see coc_server.h) */ int LscEqPar(char *par, char *res); @@ -49,4 +49,8 @@ int LscEqPar(char *par, char *res); if any parameter in par is omitted, it is not compared */ +char *LscReadStat(int stat); + +char *LscHtrStat(int stat); + #endif /* _TECS_LSC_H_ */ diff --git a/tecs/tecs_plot.f90 b/tecs/tecs_plot.f90 index f839a3f4..6a100570 100644 --- a/tecs/tecs_plot.f90 +++ b/tecs/tecs_plot.f90 @@ -1,36 +1,55 @@ -subroutine tecs_plot(file) +subroutine tecs_plot(pars, naux) - character(len=*) file + character(len=*) pars ! parameters to plot + integer naux ! number of auxiliary, non-T parameters - integer, parameter :: dmax=500, nset=3, nmenu=10, chartfreq=2 - real, parameter :: winmin=60., undef=-65535.0 + integer, parameter :: dmax=1000, nmax=5, nmenu=11, chartfreq=1 + integer, parameter :: minRange=60, maxRange=7*24*3600 + integer, parameter :: oneDay = 24*3600 + real, parameter :: winmin=60., undef=-1.125/1024./1024./1024. real*4 x1,x2,xmin,xmax,ymin(2),ymax(2),window - real*4 xd(dmax),yd(dmax,nset) + real*4 xd(dmax, nmax),yd(dmax,nmax), yy0(nmax), yy1(nmax) real*4 ylast1,ylast2,y1,y2 - real*4 ex,ey,fx,fy,hmenu,wmenu,ymenu,ticks - real*4 xbox(8), ybox(8) - integer l,j,i,t0,t1,ntot,i1,i2,rl,n,startday,thisday - integer first,last,tbase,lastj - integer color(3)/2,4,3/ + real*4 ex,ey,fx,fy,row,ticks,tim0,tim1 + integer l,j,i,n,t,leng,i1,i2,rl,startday,thisday + integer nset + integer first,last,step,tbase,lastj + integer color(nmax) + integer retLen(nmax) character key*1 character text(nmenu)*12/ & - 'live off','sel. zoom','zoom in','zoom out','show all','n days','n hours','n min','file','quit'/ - character keys*(nmenu)/'LZ+-XDHMFQ'/ - character weekdays(7)*3/'Mon','Tue','Wed','Thu','Fri','Sat','Sun'/ - character buf*8, device*8, line*40, filnam*128 + 'live off','sel. zoom','zoom in','zoom out','show all','n days','n hours','n min','date','file','quit'/ + character keys*(nmenu)/'LZ+-XDHMTFQ'/ + character weekdays(7)*4/'Mon','Tue','Wed','Thu','Fri','Sat','Sun'/ + character buf*8, device*8, name*40, filnam*128, numb*16 + character(len=16) parnam(nmax) external tplot_close + logical gap, done logical live, xwin, zoom, right, saveit - integer iret, numb, lund + integer iret, lund, numl, mon, day - integer dlog_open_r, dlog_get, dlog_close_r +! functions + integer sys_gmt_off, myc_now, myc_time, myc_date, tecs_get_data, tecs_get_mult - data window/1800./ + data window/0./ + if (window==0) window=1800. saveit=.false. zoom=.false. right=.true. call pgopen(" ") + + call pgscr(0, 1.0, 1.0, 1.0) + call pgscr(1, 0.0, 0.0, 0.0) + call pgscr(2, 1.0, 0.0, 0.0) + call pgscr(3, 0.0, 1.0, 0.0) + call pgscr(4, 0.0, 0.0, 1.0) + call pgscr(5, 0.0, 1.0, 1.0) + call pgscr(6, 1.0, 0.0, 1.0) + call pgscr(7, 1.0, 1.0, 0.0) + call pgscr(8, 1.0, 0.5, 0.0) + call pgqinf('TYPE', device, l) if (device=='NULL') then print *,'No PGPLOT-Device defined' @@ -38,72 +57,104 @@ subroutine tecs_plot(file) endif live=device(1:1)/='X' ! live switched off by default on X-Windows + nset=1 + l=1 + i=1 + do while (i <= nmax) + do while (l < len(pars) .and. pars(l:l) <= ' ') + l=l+1 + enddo + if (pars(l:l) > ' ') then + j=l + do while (l < len(pars) .and. pars(l:l) > ' ') + l=l+1 + enddo + parnam(i)=pars(j:l) + nset=i + if (l == len(pars)) i=nmax + else + i=nmax + endif + i=i+1 + enddo + call pgask(.false.) l=0 - iret=dlog_open_r(file, first, last, tbase) - if (iret<0) then - call err_txt('dlog_open_r') - goto 99 - endif - xmax=0 x1=0 + step=0 -1 if (right .or. window==0 .or. live) then - ntot=dlog_get(dmax, nset, tbase, -window*1.1, 0.0, undef, xd, yd) - if (ntot<=0) then - if (ntot<0) then - call err_txt('dlog_get') - goto 99 - endif - x2=last-tbase - else - x2=maxval(xd(1:ntot)) - endif - if (live) then - if (x1 .eq. 0) then - x1=max(x2-window,xd(1)) - else - window=x2-x1 - endif - x2=max(x1+window,x2+min(window*0.2,max(window*0.01,300.))) - elseif (window==0) then - x1=minval(xd(1:ntot)) - window=x2-x1 - else - x1=x2-window - endif +1 iret=tecs_get_mult(pars, t, nset, yy0) + if (iret < 0) goto 99 + if (window == 0) then + last=t + step=maxRange/dmax + window=maxRange + first=t-min(dmax*step-1,maxRange-step) + else if (right .or. live) then + step=window/(dmax-1)+0.99 + last=t + first=t-min(dmax*step-1,nint(window)-step) else if (.not. zoom) then x2=(x1+x2+window)/2 x1=x2-window endif - ntot=dlog_get(dmax, nset, tbase, x1-window*0.1, x2+window*0.1, undef, xd, yd) - endif - if (ntot<0) then - call err_txt('dlog_get') - goto 99 - endif - if (saveit) goto 9 - if (ntot>0) then - xmin=minval(xd(1:ntot)) - xmax=maxval(xd(1:ntot)) + if (x1 .gt. x2-minRange) x1=x2-minRange + step=(x2-x1)/(dmax-1)+0.99 + last=nint(x2)+tbase + first=nint(x1)+tbase + endif + if (step == 0) step=1 + + iret=tecs_get_data(pars, first, last, step, yd, dmax, nmax, retLen) + if (iret < 0) goto 99 +! do i=1,nmax +! if (retLen(i) > 0) nset=i +! enddo +! if (nset == 0) then +! retLen(1)=0 +! nset=1 +! endif + color(1)=2 + color(2)=4 + color(3)=3 + color(4)=5 + color(5)=8 + if (naux > 0) color(nset)=8 + + tbase=first-mod(first,7*oneDay); + x2 = last - tbase; + if (right .or. live) then + x1=x2-window else - xmin=x1 - xmax=x2 + x1 = first - tbase; + endif + tim0=t-tbase + do j=1,nset + leng=retLen(j) + do i=1,leng + xd(i,j)=(float(i-1)*(last-tbase)+float(leng-i)*(first-tbase))/(leng-1) + enddo + if (live .and. leng>0) then + xd(leng,j)=tim0 + yd(leng,j)=yy0(j) + endif + enddo + if (saveit) goto 9 + if (live) then + x2=max(tim0,x2)+min(1800., window*0.5) endif - call pgsvp(0.07,0.93,0.1,0.9) ! define window size - - if (xmax<=xmin) then - xmax=xmin+1 -! l=0 -! print *,'no points found' -! print * -! goto 9 + if (window>50*3600) then + ticks=8*3600 + elseif (window>25*3600) then + ticks=4*3600 + else + ticks=0.0 ! automatic endif - call pgsch(1.0) + i1=1 - i2=2 + i2=nset-naux do rl=1,2 if (zoom) then ymin(1)=y1 @@ -114,13 +165,13 @@ subroutine tecs_plot(file) ylast1=ymin(rl) ylast2=ymax(rl) do i=i1,i2 - do j=1,ntot - if (xd(j) >= x1 .and. xd(j) <= x2 .and. yd(j,i)/=undef) then + do j=1,retLen(i) + if (yd(j,i)/=undef) then ymin(rl)=min(ymin(rl),yd(j,i)) ymax(rl)=max(ymax(rl),yd(j,i)) endif enddo - do j=max(1,ntot-4),ntot + do j=max(1,retLen(i)-4),retLen(i) if (yd(j, i)/=undef) then ylast1=min(ylast1,yd(j, i)) ylast2=max(ylast2,yd(j, i)) @@ -130,169 +181,190 @@ subroutine tecs_plot(file) ey=(ymax(rl)-ymin(rl)) fy=abs(ymax(rl)) - if (rl==1) then - ymax(rl)=ymax(rl)+max(fy*0.0075,ey*0.25) - ymin(rl)=ymin(rl)-max(fy*0.005,ey*0.01) - else - ymax(rl)=ymax(rl)+max(fy*0.1,ey*0.01) - ymin(rl)=ymin(rl)-max(fy,ey*4) - endif + ymax(rl)=ymax(rl)+max(fy*0.0075,ey*0.01) + ymin(rl)=ymin(rl)-max(fy*0.005,ey*0.01) if (live) then ymin(rl)=min(ymin(rl),max(0.0,ylast1-ey*0.4)) ymax(rl)=max(ymax(rl),ylast2+ey*0.4) endif endif - if (ymax(rl) .lt. ymin(rl)) then - ymax(rl)=1 - ymin(rl)=0 - elseif (ymax(rl) .eq. ymin(rl)) then - ymax(rl)=ymin(rl)+1.0 + if (ymax(rl) < ymin(rl)) then + ymax(rl)=1.0 ymin(rl)=0 + elseif (ymax(rl) == ymin(rl)) then + ymax(rl)=ymin(rl)*1.00001+1.0 + ymin(rl)=-1.0e-3 endif - zoom=.false. - call pgswin(x1,x2,ymin(rl),ymax(rl)) - call pgscr(0, 1.0, 1.0, 1.0) - call pgscr(1, 0.0, 0.0, 0.0) - call pgscr(2, 1.0, 0.0, 0.0) - call pgscr(3, 0.0, 0.7, 0.0) - call pgscr(4, 0.0, 0.0, 1.0) + call set_win(rl,x1,x2,ymin(rl),ymax(rl)) - do i=i1,i2 + do i=i2,i1,-1 call pgsci(color(i)) - n=0 lastj=1 - do j=1,ntot + do j=1,retLen(i) if (yd(j,i)==undef) then - if (j>lastj) call pgline(j-lastj, xd(lastj), yd(lastj,i)) + if (j>lastj) then + call pgline(j-lastj, xd(lastj,i), yd(lastj,i)) + endif lastj=j+1 endif enddo - if (ntot .gt. lastj) call pgline(ntot+1-lastj, xd(lastj), yd(lastj,i)) + if (retLen(i) > lastj) call pgline(retLen(i)+1-lastj, xd(lastj,i), yd(lastj,i)) enddo - i1=3 - i2=3 + call pgsci(1) + if (rl == 1) then + call pgsch(1.0) + call pgtbox('ZHXYBINST', ticks, 0, 'BCINMST', 0.0, 0) + call pgtbox('C', 0.0, 0, ' ', 0.0, 0) + ey=0.0 + do i=i1,i2 + name=parnam(i) + if (name=="Tm") then + name="Main Sensor" + elseif (name=="Ts") then + name="Sample Sensor" + elseif (name=="Tr") then + name="SetPoint" + endif + call pglen(5, trim(name), fx, fy) + call pgsci(color(i)) + call pgmtxt ('L', 2.5, ey, 0.0, trim(name)) + ey=ey+fy+0.04 + enddo + call pgsci(1) + call pgmtxt ('L', 2.5, ey, 0.0, 'T [K]') + else if (naux > 0) then + call pgsch(0.7) + call pgtbox('ZCIST', ticks, 0, 'BCVINMST', 0.0, 0) + call pgtbox('B', 0.0, 0, ' ', 0.0, 0) + call pgsci(color(nset)) + call pgsch(1.0) + if (parnam(nset) == 'P' .or. parnam(nset) == 'p') then + call pgmtxt ('L', 2.5, 0.5, 0.5, 'Power [W]') + else + call pgmtxt ('L', 2.5, 0.5, 0.5, parnam(nset)) + endif + endif + i1=nset-naux+1 + i2=nset enddo - rl=2 - call pgsci(1) -! call pgtbox(' ', 0.0, 0, 'CIMST', 0.0, 0) - ey=ymax(rl)-(ymax(rl)-ymin(rl))*0.20 - call pgsch(0.7) - call pgaxis('N', x1, ey, x1, ymax(rl), ey, ymax(rl), 0, 0, 0.5, 0.0, 0.0, -1.0, 0.0) + + call pgsch(0.8) rl=1 - call pgswin(x1,x2,ymin(rl),ymax(rl)) - ey=ymax(rl)-(ymax(rl)-ymin(rl))*0.21 - call pgsch(1.0) - call pgaxis('N', x1, ymin(rl), x1, ey, ymin(rl), ey, 0, 0, 0.5, 0.0, 0.5, -1.0, 0.0) - if (window>50*3600) then - ticks=8*3600 - elseif (window>25*3600) then - ticks=4*3600 - else - ticks=0.0 ! automatic - endif - call pgtbox('ZHXYBCINST', ticks, 0, 'CIMST', 0.0, 0) - call pgmtxt ('L', 2.5, 0.4, 0.5, 'T [K]') - call pgsci(color(1)) - call pgmtxt ('L', 2.5, 0.2, 0.5, 'Main Sensor') - call pgsci(color(2)) - call pgmtxt ('L', 2.5, 0.6, 0.5, 'Sample Sensor') - call pgsci(color(3)) - call pgmtxt ('L', 2.5, 0.9, 0.5, 'Power [W]') + call set_win(rl,x1,x2,ymin(rl),ymax(rl)) + call pgsci(1) call pgsclp(0) - hmenu=(ymax(rl)-ymin(rl))/15. - ymenu=ymax(rl)+hmenu*0.5 - wmenu=(x2-x1)/(nmenu+2) if (live) then text(1)='live off' else text(1)='live on' endif - call pgsch(0.7) + ex=0.0 do i=1,nmenu - xbox(1)=x1+(i-0.7)*wmenu - ybox(1)=ymenu+hmenu - xbox(2)=xbox(1) - ybox(2)=ymenu+hmenu*0.5 - xbox(3)=x1+(i-0.95)*wmenu - ybox(3)=ybox(2) - xbox(4)=xbox(3) - ybox(4)=ybox(1) - xbox(5)=xbox(1) - ybox(5)=ybox(1) - call pgline(5, xbox, ybox) - call pgptxt(x1+(i-0.9)*wmenu, ymenu+0.65*hmenu, 0.0, 0.0, keys(i:i)) - call pgptxt(x1+(i-0.9)*wmenu, ymenu+0.15*hmenu, 0.0, 0.0, text(i)) + call pglen(5, trim(text(i)), fx, fy) + call pgmtxt('T', 3.0, ex, 0.0, '|'//keys(i:i)) + call pgmtxt('T', 2.5, ex, 0.0, '|') + call pgmtxt('T', 2.0, ex, 0.0, '|'//text(i)) + ex=ex+fx+0.01 enddo - call pgmtxt('T', 3.5, 1.0, 1.0, 'any digit to enter n') - call pgmtxt('T', 2.0, 0.9, 1.0, 'n=') - thisday=(x1+x2)/2/(24*3600) - ey=ymin(rl)-hmenu*1.5 - i=max(0,int((x1+12*3600)/(24*3600))) + call pgmtxt('T', 3.0, ex, 0.0, '|') + call pgmtxt('T', 2.5, ex, 0.0, '|') + call pgmtxt('T', 2.0, ex, 0.0, '|') + call pgmtxt('T', 3.0, 0.8, 0.0, 'any digit to enter n') + call pgmtxt('T', 2.0, 0.8, 0.0, 'n=') + + done=.false. + row=(ymax(rl)-ymin(rl))/30. + ey=ymin(rl)-row*3.5 + i=max(0,int((x1+oneDay/2)/oneDay)) + do - ex=(i+0.5)*24*3600 - if (ex>x2) EXIT - thisday=0 - call pgptxt(ex, ey, 0.0, 0.5, weekdays(mod(i,7)+1)) + ex=(i+0.5)*oneDay + if (ex > x2) EXIT + done=.true. + write(buf,'(i8.8)') myc_date(nint(ex)+tbase) + call pgptxt(ex, ey, 0.0, 0.5, weekdays(mod(i,7)+1)//buf(7:8)//'.'//buf(5:6)) ex=ex-12*3600 - if (ex .gt. x1) then + if (ex > x1) then call pgmove(ex, ey) - call pgdraw(ex, ey+hmenu/2) + call pgdraw(ex, ey+row) endif - ex=ex+24*3600 - if (ex .lt. x2) then + ex=ex+oneDay + if (ex < x2) then call pgmove(ex, ey) - call pgdraw(ex, ey+hmenu/2) + call pgdraw(ex, ey+row) endif i=i+1 enddo - if (thisday>0) then - call pgptxt((x1+x2)/2, ey, 0.0, 0.5, weekdays(mod(thisday,7)+1)) + if (.not. done) then + n=nint(x2)/oneDay*oneDay; + i=nint(x1)-n + j=nint(x2)-n + if (i < 0) then + if (-i > j) then + ex=0.0 + i=nint(x1)+tbase + else + ex=1.0 + i=nint(x2)+tbase + endif + else + ex=0.5 + i=nint(x2)+tbase + endif + thisday=mod(i/oneDay,7)+1 + write(buf,'(i8.8)') myc_date(i) +! call pgptxt((x1+x2)/2, ey, 0.0, ex, weekdays(mod(thisday,7)+1)//buf(7:8)//'.'//buf(5:6)) + call pgmtxt('B', 3.5, ex, ex, weekdays(thisday)//buf(7:8)//'.'//buf(5:6)) endif + call pgsclp(1) call get_key(key, 0, 0) ! purge buffer - numb=0 + numl=0 + numb=' ' 7 if (live) then if (device(1:1)=='X') then - call pgmtxt('T', 1.0, 1.0, 1.0, 'LIVE MODE (click on text window before pressing any further key)') + call pgmtxt('T', 0.5, 0.0, 0.0, 'LIVE MODE (click on text window before pressing any further key)') endif call get_key(key, 0, chartfreq) - do while (key .eq. char(0)) ! no key pressed - ntot=dlog_get(dmax, nset, tbase, xmax-0.5, 1e10, undef, xd, yd) - if (ntot<0) then - call err_txt('dlog_open_r 2') - goto 99 + + do while (key == char(0)) ! no key pressed + iret=tecs_get_mult(pars, t, nset, yy1) + if (iret<0) goto 99 + tim1=t-tbase + if (tim1 > x2) then + call pgpage + window=x2-x1 + goto 1 endif - if (ntot .gt. 1) then + if (tim1 > tim0) then i1=1 - i2=2 + i2=nset-naux do rl=1,2 - call pgswin(x1,x2,ymin(rl),ymax(rl)) - do i=i1,i2 - call pgsci(color(i)) - n=0 - lastj=1 - do j=1,ntot - if (yd(j,i)==undef) then - if (j>lastj) call pgline(j-lastj, xd(lastj), yd(lastj,i)) - lastj=j+1 - elseif (xd(j)>x2 .or. yd(j,i)ymax(rl)) then + call set_win(rl,x1,x2,ymin(rl),ymax(rl)) + do i=i2,i1,-1 + if (yy0(i) .ne. undef .and. yy1(i) .ne. undef) then + if (yy1(i) < ymin(rl) .or. yy1(i) > ymax(rl)) then call pgpage window=x2-x1 goto 1 endif - enddo - if (ntot .gt. lastj) call pgline(ntot+1-lastj, xd(lastj), yd(lastj,i)) + call pgsci(color(i)) + call pgmove(tim0, yy0(i)) + call pgdraw(tim1, yy1(i)) + endif + yy0(i)=yy1(i) enddo - i1=3 - i2=3 + i1=nset-naux+1 + i2=nset enddo - xmax=max(xmax,xd(ntot)) + tim0=tim1 + endif call get_key(key, 0, chartfreq) enddo @@ -301,16 +373,11 @@ subroutine tecs_plot(file) call must_purge endif rl=1 - call pgswin(x1,x2,ymin(rl),ymax(rl)) + call set_win(rl,x1,x2,ymin(rl),ymax(rl)) 8 if (key>='a') key=char(ichar(key)-32) - if (ey>ymenu) then - i=max(0,min(nmenu,int((ex-x1)/wmenu+1))) - key=keys(i:i) - ex=(x1+x2)/2 - endif if (key=='-') then - window=min(window*2, 8*24*3600.) + window=min(window*2, 8.0*oneDay) elseif (key=='X') then window=0 live=.false. @@ -319,10 +386,10 @@ subroutine tecs_plot(file) elseif (key=='Z') then call pgsci(1) if (live) then - call pgmtxt('T', 1.0, 0.0, 0.0, 'click on two opposite corners of a selection rectangle') + call pgmtxt('T', 0.5, 0.0, 0.0, 'click on two opposite corners of a selection rectangle') call pgcurs(ex, ey, key) else - call pgmtxt('T', 1.0, 0.3, 0.0, 'click on second corner of selection rectangle') + call pgmtxt('T', 0.5, 0.0, 0.0, 'click on second corner of selection rectangle') endif call pgsci(5) xmin=x1 @@ -349,16 +416,13 @@ subroutine tecs_plot(file) zoom=.true. live=.false. right=.false. - elseif (key .ge. '0' .and. key .le. '9') then - numb=numb*10+(ichar(key)-ichar('0')) - if (numb>0) then - write(buf, '(i8)') numb - l=1 - do while (buf(l:l)==' ') - l=l+1 - enddo + elseif (key >= '0' .and. key <= '9' .or. key == '.') then ! number + if (numl .lt. len(numb)) then + numl=numl+1 + numb(numl:numl)=key call pgsci(1) - call pgmtxt('T', 2.0, 0.9, 0.0, buf(l:)) + call pgsch(0.8) + call pgmtxt('T', 2.0, 0.825, 0.0, numb(1:numl)) endif if (device(1:1)=='X' .and. .not. live) then call pgcurs(ex, ey, key) @@ -368,35 +432,59 @@ subroutine tecs_plot(file) endif if (key/=char(0)) goto 8 goto 7 - elseif (key .eq. 'D') then - window=min(7*24*3600,24*3600*max(1,numb)) + elseif (key == 'D') then + ex=1 + read(numb, *, iostat=i) ex + window=min(maxRange,max(minRange, nint(oneDay*ex))) right=.true. x1=0 - elseif (key .eq. 'H') then - window=min(7*24*3600,3600*max(1,numb)) + elseif (key == 'H') then + ex=1 + read(numb, *, iostat=i) ex + window=min(maxRange,max(minRange, nint(3600*ex))) right=.true. x1=0 - elseif (key .eq. 'M') then - window=min(7*24*3600,60*max(1,numb)) + elseif (key == 'M') then + ex=1 + read(numb, *, iostat=i) ex + window=min(maxRange,max(minRange, nint(60*ex))) right=.true. x1=0 - elseif (key .eq. 'L') then + elseif (key == 'T' .or. numl>0 .and. (key==char(13) .or. key==char(10))) then + j=index(numb,'.') + day=0 + if (j > 1 .and. j < numl) then + read(numb(1:j-1), *, iostat=i) day + mon=0 + read(numb(j+1:numl), *, iostat=i) mon + tbase = myc_time(day+mon*100); + else + read(numb, *, iostat=i) day + tbase = myc_time(day); + endif + x1=0 + x2=oneDay + window=x2 + live=.false. + right=.false. + elseif (key == 'L') then live=.not. live if (live) then right=.true. - x2=xmax endif - elseif (key .eq. 'F') then + elseif (key == 'F') then saveit=.true. - elseif (key=='Q' .or. key==char(13)) then - goto 9 + elseif (key=='Q' .or. key==char(13) .or. key==char(10)) then + goto 9 + elseif (key == 'R') then elseif (live) then goto 7 endif - numb=0 + numl=0 + numb=' ' call pgpage goto 1 -99 call tecs_write_error(6) +99 call tecs_write_msg(6) 9 continue call tplot_close call get_key(key, 0, 0) ! purge type-ahead-buffer @@ -406,19 +494,35 @@ subroutine tecs_plot(file) print '(x,a,$)', 'Filename: ' read(*,'(a)') filnam open(lund, file=filnam, status='unknown', carriagecontrol='list') - write(lund, *) ' time [h]',char(9),' T1 [K]',char(9),' T2 [K]',char(9),'power [W]' - do i=1,ntot - write(line, '(4(f9.4,a))') xd(i)/3600., (char(9), max(-999.,min(9999.,yd(i,j))), j=1,3) - do j=1,3 + + gap=.false. + do j=1,nset + if (j == 1) then + write(lund, *) ' time [h]',char(9),' Tm [K]' + elseif (j == 2) then + write(lund,*) + write(lund, *) ' time [h]',char(9),' Ts [K]' + else + write(lund,*) + write(lund, *) ' time [h]',char(9), ' ',trim(parnam(j)) + endif + + do i=1,retLen(j) if (yd(i,j)==undef) then - line(10*j+1:10*j+9)=' ' + if (gap) then + write(lund, '(f9.4,2a)') xd(i,j)/3600., char(9), ' ' + gap=.false. + endif + else + write(lund, '(f9.4,a,f9.4)') xd(i,j)/3600., char(9), max(-999.,min(9999.,yd(i,j))) + gap=.true. endif enddo - write(lund, *) line(1:39) enddo close(lund) - print *, ntot+1, ' lines written to ',filnam(1:48) + print *, retLen(1)+1, ' lines written to ',filnam(1:48) endif + end subroutine subroutine get_key(key, tmo1, tmo2) @@ -439,7 +543,20 @@ entry must_purge purge=.true. end subroutine +subroutine set_win(rl, x1, x2, y1, y2) + integer rl + real x1, x2, y1, y2 + + if (rl == 1) then + call pgsvp(0.07,0.93,0.3,0.9) + else + call pgsvp(0.07,0.93,0.01,0.20) + endif + + call pgswin(x1,x2,y1,y2) +end subroutine + subroutine tplot_close call pgclos - call dlog_close_r +! call dlog_close_r end subroutine diff --git a/tecs/tecs_serial.c b/tecs/tecs_serial.c index 3d2528e2..bdeb95d8 100644 --- a/tecs/tecs_serial.c +++ b/tecs/tecs_serial.c @@ -1,27 +1,37 @@ #include +#include #include -#include +#include +#include +#include #include "rs232c_def.h" #include "asynsrv_def.h" #include "sinq_prototypes.h" #include "sys_util.h" -#include "err_handling.h" +#include "myc_err.h" #include "tecs_serial.h" #include "coc_logfile.h" -#include "str_util.h" +#include "coc_util.h" +#include "myc_str.h" +#include "myc_mem.h" -#define A_CHK(R) if (1!=(R)) { SerA_error(); ErrTxt(#R,0); goto OnError; } +#define ASYNSRV_TYPE 1 +#define TERMSRV_TYPE 2 +#define EOT '\r' -int ftime (struct timeb *__timeptr); /* for some reason not defined in timeb.h with flag -std1 */ - -void (*idleHandler)(int,int); - -struct SerChan { +typedef struct { + int type; /* = ASYNSRV_TYPE */ struct AsynSrv__info asyn_info; /* Contains skt, host, port & chan */ struct RS__MsgStruct to_host; struct RS__RespStruct from_host; - char cmd[SER_BUF_LEN]; -}; +} AsynSrvChan; + +typedef struct { + int type; /* = TERMSRV_TYPE */ + char res[SER_BUF_LEN]; + int fd, tmo; + int (*idleHdl)(int,int); +} TermSrvChan; void SerA_error(void) { char *a_txt; @@ -31,43 +41,182 @@ void SerA_error(void) { ErrMsg("asynsrv error"); ErrTxt(a_txt,0); } -SerChannel *SerOpen(const char *host, int msecTmo, void (*idleHdl)(int,int)) { - struct SerChan *ser; - char hbuf[64], cport[16]; - char *p, *c; - int port, chan, iRet; +int SerWait(int tmo_msec, int fd) { + struct timeval tmo; + fd_set mask; + int i; + + FD_ZERO(&mask); + FD_SET(fd, &mask); + tmo.tv_sec=tmo_msec / 1000; + tmo.tv_usec=(tmo_msec % 1000) % 1000 +1; + ERR_SI(i=select(fd+1,&mask,NULL,NULL,&tmo)); + if (i==0) return(0); /* timeout */ + return(1); + OnError: return(-1); +} - idleHandler=idleHdl; - NEW(ser); - str_copy(hbuf, host); - p=str_split(ser->asyn_info.host, hbuf, ':'); - port=4000; - chan=0; - if (p!=NULL) { - c=str_split(cport, p, '/'); - if (c!=NULL) chan=atoi(c); - port=atoi(cport); - } - ser->asyn_info.port=port; - ser->asyn_info.chan=chan; - A_CHK(AsynSrv_Open(&ser->asyn_info)); +SerChannel *SerOpen(const char *hostPort, int msecTmo, int (*idleHdl)(int,int)) { + AsynSrvChan *aser; + TermSrvChan *tser; + char hbuf[64], cport[16], host[32]; + char *p, *c; + struct sockaddr_in sadr; + int iret; + time_t t1, t2; + static int ecnt; + + time(&t1); + str_copy(hbuf, hostPort); + p=str_split(host, hbuf, ':'); + assert(p!=NULL); + c=str_split(cport, p, '/'); if (msecTmo==0) msecTmo=5000; - A_CHK(AsynSrv_Config(&ser->asyn_info, "msecTmo", msecTmo, "idleHdl", idleHdl, NULL)); - logfileOut(LOG_MAIN, "connection to %s:%d/%d opened\n", ser->asyn_info.host, ser->asyn_info.port, ser->asyn_info.chan); - return((SerChannel *)ser); + if (c!=NULL) { + NEW(aser, AsynSrvChan); aser->type=ASYNSRV_TYPE; + str_copy(aser->asyn_info.host, host); + aser->asyn_info.port=atoi(cport); + aser->asyn_info.chan=atoi(c); + + iret=AsynSrv_Open(&aser->asyn_info); + if (iret==1) { + iret=AsynSrv_Config(&aser->asyn_info, "msecTmo", msecTmo, "idleHdl", idleHdl, NULL); + } + if (iret!=1) { + SerA_error(); + goto OnError; + } + time(&t2); + ecnt=0; + logfileOut(LOG_MAIN, "connection to %s:%d/%d opened (%d sec)\n", + aser->asyn_info.host, aser->asyn_info.port, aser->asyn_info.chan, + t2-t1); + return((SerChannel *)aser); + } else { + NEW(tser, TermSrvChan); tser->type=TERMSRV_TYPE; + tser->tmo=msecTmo; + if (idleHdl==NULL) { + tser->idleHdl=SerWait; + } else { + tser->idleHdl=idleHdl; + } + ERR_I(CocCreateSockAdr(&sadr, host, atoi(p))); + ERR_SI(tser->fd=socket(AF_INET, SOCK_STREAM, 0)); + /* do we need this really as a client ? + i = 1; + ERR_SI(setsockopt(conn->fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))); + */ /* allow quick port reuse */ + ERR_SI(connect(tser->fd, (struct sockaddr *)&sadr, sizeof(sadr))); + time(&t2); + ecnt=0; + logfileOut(LOG_MAIN, "connected to %s (%d sec)\n", hostPort, t2-t1); + return ((SerChannel *)tser); + } + OnError: + time(&t2); + if (ecnt<4) { + logfileOut(LOG_MAIN, "failed after %d sec\n", t2-t1); + ecnt++; + } + return(NULL); +} + +void SerClose(SerChannel *serch) { + AsynSrvChan *aser; + TermSrvChan *tser; + + if (serch->type==ASYNSRV_TYPE) { + aser=(AsynSrvChan *)serch; + AsynSrv_Close(&aser->asyn_info, 0); + } else if (serch->type==TERMSRV_TYPE) { + tser=(TermSrvChan *)serch; + close(tser->fd); + } + serch->type=0; +} + +SerChannel *SerCheck(SerChannel *serch) { + if (serch==NULL || serch->type==0) { + return(NULL); + } else { + return(serch); + } +} + +char *SerCmd(SerChannel *serch, char *cmnd) { + int l, n; + AsynSrvChan *aser; + TermSrvChan *tser; + char *result, *pos, *trm; + int iret, incomplete; + + l=strlen(cmnd); + if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS); + cmnd[l]=EOT; l++; + cmnd[l]='\0'; + + logfileOut(LOG_SER, ">%s\n", cmnd); + if (serch->type==ASYNSRV_TYPE) { + aser=(AsynSrvChan *)serch; + iret=AsynSrv_SendCmnds(&aser->asyn_info, &aser->to_host, &aser->from_host, cmnd, NULL); + if (iret!=1) { + SerA_error(); + SerClose(serch); + return(NULL); + } + result=AsynSrv_GetReply(&aser->asyn_info, &aser->from_host, NULL); + if (result==NULL) ERR_MSG("empty result"); + } else if (serch->type==TERMSRV_TYPE) { + tser=(TermSrvChan *)serch; + iret=send(tser->fd, cmnd, l, 0); + if (iret<0) { + ErrMsg("disconnected"); + SerClose(serch); + goto OnError; + } + n=sizeof(tser->res); + pos=tser->res; + result=NULL; + incomplete=1; + while (incomplete) { + /* Wait for an event on tser->fd or a timeout tmo */ + iret=tser->idleHdl(tser->tmo, tser->fd); + if (iret==0) { + if (result==NULL) ERR_MSG("time out"); + ERR_MSG("missing terminator"); + } + ERR_SI(l=recv(tser->fd, pos, n, 0)); + if (l==0) { + ErrMsg("disconnected"); + SerClose(serch); + goto OnError; + } + n -= l; + if (n==0) ERR_MSG("answer too long"); + while (l>0) { + if (*pos>' ') { + if (result==NULL) result=pos; /* skip trailing white space */ + } else if (*pos<' ') { /* all control characters are treated as terminators */ + if (result!=NULL) { + *pos='\0'; + incomplete=0; + } + } + pos++; l--; + } + } + } else { + serch->type=0; + ERR_MSG("invalid channel"); + } + logfileOut(LOG_SER, "<%s\n", result); + + return(result); OnError: return(NULL); } -int SerClose(SerChannel *serch) { - struct SerChan *ser; - - ser=(struct SerChan *)serch; - A_CHK(AsynSrv_Close(&ser->asyn_info, 0)); - return(0); - OnError: return(-1); -} - +/* obsolete ? char *SerCmdC(SerChannel *serch, const char *cmnd) { char cmd[SER_BUF_LEN]; int l; @@ -78,33 +227,5 @@ char *SerCmdC(SerChannel *serch, const char *cmnd) { return(SerCmd(serch, cmd)); OnError: return(NULL); } +*/ -char *SerCmd(SerChannel *serch, char *cmnd) { - int l; - struct SerChan *ser; - char *result; - struct timeb tim0, tim1; - int tdif; - - l=strlen(cmnd); - if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS); - - ser=(struct SerChan *)serch; - logfileOut(LOG_SER, ">%s\n", cmnd); - cmnd[l]=ser->asyn_info.eot[1]; - cmnd[l+1]='\0'; - ftime(&tim0); - A_CHK(AsynSrv_SendCmnds(&ser->asyn_info, &ser->to_host, &ser->from_host, cmnd, NULL)); - result=AsynSrv_GetReply(&ser->asyn_info, &ser->from_host, NULL); - ftime(&tim1); - tdif=(tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm; - if (result==NULL) ERR_MSG("empty result"); - /* if (idleHandler!=NULL) idleHandler(50,0); */ - logfileOut(LOG_SER, "<%s\n", result); - if (tdif>1000) { - logfileOut(LOG_SER, "%d msec:\n >%s\n", tdif, cmnd); - logfileOut(LOG_SER, " <%s\n", result); - } - return(result); - OnError: return(NULL); -} diff --git a/tecs/tecs_serial.h b/tecs/tecs_serial.h index b1fa5e35..75a8c1f0 100644 --- a/tecs/tecs_serial.h +++ b/tecs/tecs_serial.h @@ -3,11 +3,16 @@ #define SER_BUF_LEN 320 -typedef struct { int private; } SerChannel; +typedef struct { + /* private */ + int type; +} SerChannel; -SerChannel *SerOpen(const char *host, int msecTmo, void (*idleHdl)(int,int)); -char *SerCmdC(SerChannel *ser, const char *cmnd); +SerChannel *SerOpen(const char *host, int msecTmo, int (*idleHdl)(int,int)); char *SerCmd(SerChannel *ser, char *cmnd); -int SerClose(SerChannel *ser); +SerChannel *SerCheck(SerChannel *ser); +void SerClose(SerChannel *ser); + +/* char *SerCmdC(SerChannel *ser, const char *cmnd); */ #endif /* _SERUTIL_H_ */