From b9b30e7d62818971aa583a6c48be624bfd604fe2 Mon Sep 17 00:00:00 2001 From: cvs Date: Wed, 15 Mar 2000 11:29:50 +0000 Subject: [PATCH] *** empty log message *** --- tecs/asynsrv_errcodes.h | 34 ++ tecs/dlog.h | 49 +++ tecs/logfile.h | 14 + tecs/lsc.h | 32 ++ tecs/rs232c_def.h | 176 +++++++++ tecs/serutil.h | 8 + tecs/server.c | 226 +++++++++++ tecs/server.h | 35 ++ tecs/sinq_prototypes.h | 43 +++ tecs/tcli.c | 53 +++ tecs/tecc.h | 10 +- tecs/tecs.c | 803 ++++++++++++++++++++++++++++++++++++++++ tecs/util.h | 16 +- tecsdriv.h | 25 ++ 14 files changed, 1518 insertions(+), 6 deletions(-) create mode 100644 tecs/asynsrv_errcodes.h create mode 100644 tecs/dlog.h create mode 100644 tecs/logfile.h create mode 100644 tecs/lsc.h create mode 100644 tecs/rs232c_def.h create mode 100644 tecs/serutil.h create mode 100644 tecs/server.c create mode 100644 tecs/server.h create mode 100644 tecs/sinq_prototypes.h create mode 100644 tecs/tcli.c create mode 100644 tecs/tecs.c create mode 100644 tecsdriv.h diff --git a/tecs/asynsrv_errcodes.h b/tecs/asynsrv_errcodes.h new file mode 100644 index 00000000..2ca38057 --- /dev/null +++ b/tecs/asynsrv_errcodes.h @@ -0,0 +1,34 @@ +/* +** TAS_SRC:[LIB]ASYNSRV_ERRCODES.H +** +** Include file generated from ASYNSRV_ERRCODES.OBJ +** +** 25-NOV-1999 14:40:45.57 +*/ + +#define ASYNSRV__NO_ROOM 0x86480CC +#define ASYNSRV__FORCED_CLOSED 0x86480C4 +#define ASYNSRV__BAD_SOCKET 0x86480BC +#define ASYNSRV__BAD_SEND_UNKN 0x86480B4 +#define ASYNSRV__BAD_SEND_PIPE 0x86480AC +#define ASYNSRV__BAD_SEND_NET 0x86480A4 +#define ASYNSRV__BAD_SEND_LEN 0x864809C +#define ASYNSRV__BAD_SEND 0x8648094 +#define ASYNSRV__BAD_REPLY 0x864808C +#define ASYNSRV__BAD_RECV1_PIPE 0x8648084 +#define ASYNSRV__BAD_RECV1_NET 0x864807C +#define ASYNSRV__BAD_RECV1 0x8648074 +#define ASYNSRV__BAD_RECV_UNKN 0x864806C +#define ASYNSRV__BAD_RECV_PIPE 0x8648064 +#define ASYNSRV__BAD_RECV_NET 0x864805C +#define ASYNSRV__BAD_RECV_LEN 0x8648054 +#define ASYNSRV__BAD_RECV 0x864804C +#define ASYNSRV__BAD_PROT_LVL 0x8648044 +#define ASYNSRV__BAD_PAR 0x864803C +#define ASYNSRV__BAD_NOT_BCD 0x8648034 +#define ASYNSRV__BAD_HOST 0x864802C +#define ASYNSRV__BAD_FLUSH 0x8648024 +#define ASYNSRV__BAD_CONNECT 0x864801C +#define ASYNSRV__BAD_CMND_LEN 0x8648014 +#define ASYNSRV__BAD_BIND 0x864800C +#define ASYNSRV__FACILITY 0x864 diff --git a/tecs/dlog.h b/tecs/dlog.h new file mode 100644 index 00000000..9a0c4db1 --- /dev/null +++ b/tecs/dlog.h @@ -0,0 +1,49 @@ +#include + +#define DLOG_MAX_SET 32 + +typedef struct { + time_t last, start; + float version, undef; + int period, headsize, fsize, nset, nlen; + int fd, pos; + char name[128]; +} DlogSet; + + +int DlogOpen(DlogSet *dset, char *name, int write); +/* open existing dlog set */ + +int DlogCreate(DlogSet *dset, char *name, time_t start, int nset, int nlen, int period, float undef); +/* create new dlog file */ + +int DlogPut(DlogSet *dset, time_t time, int nset, float val[]); +/* put values to dlog set */ + +int DlogGet(DlogSet *dset, int iset, int nmax, double *starttime, float *x, float *y); +/* get one dataset from dlog set + + iset is the dataset to be returned + nmax is the maximal number of points to be returned + x, y: the data (arrays declared with at least nmax elements) + + on success, the return value is the effective length of returned data +*/ + +int DlogGetMany(DlogSet *dset, int nset, int nmax, double *starttime, float x[], float y[], int index[]); +/* get many datasets from dlog set + + nset is the nember of datasets to be returned + nmax is the maximal number of points to be returned + x, y: the data, one dataset after an other (arrays declared with at least nmax elements) + index must be an array of at least nset elements. + it returns the start indices in x[] and y[] of the data sets. + + on success, the return value is the effective length of returned data +*/ + +int DlogUpd(DlogSet *dset); +/* update pointer */ + +int DlogClose(DlogSet *dset); +/* close dlog set */ diff --git a/tecs/logfile.h b/tecs/logfile.h new file mode 100644 index 00000000..a4b495b8 --- /dev/null +++ b/tecs/logfile.h @@ -0,0 +1,14 @@ +#include "buf.h" + +void logfileInit(char *path, int nodate); +void logfileUpd(); +void logfileStamp(char *text); +void logfileOut(char *fmt, ...); +void logfileOutTmp(char *fmt, ...); +void logfileOutBuf(buf_type *buf); +void logfileShowErr(char *text); +void logfilePurge(); +void logfileWriteTmp(); +void logfileClose(); + +extern int logfileStd; diff --git a/tecs/lsc.h b/tecs/lsc.h new file mode 100644 index 00000000..eb9fc9f8 --- /dev/null +++ b/tecs/lsc.h @@ -0,0 +1,32 @@ +#include "serutil.h" +#define LSC_MAX_CMDS 5 + +int LscCmdChk(SerChannel *ser, char *cmds); +int LscCmdChkC(SerChannel *ser, const char *cmds); +/* + send one or several commands and check it's parameters + a colon must separate the parameters + attention: + in LscCmdChk, *cmds will be modified (more efficient) + in LscCmdChkC, *cmds must not be longer than 127 chars +*/ + +int LscEqPar(char *par, char *res); +/* + compare if parameters are equal (numbers as numbers, spaces ignored) +*/ + +struct { struct LscElem *next; char *cmnd; } LscElem; +typedef struct { struct LscElem *head, *tail; } LscList; + +int LscPushCmd(LscList clist, char *cmnd); +/* + push a command on th command list. If cmnd points to a temporary buffer, + strdup() must be used. +*/ + +int LscNextCmd(SerChannel *ser, LscList clist); +/* + strip one line from LscList, and send it through LscCmdChk + the list and the command buffers are freed when no longer used +*/ diff --git a/tecs/rs232c_def.h b/tecs/rs232c_def.h new file mode 100644 index 00000000..5fac974d --- /dev/null +++ b/tecs/rs232c_def.h @@ -0,0 +1,176 @@ +#ifndef _rs232c_def_ +#define _rs232c_def_ +/*------------------------------------------------ RS232C_DEF.H Ident V02F +** Definitions for the RS-232-C Server Protocol +** +** On UNIX systems, this file is located in /public/lib/include +** On VMS systems, this file is a module in mad_lib:sinq_c.tlb +*/ +#define RS__PROTOCOL_ID "V01A" +#define RS__PROTOCOL_ID_V01B "V01B" + +#define RS__PROTOCOL_CODE 1 /* Code corresponding to RS__PROTOCOL_ID */ +#define RS__PROTOCOL_CODE_V01B 2 /* Code corresponding to RS__PROTOCOL_ID_0 */ + +#ifndef OffsetOf +#define OffsetOf(type, identifier) ((size_t)(&((type*) NULL)->identifier)) +#endif +/*---------------------------------------------------------------------------- +** Structure of Message from Client to Server - everything is sent in ASCII +** for LabView's benefit. +** Name #bytes Description +** ==== ====== =========== +** msg_size 4 Number of bytes following (rounded up to multiple +** of 4). +** msg_id 4 Message ident (an incrementing counter for debugging). +** c_pcol_lvl 4 Client-Protocol-Level (should be "V01A"). +** serial_port 4 Serial port to which commands should be sent. This +** is a small integer). +** tmo 4 Time-out in units of 0.1 secs (<0 = "wait for ever"). +** terms 1 + 3 Terminators. The first char gives the number of +** terminators (up to 3) and the following 3 chars +** are valid response terminators, e.g. "1\r\0\0". +** n_cmnds 4 Number of commands following. +** cmnds 356 The command buffer. This is a concatenated list of +** commands with the structure described below. +** +** Structure of a command item in the cmnds buffer. +** +** a) RS__PROTOCOL_ID = "V01A" +** +** Name #bytes Description +** ==== ====== =========== +** cmnd_len 2 The number of bytes following encoded as 2 ASCII +** decimal chars. +** cmnd The command to be sent on Serial Port . +** The string should contain any required terminator +** bytes but should not be zero-terminated (unless +** the zero-byte should be transmitted at the end +** of the command). cmnd_len should count the +** terminator byte. +** +** An example of a command item might be: "06RMT 1\r" +** +** b) RS__PROTOCOL_ID = "V01B" +** +** Name #bytes Description +** ==== ====== =========== +** cmnd_len 4 The number of bytes following encoded as 4 ASCII +** decimal chars. +** cmnd The command to be sent on Serial Port . +** The string should contain any required terminator +** bytes but should not be zero-terminated (unless +** the zero-byte should be transmitted at the end +** of the command). should count the +** terminator byte. +** +** An example of a command item might be: "0006RMT 1\r" +**--------------------------------------------------------------------------*/ + struct RS__MsgStruct { + char msg_size[4]; /* 4 ASCII decimal chars!! */ + char msg_id[4]; + char c_pcol_lvl[4]; /* Client protocol level */ + char serial_port[4]; + char tmo[4]; /* Units are 0.1 secs */ + char terms[4]; + char n_cmnds[4]; + char cmnds[356]; + }; + /* + ** The "cmnds" buffer in RS__MsgStruct is a concatenated + ** list of the following structures. + */ + struct RS__CmndStruct { + char cmnd_len[2]; + char cmnd[1]; + }; + struct RS__CmndStruct_V01B { + char cmnd_len[4]; + char cmnd[1]; + }; +/*---------------------------------------------------------------------------- +** Structure of Reply from Server to Client - everything is sent in ASCII +** for LabView's benefit. +** +** Name #bytes Description +** ==== ====== =========== +** msg_size 4 Number of bytes following (rounded up to multiple +** of 4). +** msg_id 4 Message ident (this is a copy of the msg_id field +** in the message from Client to Server). +** s_pcol_lvl 4 Server-Protocol-Level (should be "V01A" or "V01B"). +** n_rply 4 Number of replies following. If < 0, an error has +** been detected and sub_status may give additional +** information. +** rplys 496 The reply buffer. This is a concatenated list of +** replies with the structure described below. +** sub_status 12 A sub-status code. This field overlays the first 12 +** bytes of rplys and may provide additional +** information in the case that n_rply < 0. +** +** Structure of a reply item in the rplys buffer. +** +** a) RS__PROTOCOL_ID = "V01A" +** +** Name #bytes Description +** ==== ====== =========== +** rply_len 2 The number of bytes following encoded as 2 ASCII +** decimal chars. +** term 1 The terminating character which was detected at the +** end of the reply. This will be one of the +** characters specified in . +** rply The zero-terminated reply. This is effectively the +** reply as received with the terminating character +** replaced by '\0'. +** +** An example of a reply item might be: "08\r12.345\0" +** +** b) RS__PROTOCOL_ID = "V01B" +** +** Name #bytes Description +** ==== ====== =========== +** rply_len 4 The number of bytes following encoded as 4 ASCII +** decimal chars. +** term 1 The terminating character which was detected at the +** end of the reply. This will be one of the +** characters specified in . +** rply The zero-terminated reply. This is effectively the +** reply as received with the terminating character +** replaced by '\0'. +** +** An example of a reply item might be: "0009\r12.3456\0" +**--------------------------------------------------------------------------*/ + struct RS__RespStruct { + char msg_size[4]; + char msg_id[4]; + char s_pcol_lvl[4]; /* Server protocol level */ + char n_rply[4]; /* Error if < 0 */ + union { + char rplys[496]; + char sub_status[12]; + } u; + }; + /* + ** The "rplys" buffer in RS__RespStruct is a + ** concatenated list of the following structures. + */ + struct RS__RplyStruct { + char rply_len[2]; /* 2 ASCII decimal chars!! + ** The length includes the + ** terminator, term, and the + ** zero terminator of rply. + */ + char term; /* The terminating character */ + char rply[1]; /* Zero terminated string */ + }; + struct RS__RplyStruct_V01B { + char rply_len[4]; /* 4 ASCII decimal chars!! + ** The length includes the + ** terminator, term, and the + ** zero terminator of rply. + */ + char term; /* The terminating character */ + char rply[1]; /* Zero terminated string */ + }; +/*------------------------------------------------ End of RS232C_DEF.H --*/ +#endif /* _rs232c_def_ */ diff --git a/tecs/serutil.h b/tecs/serutil.h new file mode 100644 index 00000000..21f5e5c4 --- /dev/null +++ b/tecs/serutil.h @@ -0,0 +1,8 @@ +#define SER_BUF_LEN 320 + +typedef struct { int private; } SerChannel; + +SerChannel *SerOpen(const char *host, int logIt, int msecTmo, void (*idleHdl)(int,int)); +char *SerCmdC(SerChannel *ser, const char *cmnd); +char *SerCmd(SerChannel *ser, char *cmnd); +int SerClose(SerChannel *ser); diff --git a/tecs/server.c b/tecs/server.c new file mode 100644 index 00000000..03b7734f --- /dev/null +++ b/tecs/server.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include "logfile.h" +#include "server.h" +#include "util.h" + +static buf_type *buf, *bufo; + +static fd_set mask, rmask; +static int maxfd; +struct CocClient *cList, *cLastCmd=NULL; +static int mainFd; + +int CocInitServer(int bufsize, int port) { + int i; + struct sockaddr_in sadr; + char *err; + + if (bufsize==0) bufsize=1024; + buf=buf_create(bufsize); + bufo=buf_create(bufsize); + cList=malloc(sizeof(*cList)); /* empty header */ + + /* first try to connect to an existing server */ + + logfileStamp("start server"); + + 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))); + logfileOut("created server on port %d\n", port); + ERR_SI(listen(mainFd, SOMAXCONN)); + FD_ZERO(&mask); + FD_SET(mainFd, &mask); + maxfd=mainFd+1; + logfileUpd(); + return(0); + OnError: return(-1); +} + +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, status; + size_t cadrlen; + char *err, *varname; + + status=3; + rmask=mask; + if (fd>0) FD_SET(fd, &rmask); + tmo.tv_sec=tmo_msec / 1000; + tmo.tv_usec=(tmo_msec % 1000)*1000+1; + if (fd>=maxfd) maxfd=fd+1; + ERR_SI(i=select(maxfd,&rmask,NULL,NULL,&tmo)); + if (fd>0 && FD_ISSET(fd, &rmask)) return(1); + + logfileStamp(""); + if (FD_ISSET(mainFd, &rmask)) { + ERR_SI(newfd=accept(mainFd, (struct sockaddr *)&cadr, &cadrlen)); + FD_SET(newfd, &mask); + if (newfd>=maxfd) maxfd=newfd+1; + cl=cList; + cl->fd=newfd; + cl->mode=0; + cl->cmd[0]='\0'; + cl->res[0]='\0'; + cList=malloc(sizeof(*cList)); + cList->next=cl; + h=gethostbyaddr(&cadr.sin_addr, 4, AF_INET); + if (h==NULL) { + logfileOut("(%d) open from %s\n", newfd, "local"); + } else { + logfileOut("(%d) open from %s\n", newfd, h->h_name); + } + logfileUpd(); + } else { + cl0=cList; cl=cl0->next; + while (cl!=NULL) { + if (FD_ISSET(cl->fd, &rmask)) { + buf->usize=recv(cl->fd, buf->start, buf->isize, 0); + if (buf->usize<=0) { + logfileOut("(%d) disconnected\n",cl->fd); + close(cl->fd); + FD_CLR(cl->fd, &mask); + cl0->next=cl->next; + free(cl); + cl=cl0; + } else { + if (buf->usize<0) ERR_MSG("usize negative"); + + buf_put_start(bufo); + buf_put_str(bufo, ""); /* empty error message */ + setmode=0; + buf_reset(buf); + err=NULL; + varname=buf_get_str(buf); + logfileOutTmp("(%d) ", cl->fd); + if (varname[0]=='#') { /* access code */ + if (0==strcmp(varname,"#rdacc")) { + logfileOutTmp(" set read mode"); + cl->mode=1; + } else if (0==strcmp(varname,"#rwacs")) { + logfileOutTmp(" set write mode"); + 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 */ + str_copy(cl->cmd, buf_get_str(buf)); + cl->res[0]='\0'; + } else { + i=CocGetVar(serverVarList, buf, varname); + if (i<0) { err=ErrMessage; break; } + } + status=2; + } else { + if (0==strcmp("$", varname)) { /* special case: response */ + buf_put_str(bufo, cl->res); + cl->res[0]='\0'; + } else { + i=CocPutVar(serverVarList, bufo, varname); + if (i<0) { err=ErrMessage; break; } + } + } + i=buf_size(buf); + if (i<=0) { + if (i<0) err="type mismatch"; + break; + } + varname=buf_get_str(buf); + if (buf_size(buf)<0) { err="syntax error"; break; } + } + buf_reset(buf); + logfileOutBuf(buf); + } + buf_put_end(bufo); + logfileOutTmp(" |"); + logfileOutBuf(bufo); + if (err==NULL) { + logfileOutTmp("\n"); + } else { + buf_put_start(bufo); /* reset output */ + buf_put_str(bufo, err); /* put error message */ + buf_put_end(bufo); + logfileOutTmp(" (%s)\n", err); + } + ERR_SI(send(cl->fd, bufo->buf, bufo->size, 0)); + } + } + cl0=cl; cl=cl->next; + } + logfileUpd(); + } + return(status); + OnError: return(-1); +} + +int CocHandleRequests(int tmo_msec, int fd) { + struct timeb tim1, tim0; + int tdif, iret; + + ftime(&tim0); + tdif=tmo_msec; + while (tdif>=0) { + ERR_I(iret=CocHandle1Request(tdif, fd)); + if (iret==2 && fd==0) return(iret); /* a variable was changed */ + if (iret!=3) return(iret); /* event on fd or timeout */ + ftime(&tim1); + tdif=tmo_msec-((tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm); + } + 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; + + cl=cList->next; + while (cl!=NULL) { + close(cl->fd); + cl0=cl; + cl=cl->next; + free(cl0); + } + free(cList); + close(mainFd); + buf_free(buf); buf_free(bufo); + logfileClose(); +} diff --git a/tecs/server.h b/tecs/server.h new file mode 100644 index 00000000..aa75eb89 --- /dev/null +++ b/tecs/server.h @@ -0,0 +1,35 @@ +#include "coc.h" + +struct CocClient { struct CocClient *next; int fd; int mode; char cmd[80]; char res[80]; }; + +int CocInitServer(int bufsize, int port); + +int CocHandleRequests(int tmo_msec, int fd); +int CocHandle1Request(int tmo_msec, int fd); +/* + handle hetwork requests. + + return value: <0: error + =0: error + =1: event on fd + =2: variable was changed + =3: other network request treated + + CocHandle1Request handles only one network request + + For CocHandleRequests: + + if fd=0: returns when a network request has changed a variable, + or when timeout has expired + + if fd>0: returns when an read event is pending on fd + or when timeout has expired + +*/ + +struct CocClient *CocGetNextCmd(); +/* + get next client with a pending command +*/ + +void CocCloseServer(); diff --git a/tecs/sinq_prototypes.h b/tecs/sinq_prototypes.h new file mode 100644 index 00000000..fbcd288f --- /dev/null +++ b/tecs/sinq_prototypes.h @@ -0,0 +1,43 @@ +/* ---------------------------------------------------------------------*/ + int AsynSrv_Close ( + struct AsynSrv__info *asyn_info, + int force_flag); + int AsynSrv_Config ( + struct AsynSrv__info *asyn_info, + ...); + int AsynSrv_ConfigDflt ( + char *par_id, + ...); + void AsynSrv_ErrInfo ( + char **entry_txt, + int *errcode, + int *my_errno, + int *vaxc_errno); + char *AsynSrv_GetReply ( + struct AsynSrv__info *asyn_info, + struct RS__RespStruct *rcve_buff, + char *last_rply); + int AsynSrv_Open ( + struct AsynSrv__info *asyn_info); + int AsynSrv_SendCmnds ( + struct AsynSrv__info *asyn_info, + struct RS__MsgStruct *send_buff, + struct RS__RespStruct *rcve_buff, + ...); + int AsynSrv_SendCmndsBig ( + struct AsynSrv__info *asyn_info, + struct RS__MsgStruct *send_buff, + int send_buff_size, + struct RS__RespStruct *rcve_buff, + int rcve_buff_size, + ...); + + void GetErrno ( + int *his_errno, + int *his_vaxc_errno); + + char *StrJoin ( + char *result, + int result_size, + char *str_a, + char *str_b); diff --git a/tecs/tcli.c b/tecs/tcli.c new file mode 100644 index 00000000..2fe56648 --- /dev/null +++ b/tecs/tcli.c @@ -0,0 +1,53 @@ +#include +#include +#include "tecc.h" +#include "errhdl.h" + +/*-------------------------------------------------------------------------*/ + +main(int argc, char *argv[]) +{ + char response[80], cmd[80], device[80]; + float val; + pTecsClient conn; + char *res; + +#ifdef __VMS + ERR_P(conn=TeccInit("@start_tecs -p 9753 -l -d [.log]", 9753)); +#else + ERR_P(conn=TeccInit("TecsServer -p 9753 -l -d log/ &", 9753)); +#endif + +retry: + while (1) { + scanf("%s", cmd); + if (0==strcmp(cmd,"r")) { + ERR_I(TeccGet(conn, &val)); + ERR_P(res=TeccGetDev(conn)); + printf("T=%f %s\n", val, res); + + } else if (0==strcmp(cmd,"s")) { + + scanf("%f", &val); + ERR_I(TeccSet(conn, val)); + + } else if (0==strcmp(cmd,"c")) { + + scanf("%s", cmd); + ERR_I(TeccSend(conn, cmd, response, sizeof(response))); + printf("%s\n", response); + + } else if (0==strcmp(cmd,"d")) { + + scanf("%s", cmd); + ERR_I(TeccSetDev(conn, cmd)); + + } else if (0==strcmp(cmd,"q")) { + + TeccClose(conn); + exit(1); + + } + } + OnError: ErrShow("Client"); goto retry; +} diff --git a/tecs/tecc.h b/tecs/tecc.h index e0e3a8cc..4fc2fdf4 100644 --- a/tecs/tecc.h +++ b/tecs/tecc.h @@ -1,14 +1,16 @@ +#include "client.h" /* tecc.h: tecs client interface routines M. Zolliker March 2000 ------------------------------------------------------------------------*/ -typedef struct { int tecc_private; } *pTecsClient; +typedef CocConn *pTecsClient; +/* typedef struct { int tecc_private; } *pTecsClient; */ /* hidden structure for a tecs client ------------------------------------------------------------------------*/ -pTecsClient TeccInit(char *server); +pTecsClient TeccInit(char *server, int port); /* init tecs client (connect to server) ------------------------------------------------------------------------*/ @@ -37,3 +39,7 @@ void TeccClose(pTecsClient conn); /* close connection and free ressources ------------------------------------------------------------------------*/ +int TeccKillServer(pTecsClient conn); +/* kill the server process +------------------------------------------------------------------------*/ + diff --git a/tecs/tecs.c b/tecs/tecs.c new file mode 100644 index 00000000..551c2144 --- /dev/null +++ b/tecs/tecs.c @@ -0,0 +1,803 @@ +#include +#include +#include +#include +#include "server.h" +#include "logfile.h" +#include "util.h" +#include "lsc.h" +#include "dlog.h" + +#define TABLE_FILE "lsc.tab" +#define NO_CODE 999 + +static SerChannel *ser=NULL; +static char *serverId=NULL; +static char *binDir=NULL; +static char *logDir=NULL; +static DlogSet dset; + +static float + tempP=0, /* sample T */ + tempX=0, /* heat exch. T */ + tempC=0, /* set T */ + tempH=0, /* set T on heater */ + htr; /* heat power */ + +static int + logPeriod=10, /* logging period (sec.) */ + period=1000, /* default read interval (msec.) */ + logTime=0, /* next logging time */ + setFlag=0, /* temperature to be set */ + remoteFlag=0, /* to be set to remote mode */ + dirtyX=0, /* reload input config for heat exch. */ + dirtyP=0, /* reload input config for sample */ + tryP=0, /* trial count for sample */ + tryX=0, /* trial count for heat exch */ + saveIt=0, /* CRVSAV command */ + noResp=1, /* no response */ + manualX=0, /* X device was given manually */ + manualP=0, /* P device was given manually */ + quit=0, /* quit server */ + controlMode=2, /* 0: control on heater, 1: control on sample, 3: 2nd loop for difference heater-sample */ + serialNo=0; + +static int busy, mode=0; +static int nX=0, nP=0; /* number of sensors */ +static int maxfld; /* last used display field */ +static float tLimit, resist=0.0, power; /* heater parameters */ +static float tLow=0, tHigh=0; /* lower limit of high-T sensor, upper limit of low-T sensor */ +static float tShift=0; /* setpoint shift */ +static float tInt=0; /* integral time (sec.) for setpoint shift */ +static time_t auto_remote_time=0; /* time for automatic reload */ +static time_t tim; /* actual time */ +static time_t tableTime; /* last time when table was read */ +static int codX=-1, codP=0; /* codes for heat exchanger and sample */ +static int decod[8]={21,20,17,16,5,4,1,0}; /* for code conversion */ +static char channel[5]="ACBD"; /* sensor channels for heater and sample (main, lowT) */ +static char device[32], deviceX[16], deviceP[16]; +static int deviceFlag=0; +static char *table=NULL; /* environment devices table */ +static char *cache=NULL; /* curve list cache */ + +void idleHdl(int tmo, int fd) { + int iRet; + + iRet=CocHandleRequests(tmo, fd); + if (iRet<0) logfileShowErr("CocHandleRequests"); +} + +void concatDevice() { + str_copy(device, deviceX); + if (0!=strcmp(deviceX, deviceP)) { + str_append(device, "/"); + str_append(device, deviceP); + } +} + +int instCurve(char *nam, char chan) { +/* + install sensor nam on channel chan +*/ + char *args[2]; + char buf[256], head[64], nbuf[256], lbuf[16]; + char *crv, *entry, *points, *intype, *start, + *s, /* start of found entry */ + *e, /* cache part after found entry */ + *res, *t; + int i, num, n, fld; + char used[60]; + FILE *fil; + int retstat; + + logfileOut("install curve %s\n", nam); + retstat=-2; /* errors in following section are severe */ + fil=NULL; + crv=NULL; + strcpy(buf, ":"); + str_append(buf, nam); + str_append(buf, " "); + str_upcase(buf); + + if (cache==NULL) { cache=malloc(1); *cache='\0'; } /* create empty cache if undefined */ + start=strchr(cache, '\n'); /* skip device names */ + if (start==NULL) { start=cache; } else { start++; } + entry=strstr(start, buf); + if (entry==NULL) { /* sensor not found in cache */ + entry=start; + for (i=60;i>20;i--) used[i]=0; + n=40; num=0; + while (entry!=NULL && n>0) { + i=0; + sscanf(entry, "%d", &i); + if (i>20 && i<=60) { num=i; s=entry; used[i]=1; n--; } + entry=strchr(entry, '\n'); + if (entry !=NULL) entry++; + } + if (n>0) { + for (num=60;num>20;num--) { if (used[num]==0) break; } + s=NULL; + e=NULL; + } else { + e=strchr(s, '\n'); + if (e!=NULL) { *e='\0'; e++; } + if (s>start) { s--; *s='\0'; } + } + head[0]='\0'; + } else { + s=entry; entry++; + while (s>start && *s!='\n') s--; + if (s>start) { *s='\0'; s++; } + num=0; + sscanf(s, "%d", &num); + if (num<21 || num>60) ERR_MSG("illegal curve number"); + sprintf(buf, "CRVHDR?%d", num); + retstat=-1; /* errors in following section are not severe */ + ERR_P(res=SerCmd(ser, buf)); + e=strchr(entry, '\n'); + if (e!=NULL) { *e='\0'; e++; } + str_copy(head, res); + } + + /* read and substitute curve file */ + sprintf(buf, "CRVPT %d", num); + args[0]=buf; + retstat=-2; /* errors in following section are severe */ + str_copy(nbuf, binDir); + str_append(nbuf, nam); + ERR_P(crv=str_read_arg(nbuf, args, 1)); + + intype=str_split1(crv, '\n'); + if (intype==NULL) { + points=NULL; + } else { + points=str_split1(intype, '\n'); + } + if (points==NULL) { + ERR_MSG("illegal curve file"); + } + + res=strchr(channel, chan); + if (res!=NULL) { fld=res-channel+1; } else { fld=1; } + if (fld>maxfld) maxfld=fld; + retstat=-1; /* errors in following section are not severe */ + if (LscEqPar(crv, head)) { /* header matches: select sensor type and curve */ + sprintf(buf, "INTYPE %c:%s;INCRV %c:%d;DISPFLD %d:%c,1;DISPLAY:%d" + , chan, intype, chan, num, fld, chan, maxfld); + ERR_I(LscCmdChk(ser, buf)); + logfileOut("curve %d on channel %c selected\n", num, chan); + } else { /* header does not match -> download */ + if (busy) ERR_MSG("busy"); + logfileOut("download curve %d\n", num); + sprintf(buf, "INTYPE %c:%s;DISPFLD %d:%c,3;DISPLAY:%d" + , chan, intype, fld, chan, maxfld); /* select sensor type first to display sensor units */ + ERR_I(LscCmdChk(ser, buf)); + sprintf(buf, "CRVDEL %d;CRVHDR?%d", num, num); + n=3; + do { + ERR_P(res=SerCmd(ser, buf)); + res[4]='\0'; + i=strcmp(res, "User"); + n--; + } while (i!=0 && n!=0); + if (i!=0) ERR_MSG("can not delete curve"); + do { /* download curve */ + t=str_split1(points, '\n'); + if (*points!='\0') ERR_I(LscCmdChk(ser, points)); + points=t; + } while (t!=NULL); + sprintf(buf, "CRVHDR %d:%s;INCRV %c:%d;DISPFLD %d:%c,1", num, crv, chan, num, fld, chan); /* write header, select curve */ + ERR_I(LscCmdChk(ser, buf)); + logfileOut("curve selected on channel %c\n", chan); + str_copy(head, crv); + str_upcase(head); + saveIt=1; + } + free(crv); crv=NULL; + + /* rewrite cache with actual entry at beginning */ + retstat=-2; /* errors in following section are severe */ + sprintf(lbuf, "lsc.%d", serialNo); + str_copy(nbuf, logDir); + str_append(nbuf, lbuf); + fil=fopen(nbuf, "r+"); + if (fil==NULL) ERR_SP(fil=fopen(nbuf, "w")); + if (manualX) ERR_SI(fputs(deviceX, fil)); + ERR_SI(fputs("/", fil)); + if (manualP) ERR_SI(fputs(deviceP, fil)); + ERR_SI(fputs("\n", fil)); + sprintf(buf, "%d:%s", num, head); + ERR_SI(fputs(buf, fil)); /* write actual entry */ + if (start!=s) { /* write content before replaced entry */ + ERR_SI(fputs("\n", fil)); + ERR_SI(fputs(start, fil)); + } + if (e!=NULL) { /* write content after replaced entry */ + ERR_SI(fputs("\n", fil)); + ERR_SI(fputs(e, fil)); + } + ERR_SI(fclose(fil)); + fil=NULL; + free(cache); + /* re-read it */ + ERR_P(cache=str_read_arg(nbuf, NULL, 0)); + return(0); + + OnError: + if (crv!=NULL) free(crv); + if (fil!=NULL) fclose(fil); + return(retstat); +} + +int configInput(int sampleStick) { + char *t; + char buf[80], nam[16], nbuf[256]; + int i, j, n, nn; + int retstat; + + retstat=-2; /* errors in following section are severe */ + if (sampleStick) { + if (manualP) { + sprintf(buf, ".%s.", deviceP); + } else { + sprintf(buf, "%+d ", codP); + if (codP==0) return(0); + } + } else { + if (manualX) { + sprintf(buf, ".%s.", deviceX); + } else { + sprintf(buf, "%+d ", codX); + if (codX==0) return(0); + } + } + if (table!=NULL && tim>tableTime+60) { free(table); table=NULL; }; /* clear old table */ + if (table==NULL) { /* read table */ + str_copy(nbuf, binDir); + str_append(nbuf, TABLE_FILE); + ERR_P(table=str_read_arg(nbuf, NULL, 0)); + tableTime=tim; + str_replace_char(table, 9, ' '); /* replace TAB (9) by space in order to find codes terminated by tab */ + } + t=strstr(table, buf); + if (t==NULL) ERR_MSG("device not found"); + i=sscanf(t, "%79[^\n!]", buf); /* read line */ + t=strchr(buf, '.'); + if (t==NULL) ERR_MSG("missing '.' in table file"); + t++; + n=1; + if (sampleStick) { + nP=0; + i=sscanf(t, "%12s%d%d", nam, &nn, &n); + if (i<1) ERR_MSG("missing sensor name"); + j=1; + if (n<0 || n>2) ERR_MSG("illegal value for nsensor"); + if (n==0) return(0); + if (!manualP) { /* set device name */ + str_copy(deviceP, nam); + deviceP[strlen(deviceP)-1]='\0'; /* strip off '.' */ + concatDevice(); + } + str_append(nam,"s"); + } else { + nX=0; + tLow=0; tHigh=0; + controlMode=0; + i=sscanf(t, "%12s%d%d%d%f%f%f%f%f", nam, &n, &nn, &controlMode, &tLimit, &resist, &power, &tLow, &tHigh); + if (i<7) ERR_MSG("missing some sensor parameters"); + j=0; + if (n<0 || n>2) ERR_MSG("illegal value for nsensor"); + if (n==0) return(0); + if (!manualX) { /* set device name */ + str_copy(deviceX, nam); + deviceX[strlen(deviceX)-1]='\0'; /* strip off '.' */ + concatDevice(); + } + str_append(nam, "x"); + } + ERR_I(retstat=instCurve(nam, channel[j])); + if (n==2) { + str_append(nam, "l"); + ERR_I(retstat=instCurve(nam, channel[j+2])); + } + if (sampleStick) { + nP=n; + } else { + nX=n; + } + return(0); + OnError: return(retstat); +} + +int loadCache() { + int i, j; + char *res, *p; + char buf[256], nbuf[256], lbuf[16]; + FILE *fil; + + fil=NULL; + sprintf(lbuf, "lsc.%d", serialNo); + str_copy(nbuf, logDir); + str_append(nbuf, lbuf); + ERR_SP(fil=fopen(nbuf, "w")); + if (manualX) ERR_SI(fputs(deviceX, fil)); + ERR_SI(fputs("/", fil)); + if (manualP) ERR_SI(fputs(deviceP, fil)); + ERR_SI(fputs("\n", fil)); + for (i=60; i>21; i-=4) { + sprintf(buf, "CRVHDR?%d;CRVHDR?%d;CRVHDR?%d;CRVHDR?%d", i, i-1, i-2, i-3); + ERR_P(res=SerCmd(ser, buf)); + for (j=i; j>i-4; j--) { + p=str_split1(res, ';'); + if (res[1]=='s') { i=0; break;} /* s of "User", must be empty slot, lowercase letters are not programmable */ + sprintf(buf, "%d:%s", j, res); + ERR_SI(fputs(buf, fil)); + ERR_SI(fputs("\n", fil)); + if (p==NULL) break; + res=p; + } + } + ERR_SI(fclose(fil)); + /* re-read cache */ + ERR_P(cache=str_read_arg(nbuf, NULL, 0)); + return(0); + OnError: + if (fil!=NULL) fclose(fil); + return(-1); +} + +float WeightedAverage(int n, float t1, float t2) { + float p,q; + if (n==0) { + return(0.0); + } else if (n<2) { + return(t1); + } else { + if (t21 && tempC<(tLow+tHigh)/2) ch=channel[2]; + if (nP>0) { + if (controlMode==1) { /* control directly on sample sensor */ + tShift=0; + ch=channel[1]; + if (nX>1 && tempC<(tLow+tHigh)/2) ch=channel[3]; + } else if (controlMode!=2) { + tShift=0; + } + } else { + tShift=0; + } + tempH=tempC+tShift; + if (switchOn) { + sprintf(buf, "CSET 1:%c,1;RANGE:5;SETP 1:%f", ch, tempH); + } else { + sprintf(buf, "CSET 1:%c,1;SETP 1:%f", ch, tempH); + } + ERR_I(LscCmdChk(ser, buf)); + return(0); + OnError: return(-1); +} + +int ReadTemp() { + char buf[256], lbuf[16]; + char *res; + int i, key, k; + int cod1, cod2, out1, out2; /* codes read from digital input/output */ + int codX1, codP1; + float t2[2], t4[4], p, d; + + ERR_P(res=SerCmdC(ser, "DIOST?;HTR?;BUSY?;DOUT 3,29")); + if (0==strcmp(res, "?TMO")) { + if (0==noResp) logfileOut("no response\n"); + noResp=1; + return(0); + } + i=sscanf(res, "%d%*c%d%*c%f%*c%d", &cod1, &out1, &htr, &busy); + if (i!=4) ERR_MSG("bad answer 0"); + + if (noResp) { /* check serial number */ + ERR_P(res=SerCmdC(ser, "*IDN?")); + if (0!=strncmp(res, "LSCI,MODEL340,", 14)) return(0); + res+=14; + k=0; + sscanf(res, "%d", &k); + if (k!=0 && k!=serialNo) { + serialNo=k; + dirtyX=1; dirtyP=1; + ERR_I(LscCmdChkC(ser, "RANGE:0")); /* switch off heater */ + /* reload curve cache: */ + if (cache!=NULL) free(cache); + sprintf(lbuf, "lsc.%d", serialNo); + str_copy(buf, logDir); + str_append(buf, lbuf); + cache=str_read_arg(buf, NULL, 0); + if (cache==NULL && 0==strcmp(ErrMessage, "file not found")) ERR_I(loadCache()); + deviceX[0]='\0'; + deviceP[0]='\0'; + sscanf(cache, "%15[^/!]%*c%15[^\n!]", deviceX, deviceP); /* read device names separated by '/' */ + if (deviceX[0]!='\0') manualX=1; + if (deviceP[0]!='\0') manualP=1; + concatDevice(); + } + noResp=0; + } + + sprintf(buf, "KRDG?%c;KRDG?%c;KRDG?%c;KRDG?%c", channel[0], channel[1], channel[2], channel[3]); + ERR_P(res=SerCmd(ser, buf)); + i=sscanf(res, "%f%*c%f%*c%f%*c%f", &t4[0], &t4[1], &t4[2], &t4[3]); + if (i!=4) ERR_MSG("bad answer 1"); + tempX=WeightedAverage(nX, t4[0], t4[2]); + tempP=WeightedAverage(nP, t4[1], t4[3]); + if (dirtyX==0 && dirtyP==0 && noResp==0 && tim>logTime) { + t2[0]=tempX; + t2[1]=tempP; + DlogPut(&dset, tim, 2, t2); DlogUpd(&dset); + logTime=(tim/logPeriod+1)*logPeriod; + } + if (nP>0 && nX>0 && controlMode==2) { + d=tempH-tempX; d=exp(-d*d); /* if d is small, we are far from setpoint */ + if (tInt<60000/period) tInt+=d; /* increase integral time until 60 sec. */ + p=d/tInt; + tShift=tShift*(1.0-p)+p*(tempX-tempP); + ERR_I(SetTemp(0)); + } + + ERR_P(res=SerCmdC(ser, "KEYST?;DIOST?;DOUT 3,30")); + i=sscanf(res, "%d%*c%d%*c%d", &key, &cod2, &out2); + if (i!=3) ERR_MSG("bad answer 2"); + + if (busy==0) { + + while (out1!=30) { + ERR_I(LscCmdChkC(ser, "DOUT:3,30")); + ERR_P(res=SerCmdC(ser, "DIOST?")); + i=sscanf(res, "%d%*c%d", &cod1, &out1); + } + while (out2!=29) { + ERR_I(LscCmdChkC(ser, "DOUT:3,29")); + ERR_P(res=SerCmdC(ser, "DIOST?;DOUT 3,30")); + i=sscanf(res, "%d%*c%d", &cod2, &out2); + } + + /* code conversion */ + codX1=3*decod[cod2 % 8] ^ 2*decod[cod1 % 8]; /* ^ is exclusive OR */ + codP1=-(3*decod[cod2 / 8] ^ 2*decod[cod1 / 8]); + if (codX<0) { codX=codX1; codP=codP1; } /* first time after restart */ + if (codP1!=codP) { + dirtyP=1; + codP=codP1; manualP=0; + } + if (codX1!=codX) { + dirtyX=1; + codX=codX1; manualX=0; + } + } + + if (key!=0) { + auto_remote_time=tim+600; + if (!(dirtyX || dirtyP)) { + logfileOut("user touched keys\n"); + } + dirtyX=1; dirtyP=1; + ERR_P(res=SerCmdC(ser, "MODE?")); + mode=0; + sscanf(res, "%d", &mode); + if (mode==2) auto_remote_time=tim; /* user switched to remote mode */ + } + return(0); + OnError: return(-1); +} + +int Settings() { + char buf[256]; + char *res; + int i, j, k, ia, ir; + float pa, pr, pw, dif; + + if (dirtyX || dirtyP) { + if (busy==0 || dirtyX>=0 && dirtyP>=0) { /* do not enter when busy and dirtyX/P indicates error on last time */ + if (device[0]=='\0') { + logfileOut("configure inputs for codes %d %d\n", codX, codP); + } else { + logfileOut("configure inputs for %s\n", device); + } + if (dirtyP) { + sprintf(buf, "DISPFLD 2:%c,1;DISPFLD 4:%c,1", channel[1], channel[3]); + ERR_I(LscCmdChk(ser, buf)); + } + if (dirtyX) { + if (dirtyX>0) tryX=0; + sprintf(buf, "DISPFLD 1:%c,1;DISPFLD 3:%c,1", channel[0], channel[2]); + ERR_I(LscCmdChk(ser, buf)); + nX=0; + if (!manualX) { deviceX[0]='\0'; concatDevice(); } + dirtyX=configInput(0); + if (dirtyX<0) { + tryX++; + if (dirtyX!=-1 || tryX>3) { + logfileShowErr("fatal error X"); + dirtyX=0; deviceX[0]='\0'; concatDevice(); + } else { + logfileShowErr("try again X"); + } + } else { + /* control settings */ + sprintf(buf, "CDISP 1:1,%d,1;MOUT 1:0;CMODE 1:1", (int)(resist+0.5)); + ERR_I(LscCmdChk(ser, buf)); + ia=1; ir=0; + if (power>0) { + pa=resist*4; /* max. power */ + pw=0; dif=1.0e6; + for (i=4; i>0; i--) { + pr=pa; + for (j=5; j>0; j--) { + if (pr>power) { + if (pr/power0), tLimit, channel[2]); + ERR_I(LscCmdChk(ser, buf)); + } + } + if (dirtyP) { + if (dirtyP>0) tryP=0; + nP=0; + if (!manualP) { deviceP[0]='\0'; concatDevice(); } + dirtyP=configInput(1); + if (dirtyP<0) { + tryP++; + if (dirtyP!=-1 || tryP>3) { + logfileShowErr("fatal error P"); + dirtyP=0; deviceP[0]='\0'; concatDevice(); + } else { + logfileShowErr("try again P"); + } + } else { + sprintf(buf, "ALARM %c:%d,1,%f,0,0,1;ALARM %c:0;RELAY 1:1;BEEP:0" + , channel[1], (nP>0), tLimit, channel[3]); + ERR_I(LscCmdChk(ser, buf)); + } + } + if (nP>=nX) { + maxfld=2*nP; + } else { + maxfld=2*nX-1; + } + if (maxfld>0) { + sprintf(buf, "MODE:2;DISPLAY:%d", maxfld); + } else { + maxfld=1; + sprintf(buf, "MODE:2;DISPLAY:1;DISPFLD 1:A,3", maxfld); + } + ERR_I(LscCmdChkC(ser, buf)); + mode=2; + + if (saveIt) { + ERR_P(res=SerCmdC(ser, "CRVSAV;BUSY?")); + do { + idleHdl(200, 0); /* wait 200 ms */ + ERR_P(res=SerCmdC(ser, "BUSY?")); + sscanf(res, "%d", &busy); + } while (!busy); + saveIt=0; + } + } + } + return(0); + OnError: return(-1); +} + +int ExecuteRequest() { + char *res, *t; + int iRet; + struct CocClient *client; + + if (tim>auto_remote_time || setFlag) ERR_I(Settings()); + if (setFlag) { + if (nX>0) { + tInt=0; /* reset integral time */ + ERR_I(SetTemp(1)); + logfileOut("set point\n"); + } else { + logfileOut("flag reset\n"); + } + setFlag=0; + } + client=CocGetNextCmd(); + if (client!=NULL) { + if (NULL==strchr(client->cmd, ':')) { + res=SerCmdC(ser, client->cmd); + if (res==NULL) { + res=ErrMessage; + if (res==NULL) res="empty error message"; + } + str_copy(client->res, res); + } else { + iRet=LscCmdChkC(ser, client->cmd); + if (iRet<0 && ErrMessage!=NULL) { + str_copy(client->res, ErrMessage); + } else { + str_copy(client->res, "o.k."); + } + } + client->cmd[0]='\0'; + } + if (deviceFlag) { + t=strchr(device, '/'); + if (t==NULL) { + str_copy(deviceX, device); + str_copy(deviceP, device); + manualX=1; dirtyX=1; + manualP=1; dirtyP=1; + } else { + if (t!=device) { + *t='\0'; + str_copy(deviceX, device); + *t='/'; + manualX=1; dirtyX=1; + } + t++; + if (*t!='\0') { + str_copy(deviceP, t); + manualP=1; dirtyP=1; + } + } + concatDevice(); + deviceFlag=0; + } + return(0); + OnError: return(-1); +} + +int main(int argc, char *argv[]) +{ int logIt=0; + struct timeb tim1, tim0; + int i, tdif, iret; + char *host; + char buf[256], opt; + int port, msecTmo; + + binDir=""; + logDir=""; + serverId="tecs"; + host="lnsp26"; + port=0; + msecTmo=0; + logfileOutTmp("%s ", argv[0]); + for (i=1;i=auto_remote_time) { + iret=Settings(); + if (iret<0) logfileShowErr("Settings"); + } + + while (!quit) { + ftime(&tim1); + tdif=period-((tim1.time-tim0.time)*1000+tim1.millitm-tim0.millitm); + if (tdif<0) { tim=tim1.time; break; } /* timeout */ + iret=CocHandleRequests(tdif, 0); + if (iret!=2) { time(&tim); break; } /* timeout */ + if (iret<0) logfileShowErr("CocHandleRequests"); + tim=tim1.time; + iret=ExecuteRequest(); + if (iret<0) logfileShowErr("ExecuteRequest"); + } + 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>1) { + logfileOut("%d cycles lost\n", tdif-1); + } + } + logfileOut("%s got quit command\n", serverId); + DlogClose(&dset); + return(1); + OnError: + SerClose(ser); + CocCloseServer(); + ERR_EXIT("TECS"); +} diff --git a/tecs/util.h b/tecs/util.h index 77e57077..80905516 100644 --- a/tecs/util.h +++ b/tecs/util.h @@ -49,15 +49,23 @@ int str_cmp(const char *str1, const char *str2); */ -int str_ncpy(char *dst, const char *src, int n); +int str_ncpy(char *dst, const char *src, int maxdest); /* - same as strncpy, but dst has always a '\0' at end - use str_copy if dst is a character array - returns -1, if destination is to short, 0 otherwise + 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' +*/ #define str_copy(DST,SRC) str_ncpy(DST,SRC,sizeof(DST)) +#define str_append(DST,SRC) str_ncat(DST,SRC,sizeof(DST)) +/* + use these macros if DST is an fixed length character array +*/ void util_delay(int tmo_msec); /* diff --git a/tecsdriv.h b/tecsdriv.h new file mode 100644 index 00000000..50f20939 --- /dev/null +++ b/tecsdriv.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + T E C S D R I V . H + + Support for TECS server (LakeShore 340 Temperature controllers) for SICS. + The meaning and working of the functions defined is as described for a + general environment controller. + + Markus Zolliker, March 2000 + + copyright: see implementation file. + +-----------------------------------------------------------------------------*/ +#ifndef SICSTECS +#define SICSTECS +/*------------------------- The Driver ------------------------------------*/ + + pEVDriver CreateTecsDriver(int argc, char *argv[]); + + +/*------------------------- The Tecs object ------------------------------*/ + + int TecsWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif