*** empty log message ***

This commit is contained in:
cvs
2000-03-15 11:29:50 +00:00
parent 952b84dedb
commit b9b30e7d62
14 changed files with 1518 additions and 6 deletions

34
tecs/asynsrv_errcodes.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View File

@ -1,14 +1,16 @@
#include "client.h"
/* /*
tecc.h: tecs client interface routines tecc.h: tecs client interface routines
M. Zolliker March 2000 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 /* hidden structure for a tecs client
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
pTecsClient TeccInit(char *server); pTecsClient TeccInit(char *server, int port);
/* init tecs client (connect to server) /* init tecs client (connect to server)
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
@ -37,3 +39,7 @@ void TeccClose(pTecsClient conn);
/* close connection and free ressources /* close connection and free ressources
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
int TeccKillServer(pTecsClient conn);
/* kill the server process
------------------------------------------------------------------------*/

803
tecs/tecs.c Normal file
View 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");
}

View File

@ -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 copy *src to *dest, maximal maxdest characters,
use str_copy if dst is a character array it is guaranteed, that dst contains '\0'
returns -1, if destination is to short, 0 otherwise
*/ */
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_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); void util_delay(int tmo_msec);
/* /*

25
tecsdriv.h Normal file
View 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