*** empty log message ***
This commit is contained in:
34
tecs/asynsrv_errcodes.h
Normal file
34
tecs/asynsrv_errcodes.h
Normal file
@ -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
|
49
tecs/dlog.h
Normal file
49
tecs/dlog.h
Normal file
@ -0,0 +1,49 @@
|
||||
#include <time.h>
|
||||
|
||||
#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 */
|
14
tecs/logfile.h
Normal file
14
tecs/logfile.h
Normal file
@ -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;
|
32
tecs/lsc.h
Normal file
32
tecs/lsc.h
Normal file
@ -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
|
||||
*/
|
176
tecs/rs232c_def.h
Normal file
176
tecs/rs232c_def.h
Normal file
@ -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 <cmnd_len> The command to be sent on Serial Port <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 <cmnd_len> The command to be sent on Serial Port <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: "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 <terms>.
|
||||
** rply <rply_len-1> 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 <terms>.
|
||||
** rply <rply_len-1> 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_ */
|
8
tecs/serutil.h
Normal file
8
tecs/serutil.h
Normal file
@ -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);
|
226
tecs/server.c
Normal file
226
tecs/server.c
Normal file
@ -0,0 +1,226 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <assert.h>
|
||||
#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();
|
||||
}
|
35
tecs/server.h
Normal file
35
tecs/server.h
Normal file
@ -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();
|
43
tecs/sinq_prototypes.h
Normal file
43
tecs/sinq_prototypes.h
Normal file
@ -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);
|
53
tecs/tcli.c
Normal file
53
tecs/tcli.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
10
tecs/tecc.h
10
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
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
|
803
tecs/tecs.c
Normal file
803
tecs/tecs.c
Normal file
@ -0,0 +1,803 @@
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <ctype.h>
|
||||
#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 (t2<tLow) {
|
||||
return(t2);
|
||||
} else if (t1<tHigh) {
|
||||
p=tHigh-t1;
|
||||
q=t2-tLow;
|
||||
return((t1*p*p+t2*q*q)/(p*p+q*q));
|
||||
} else {
|
||||
return(t1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SetTemp(int switchOn) {
|
||||
char buf[32];
|
||||
char ch;
|
||||
|
||||
ch=channel[0];
|
||||
if (nX>1 && 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/power<dif) { dif=pr/power; pw=pr; ia=i; ir=j; }
|
||||
} else {
|
||||
if (power/pr<dif) { dif=power/pr; pw=pr; ia=i; ir=j; }
|
||||
}
|
||||
pr=pr/10;
|
||||
}
|
||||
pa=pa/4;
|
||||
}
|
||||
}
|
||||
power=pw;
|
||||
sprintf(buf, "CLIMIT 1:%f,0,0,%d,%d;CSET 1:%c,1,1,0", tLimit, ia, ir, channel[0]);
|
||||
ERR_I(LscCmdChk(ser, buf));
|
||||
sprintf(buf, "ALARM %c:%d,1,%f,0,0,1;ALARM %c:0;RELAY 1:1;BEEP:0"
|
||||
, channel[0], (nX>0), 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<argc;i++) {
|
||||
if (argv[i]!=NULL) {
|
||||
if (argv[i][0]=='-') {
|
||||
opt=tolower(argv[i][1]);
|
||||
} else {
|
||||
opt=' ';
|
||||
}
|
||||
if ('l'==opt) {
|
||||
logIt=1;
|
||||
period=1000;
|
||||
opt=' ';
|
||||
} else if ('s'==opt) {
|
||||
logfileStd=1;
|
||||
opt=' ';
|
||||
} else if ('n'==opt) {
|
||||
i++;
|
||||
serverId=argv[i];
|
||||
} else if ('b'==opt) {
|
||||
i++;
|
||||
binDir=argv[i];
|
||||
} else if ('d'==opt) {
|
||||
i++;
|
||||
logDir=argv[i];
|
||||
} else if ('t'==opt) {
|
||||
i++;
|
||||
msecTmo=atoi(argv[i]);
|
||||
} else if ('h'==opt) {
|
||||
i++;
|
||||
host=argv[i];
|
||||
} else if ('p'==opt) {
|
||||
i++;
|
||||
port=atoi(argv[i]);
|
||||
} else {
|
||||
logfileOutTmp("?");
|
||||
}
|
||||
if (opt!=' ') logfileOutTmp("-%c ", opt);
|
||||
logfileOutTmp("%s ", argv[i]);
|
||||
}
|
||||
}
|
||||
if (port==0) port=9753;
|
||||
if (msecTmo==0) msecTmo=4000;
|
||||
|
||||
str_copy(buf, logDir);
|
||||
str_append(buf, serverId);
|
||||
|
||||
logfileInit(buf, logIt);
|
||||
logfileOutTmp("\n");
|
||||
logfileWriteTmp();
|
||||
|
||||
ERR_I(CocInitServer(1024, port));
|
||||
|
||||
CocDefFlt(tempX, CocRD);
|
||||
CocDefFlt(tempP, CocRD);
|
||||
CocDefFlt(htr, CocRD);
|
||||
CocDefFlt(tempC, setFlag);
|
||||
CocDefStr(device, deviceFlag);
|
||||
CocDefInt(controlMode, CocWR);
|
||||
CocDefInt(quit, CocWR);
|
||||
|
||||
ERR_P(ser=SerOpen(host, logIt, msecTmo, idleHdl));
|
||||
ERR_I(CocHandleRequests(100, 0));
|
||||
ftime(&tim0);
|
||||
str_copy(buf, logDir);
|
||||
str_append(buf, serverId);
|
||||
str_append(buf, ".dlog");
|
||||
iret=DlogOpen(&dset, buf, 1);
|
||||
if (iret<0) {
|
||||
ERR_I(DlogCreate(&dset, buf, tim0.time, 2, 24*60*60/logPeriod, logPeriod, 0.0));
|
||||
}
|
||||
while (!quit) {
|
||||
logfileStamp("");
|
||||
if (logIt) {
|
||||
logfileWriteTmp();
|
||||
} else {
|
||||
logfilePurge();
|
||||
}
|
||||
/* read & control temp */
|
||||
iret=ReadTemp();
|
||||
if (iret<0) logfileShowErr("ReadTemp");
|
||||
if (tim>=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");
|
||||
}
|
16
tecs/util.h
16
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);
|
||||
/*
|
||||
|
25
tecsdriv.h
Normal file
25
tecsdriv.h
Normal file
@ -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
|
Reference in New Issue
Block a user