diff --git a/tecs/Makefile b/tecs/Makefile new file mode 100644 index 00000000..2778b88d --- /dev/null +++ b/tecs/Makefile @@ -0,0 +1,32 @@ +#--------------------------------------------------------------------------- +# Makefile for the TECS Client library +# +# Markus Zolliker, March 2000 +#-------------------------------------------------------------------------- +OBJ= tecc.o client.o coc.o buf.o errhdl.o util.o + +#---------- for Redhat linux +#cc= GCC +#cflags= -i/USR/LOCAL/INCLUDE -i. -i../ -dlinux -G -C + +#------------ for DigitalUnix +CC=cc +CFLAGS= -I/data/koenneck/include -I. -I../ -std1 -g -c +#------------ for DigitalUnix with Fortify +#CFLAGS= -I/data/koenneck/include -DFORTIFY -I. -I../ -std1 -g -c + +#------------ for CYGNUS toolchain on Win32 +#CC=gcc +#CFLAGS= -I. -I../ -DCYGNUS -g -c + +.c.o: + $(CC) $(CFLAGS) $*.c + +tecsl: $(OBJ) + - rm libtecsl.a + ar cr libtecsl.a $(OBJ) + ranlib libtecsl.a + +clean: + rm *.o + rm *.a diff --git a/tecs/buf.c b/tecs/buf.c new file mode 100644 index 00000000..074636db --- /dev/null +++ b/tecs/buf.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include "buf.h" + +#define TWO28 268435456.0 +#define MAXINT 2147483647 + +/* static char *null="\0"; */ + +int buf_get_int(buf_type *buf) +{ char *b; + int *res; + + b=buf->buf; + if (b==NULL) return(0); + if (b[0]!=1 || buf->size<5) {buf->buf=NULL; return(0); } + b++; + res=(int *)b; + b+=4; + buf->size-=5; + buf->buf=b; + return(*res); +} + +char *buf_get_str(buf_type *buf) +{ char *b; + int l; + + b=buf->buf; + if (b==NULL) return(""); + if (b[0]==1 || b[0]==2) return(""); + l=strlen(b); + if (buf->size<=l) {buf->buf=NULL; return(""); } + buf->buf+=l+1; + buf->size-=l+1; + return(b); +} + +float buf_get_float(buf_type *buf) +{ char *b; + float res; + int *mant, iexp; + + b=buf->buf; + if (b==NULL) return(0.0); + if (b[0]!=2 || buf->size<6) { buf->buf=NULL; return(0.0); } + iexp=b[1]; + b+=2; + mant=(int *)b; + b+=4; + buf->size-=6; + res=(float)ldexp(*mant/TWO28, iexp); + buf->buf=b; + return res; +} + +int buf_size(buf_type *buf) +{ + if (buf->buf==NULL) return(-1); + return (buf->size); +} + +void buf_put_int(buf_type *buf, int val) +{ char *b; + + b=buf->buf; + if (b==NULL) return; + b[0]=1; + b++; + if (buf->size<=4) {buf->buf=NULL; return; } + *(int *)b=val; + b+=4; + buf->size-=5; + buf->buf=b; + return; +} + +void buf_put_str(buf_type *buf, char *str) +{ char *b; + int l; + + if (str[0]<=2 && str[0]!='\0') { buf->buf=NULL; return; }; + b=buf->buf; + if (b==NULL) return; + l=strlen(str); + if (buf->size<=l) { buf->buf=NULL; return; } + strcpy(b, str); + buf->buf+=l+1; + buf->size-=l+1; +} + +int buf_nint(float val) +{ int res; + + if (val<0) { + if (val<-MAXINT) { + return(-MAXINT); + } else { + return(val-0.5); + } + } else { + if (val>MAXINT) { + return(MAXINT); + } else { + return(val+0.5); + } + } +} + +void buf_put_float(buf_type *buf, float val) +{ char *b; + double d; + int iexp; + int mant; + + b=buf->buf; + if (b==NULL) return; + if (buf->size<=4) {buf->buf=NULL; return; } + d=frexp((double)val, &iexp); + mant=buf_nint(d*TWO28); + if (iexp>127) iexp=127; + if (iexp<-128) iexp=-128; + b[0]=2; + b[1]=iexp; + b+=2; + *(int *)b=mant; + b+=4; + buf->size-=6; + buf->buf=b; +} + +void buf_put_end(buf_type *buf) +{ buf->buf=buf->start; + buf->usize=buf->isize-buf->size; + buf->size=buf->usize; +} + +void buf_put_start(buf_type *buf) +{ buf->buf=buf->start; + buf->size=buf->isize; +} + +void buf_reset(buf_type *buf) +{ buf->buf=buf->start; + buf->size=buf->usize; +} + +buf_type *buf_create(size_t size) +{ buf_type *buf; + + buf=malloc(sizeof(*buf)); + buf->start=malloc(size); + buf->isize=size; + return(buf); +} + +void buf_free(buf_type *buf) +{ free(buf->buf); + free(buf); +} diff --git a/tecs/buf.h b/tecs/buf.h new file mode 100644 index 00000000..3727d9e6 --- /dev/null +++ b/tecs/buf.h @@ -0,0 +1,20 @@ +typedef struct { char *buf; char *start; int size; int usize; int isize, dummy; } buf_type; + +/* input */ +void buf_reset(buf_type *buf); +int buf_get_int(buf_type *buf); +char *buf_get_str(buf_type *buf); +float buf_get_float(buf_type *buf); +int buf_size(buf_type *buf); + +/* output */ +void buf_put_start(buf_type *buf); +void buf_put_int(buf_type *buf, int val); +void buf_put_str(buf_type *buf, char *str); +void buf_put_float(buf_type *buf, float val); +void buf_put_end(buf_type *buf); + +/* common */ +buf_type *buf_create(size_t size); +void buf_free(buf_type *buf); +void buf_log(buf_type *buf); diff --git a/tecs/client.c b/tecs/client.c new file mode 100644 index 00000000..d1cc2a1e --- /dev/null +++ b/tecs/client.c @@ -0,0 +1,180 @@ +#include +#include "client.h" +#include "util.h" + +/*-------------------------------------------------------------------------*/ + +int CocOpen(CocConn *conn) +{ + int i, cnt, try, port, tryConn, tmo; + struct sockaddr_in sadr; + char *p, *q; + + try=2; + tryConn=1; + tmo=0; + while (try>0) { + try--; + while (tryConn>0) { + port=CocPORT; + cnt=CocPORTS; + tryConn--; + while (cnt>0) { + ERR_SI(conn->fd=socket(AF_INET, SOCK_STREAM, 0)); + ERR_I(CocCreateSockAdr(&sadr, conn->host, port)); + i=connect(conn->fd, (struct sockaddr *)&sadr, sizeof(sadr)); + if (i>=0) return(0); + if (errno!=ECONNREFUSED) { ERR_COD(errno); } + port++; cnt--; + } + util_delay(tmo); tmo+=100; + } + if (conn->startcmd[0]=='\0' || try<=0) { ERR_COD(ECONNREFUSED); } + p=conn->startcmd; + q=strchr(p,' '); + while (q!=NULL) { + p=q+1; + q=strchr(p,' '); + }; + printf("start server %s\n", p); + ERR_I(system(conn->startcmd)); + util_delay(100); tmo=200; + tryConn=5; + } + ERR_COD(ECONNREFUSED); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +void CocInitClient(CocConn *conn, char *host, char *magic, int bufsize, char *startcmd) +{ void *e; + + if (bufsize==0) bufsize=1024; + conn->cmdbuf=buf_create(bufsize); + conn->resbuf=buf_create(bufsize); + str_copy(conn->host, host); + str_copy(conn->magic, magic); + str_copy(conn->startcmd, startcmd); + conn->fd=-1; + conn->varList=NULL; + CocVarList(&conn->varList); +} + +/*-------------------------------------------------------------------------*/ + +int CocSendMagic(CocConn *conn, char *magic) { + char *err; + + if (magic[0]!='#') ERR_MSG("magic must start with '#'"); + buf_put_start(conn->resbuf); /* use return buffer for command in order to preserve command buffer */ + buf_put_str(conn->resbuf, magic); + buf_put_end(conn->resbuf); + if (conn->resbuf->buf==NULL) ERR_MSG("buffer full"); + ERR_SI(send(conn->fd, conn->resbuf->buf, conn->resbuf->size, 0)); + ERR_I(CocRecv(conn->fd, conn->resbuf)); + err=buf_get_str(conn->resbuf); + if (*err!='\0') { ErrMsg(err); ErrTxt(": (response from server)",0); goto OnError; } + if (buf_size(conn->resbuf)!=0) ERR_MSG("syntax error"); + return(0); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +int CocTryCmd(CocConn *conn) +{ if (conn->fd<0) { + ERR_I(CocOpen(conn)); + ERR_I(CocSendMagic(conn, conn->magic)); + } + ERR_SI(send(conn->fd, conn->cmdbuf->buf, conn->cmdbuf->size, 0)); + ERR_I(CocRecv(conn->fd, conn->resbuf)); + return(0); + OnError: return(-1); +} + +/*-------------------------------------------------------------------------*/ + +int CocCmd(CocConn *conn, const char *rwList) +{ int iret, cnt, setmode, i; + char *err; + const char *t, *s; + char nam[32]; + CocVar *var; + + buf_put_start(conn->cmdbuf); + s=rwList; + setmode=0; + do { + t=strchr(s, ','); + if (t==NULL) t=s+strlen(s); + if (*s=='[') { + if (!setmode) buf_put_str(conn->cmdbuf, "["); + s++; + setmode=1; + } + i=t-s; + assert(i<32); + str_ncpy(nam, s, i+1); + if (setmode) { + if (nam[i-1]==']') { nam[i-1]='\0'; setmode=0; } + buf_put_str(conn->cmdbuf, nam); + ERR_I(CocPutVar(conn->varList, conn->cmdbuf, nam)); + if (!setmode) buf_put_str(conn->cmdbuf, "]"); + } else { + var=CocFindVar(conn->varList, nam); + if (var==NULL) ERR_MSG("variable not found"); + buf_put_str(conn->cmdbuf, nam); + } + s=t+1; + } while (*t!='\0'); + + buf_put_end(conn->cmdbuf); + if (conn->cmdbuf->buf==NULL) ERR_MSG("out buffer full"); + cnt=3; + while (1) { + cnt--; + if (cnt<=0) { + ERR_I(CocTryCmd(conn)); + break; + } + iret=CocTryCmd(conn); + if (iret>=0) break; + close(conn->fd); + conn->fd=-1; + if (ErrCode!=ECONNRESET && ErrCode!=EPIPE) goto OnError; + ErrShow("try again, error was"); + } + err=buf_get_str(conn->resbuf); + if (*err!='\0') { ErrMsg(err); ErrTxt(": (response from server)",0 ); goto OnError; } + + /* read values */ + s=rwList; + setmode=0; + do { + t=strchr(s, ','); + if (t==NULL) t=s+strlen(s); + if (*s=='[') { + s++; + setmode=1; + } + i=t-s; + if (!setmode) { + str_ncpy(nam, s, i+1); + if (nam[i-1]==']') { nam[i-1]='\0'; setmode=0; } + ERR_I(CocGetVar(conn->varList, conn->resbuf, nam)); + } + s=t+1; + } while (*t!='\0'); + if (buf_size(conn->resbuf)!=0) ERR_MSG("syntax error"); + return(0); + + OnError: return(-1); +} + +void CocCloseClient(CocConn *conn) { + close(conn->fd); + buf_free(conn->cmdbuf); + buf_free(conn->resbuf); + CocFreeVarList(&conn->varList); +} diff --git a/tecs/client.h b/tecs/client.h new file mode 100644 index 00000000..c32f0fcc --- /dev/null +++ b/tecs/client.h @@ -0,0 +1,16 @@ +#include "coc.h" + +typedef struct { + int fd, dummy; + CocVar *varList; + buf_type *cmdbuf; /* for sending command */ + buf_type *resbuf; /* for response */ + char host[64]; + char magic[32]; + char startcmd[64]; +} CocConn; + +void CocInitClient(CocConn *conn, char *host, char *magic, int bufsize, char *startcmd); +int CocSendMagic(CocConn *conn, char *magic); +int CocCmd(CocConn *conn, const char *rwList); +void CocCloseClient(CocConn *conn); diff --git a/tecs/coc.c b/tecs/coc.c new file mode 100644 index 00000000..b5914907 --- /dev/null +++ b/tecs/coc.c @@ -0,0 +1,161 @@ +#include +#include "coc.h" +/*-------------------------------------------------------------------------*/ +/* CreateSocketAddress stolen from Tcl. Thanks to John Ousterhout */ + +CocVar *serverVarList=NULL; +static CocVar **varListHdl=&serverVarList; +int CocRD=0; +int CocWR=0; + +int CocCreateSockAdr( + struct sockaddr_in *sockaddrPtr, /* Socket address */ + const char *host, /* Host. NULL implies INADDR_ANY */ + int port) /* Port number */ +{ + struct hostent *hostent; /* Host database entry */ + struct in_addr addr; /* For 64/32 bit madness */ + + (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); + sockaddrPtr->sin_family = AF_INET; + sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); + if (host == NULL) { + addr.s_addr = INADDR_ANY; + } else { + hostent = gethostbyname(host); + if (hostent != NULL) { + memcpy((char *) &addr, + (char *) hostent->h_addr_list[0], (size_t) hostent->h_length); + } else { + addr.s_addr = inet_addr(host); + if (addr.s_addr == (unsigned long)-1) { + return -1; /* error */ + } + } + } + /* + * There is a rumor that this assignment may require care on + * some 64 bit machines. + */ + + sockaddrPtr->sin_addr.s_addr = addr.s_addr; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +int CocRecv(int fd, buf_type *buf) +{ + struct timeval tmo={0,1}; + fd_set mask; + int i, ret; + + tmo.tv_sec=5; /* timeout 5 sec. */ + + FD_ZERO(&mask); + FD_SET(fd, &mask); + ERR_SI(i=select(fd+1,&mask,NULL,NULL,&tmo)); + if (i==0) ERR_MSG("time out"); + + buf_put_start(buf); + ERR_SI(ret=recv(fd, buf->buf, buf->isize, 0)); + if (ret==0) { ERR_COD(ECONNRESET); } + buf->usize=ret; + buf_reset(buf); + return(ret); + OnError: return(-1); +} + +void CocVarList(CocVar **varList) { + assert(varList!=NULL); + varListHdl=varList; +} + +CocVar *CocFindVar(CocVar *varList, const char *name) { + CocVar *p; + + p=varList; + while (p!=NULL && 0!=strcmp(p->name,name)) p=p->next; + return(p); +} + +void CocDefVar(const char *name, void *var, int type, int *flag) { + CocVar *p; + + assert(varListHdl!=NULL); + p=CocFindVar(*varListHdl, name); + if (p==NULL) { + p=malloc(sizeof(*p)); + p->next=*varListHdl; + *varListHdl=p; + } + str_copy(p->name, name); + p->var=var; + p->type=type; + p->flag=flag; +} + +int CocGetVar(CocVar *varList, buf_type *buf, const char *name) { + CocVar *var; + + var=CocFindVar(varList, name); + if (var==NULL) ERR_MSG("undefined variable"); + if (varList==serverVarList) { /* we are the server */ + if (var->flag==&CocRD) ERR_MSG("variable is read only"); + } + if (var->type==-1) { + *(int *)var->var=buf_get_int(buf); + } else if (var->type==-2) { + *(float *)var->var=buf_get_float(buf); + } else if (var->type>1) { + str_ncpy((char *)var->var, buf_get_str(buf), var->type); + } else { + ERR_MSG("unknown type"); + } + if (varList==serverVarList) { /* we are the server */ + if (var->flag!=NULL) (*var->flag)++; + } + return(0); + OnError: return(-1); +} + +int CocPutVar(CocVar *varList, buf_type *buf, const char *name) { + CocVar *var; + char *c; + + var=CocFindVar(varList, name); + if (var==NULL) ERR_MSG("undefined variable"); + if (varList!=serverVarList) { /* we are a client */ + if (var->flag==&CocRD) ERR_MSG("variable is read only"); + } + if (var->type==-1) { + buf_put_int(buf, *(int *)var->var); + } else if (var->type==-2) { + buf_put_float(buf, *(float *)var->var); + } else if (var->type>1) { + c=var->var; + if (c[0]<=2 && c[0]!=0) { ERR_MSG("illegal string"); } + buf_put_str(buf, c); + } else { + ERR_MSG("unknown type"); + } + if (varList!=serverVarList) { /* we are a client */ + if (var->flag!=NULL) (*var->flag)++; + } + return(0); + OnError: return(-1); +} + +void CocFreeVarList(CocVar **varList) { + CocVar *p, *v; + + if (varList==NULL) varList=&serverVarList; + v=*varList; + while (v!=NULL) { + p=v; + v=p->next; + p->next=NULL; + free(p); + } + *varList=NULL; +} diff --git a/tecs/coc.h b/tecs/coc.h new file mode 100644 index 00000000..13b11e49 --- /dev/null +++ b/tecs/coc.h @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "errhdl.h" +#include "buf.h" +#include "util.h" + +#define CocPORT 9751 +#define CocPORTS 3 + +int CocCreateSockAdr( + struct sockaddr_in *sockaddrPtr, /* Socket address */ + const char *host, /* Host. NULL implies INADDR_ANY */ + int port); /* Port number */ +int CocRecv(int fd, buf_type *buf); + +typedef struct { void *next; char name[32]; void *var; int *flag; int type; } CocVar; + +extern int CocRD; +extern int CocWR; +CocVar *serverVarList; + +void CocDefVar(const char *name, void *var, int type, int *flag); +void CocVarList(CocVar **varlist); +void CocFreeVarList(CocVar **varList); +CocVar *CocFindVar(CocVar *varList, const char *name); +int CocPutVar(CocVar *varList, buf_type *buf, const char *name); +int CocGetVar(CocVar *varList, buf_type *buf, const char *name); +void CocDefFlag(int *flag); + +#define CocDefInt(V,F) CocDefVar(#V,&V,-1,&F) +#define CocDefFlt(V,F) CocDefVar(#V,&V,-2,&F) +#define CocDefStr(V,F) CocDefVar(#V,V,sizeof(V),&F) +#define CocDefStrPtr(V,S,F) CocDefVar(#V,V,S,&F) diff --git a/tecs/errhdl.c b/tecs/errhdl.c new file mode 100644 index 00000000..5563744e --- /dev/null +++ b/tecs/errhdl.c @@ -0,0 +1,86 @@ +#include +#include +#include "errhdl.h" + +#define SLEN 64 +#define MLEN 64 + +static char *txt[SLEN]; +static int sp=0; + +int ErrCode; +char *ErrMessage=NULL; + +void ErrTxt(char *text, int systemError) +{ + if (systemError) { sp=0; ErrCode=errno; ErrMessage=strerror(errno); } + if (sp=256) l=255; + strncpy(buf, text[1], l); + buf[l]='\0'; + ErrWriteGeneral(buf, outrtn, arg); +} +#endif + +void ERR_EXIT(char *text) { + ErrShow(text); exit(1); +} diff --git a/tecs/errhdl.h b/tecs/errhdl.h new file mode 100644 index 00000000..69eab42c --- /dev/null +++ b/tecs/errhdl.h @@ -0,0 +1,81 @@ +#include +#include +#include + +/* ErrHDL Error handling utilities + ------------------------------- + Makes code more readable by hiding annoying error condition checks. + +Macros and routines: + + Spelling in uppercase indicates, that it the program flow + may be modified (jump to OnError label or program exit). + + + ERR_x + + Usage Error condition Error message taken from + ----------------------------------------------------------------------------------------- + ERR_SI(res=routine1(...)) res<0 errno + ERR_SP(ptr=routine2(...)) ptr==NULL errno + ERR_I(res=routine3(...)) res<0 stored by routine3 using errhdl mechanism + ERR_P(ptr=routine4(...)) ptr==NULL stored by routine4 using errhdl mechanism + + The result assignment "res=" or "ptr=" is optional. + + Description: + The routine routineX is called. + If the result indicates an error, the source text is saved and the + program continues at the OnError label. + The error message and the source code of the calling instructions is + saved for a later call to ErrShow or ErrExit. + + ERR_EXIT("program_name") + + Show error and exit program. + + ERR_MSG("message") + + Signals an error condition. If "message" is replaced by a variable, + take care that it is not modified until ErrShow is called. + + ERR_COD(cod) + + Signals an error condition as code from errno.h + + ErrShow("program_name") + ErrWrite(fil, "program_name") + + Show actual error message with traceback information to stdout + or a file fil + +Global Variables (read only) + + int ErrCode + + actual error message code + = errno for system errors or + = -1 for custom errors signaled by ERRMSG + + char *ErrMessage + + actual error message +*/ + +#define ERR_SI(R) { if(0>(R)) { ErrTxt(#R,1); goto OnError; }; } +#define ERR_SP(R) { if(NULL==(R)) { ErrTxt(#R,1); goto OnError; }; } +#define ERR_I(R) { if(0>(R)) { ErrTxt(#R,0); goto OnError; }; } +#define ERR_P(R) { if(NULL==(R)) { ErrTxt(#R,0); goto OnError; }; } +#define ERR_MSG(R) { ErrMsg(R); goto OnError; } +#define ERR_COD(R) { ErrCod(R); goto OnError; } + +void ErrTxt(char *text, int systemError); +void ErrMsg(char *msg); +void ErrCod(int code); +void ErrShow(char *text); +void ErrWrite(FILE *fil, char *text); +void ERR_EXIT(char *text); +void ErrLog(char *text); + +extern int ErrCode; +extern char *ErrMessage; diff --git a/tecs/tecc.c b/tecs/tecc.c new file mode 100644 index 00000000..15de3b21 --- /dev/null +++ b/tecs/tecc.c @@ -0,0 +1,130 @@ +#include "errhdl.h" +#include "client.h" +#include "tecc.h" + +char command[80], response[80], device[80]; +float tempX, tempP, tempC; + +pTecsClient TeccInit(char *server) { + CocConn *conn; + char buf[80]; + + ERR_SP(conn=(CocConn *)malloc(sizeof(*conn))); +#ifdef __VMS + sprintf(buf, "@start_tecs %s", server); +#else + sprintf(buf, "start_tecs %s", server); +#endif + CocInitClient(conn, "", "#rwacs", 0, buf); + CocDefFlt(tempX, CocRD); + CocDefFlt(tempP, CocRD); + CocDefFlt(tempC, CocWR); + CocDefStr(device, CocWR); + CocDefStr(command, CocWR); + CocDefStr(response, CocWR); + return((pTecsClient)conn); + OnError: return(NULL); +} + +int TeccSetDev(pTecsClient conn, char *dev) { + str_copy(device, dev); + ERR_I(CocCmd((CocConn *)conn, "[device]")); + return(0); + OnError: return(-1); +} + +char *TeccGetDev(pTecsClient conn) { + ERR_I(CocCmd((CocConn *)conn, "device")); + return(device); + OnError: return(NULL); +} + +int TeccGet(pTecsClient conn, float *temp) { + ERR_I(CocCmd((CocConn *)conn, "tempP")); + *temp=tempP; + return(0); + OnError: return(-1); +} + +int TeccGet3(pTecsClient conn, float temp[3]) { + ERR_I(CocCmd((CocConn *)conn, "tempC,tempX,tempP")); + temp[0]=tempC; + temp[1]=tempX; + temp[2]=tempP; + return(0); + OnError: return(-1); +} + +int TeccSet(pTecsClient conn, float temp) { + tempC=temp; + ERR_I(CocCmd((CocConn *)conn, "[tempC]")); + return(0); + OnError: return(-1); +} + +int TeccSend(pTecsClient conn, char *cmd, char *reply, int replyLen) { + command[0]='\0'; + while (0!=strcmp(command, cmd)) { + str_copy(command, cmd); + strcpy(response,""); + ERR_I(CocCmd((CocConn *)conn, "[command,response]")); + while (0==strcmp(response,"") && 0==strcmp(command, cmd)) { + util_delay(250); + ERR_I(CocCmd((CocConn *)conn, "command,response")); + } + } + str_ncpy(reply, response, replyLen); + return(0); + OnError: return(-1); +} + +void TeccClose(pTecsClient conn) { + CocCloseClient((CocConn *)conn); + free(conn); +} + +#ifdef __VMS + +int TeccSetDevVms(pTecsClient conn, char **dev) { + int l; + + l=*(short *)dev; + if (l>=sizeof(device)) l=sizeof(device)-1; + strncpy(device, dev[1], l); + while (l>0 && device[l-1]==' ') l--; /* trim */ + device[l]='\0'; + ERR_I(CocCmd((CocConn *)conn, "[device]")); + return(0); + OnError: return(-1); +} + +int TeccGetDevVms(pTecsClient conn, char **dev) { + int l, ld; + + ERR_I(CocCmd((CocConn *)conn, "device")); + ld=strlen(device); + l=*(short *)dev; + if (ld>=l) ld=l; + strncpy(dev[1], device, ld); + return(ld); + OnError: return(-1); +} + +int TeccSendVms(pTecsClient conn, char **cmd, char **reply) { + int l, lr; + char cbuf[80], rbuf[80]; + + l=*(short *)cmd; + if (l>=sizeof(cbuf)) l=sizeof(cbuf)-1; + strncpy(cbuf, cmd[1], l); + while (l>0 && cbuf[l-1]==' ') l--; /* trim */ + cbuf[l]='\0'; + TeccSend(conn, cbuf, rbuf, sizeof(rbuf)); + lr=strlen(rbuf); + l=*(short *)reply; + if (lr>=l) lr=l; + strncpy(reply[1], rbuf, lr); + return(lr); + OnError: return(-1); +} +#endif diff --git a/tecs/tecc.h b/tecs/tecc.h new file mode 100644 index 00000000..e0e3a8cc --- /dev/null +++ b/tecs/tecc.h @@ -0,0 +1,39 @@ +/* + tecc.h: tecs client interface routines + + M. Zolliker March 2000 +------------------------------------------------------------------------*/ + +typedef struct { int tecc_private; } *pTecsClient; +/* hidden structure for a tecs client +------------------------------------------------------------------------*/ + +pTecsClient TeccInit(char *server); +/* init tecs client (connect to server) +------------------------------------------------------------------------*/ + +int TeccSetDev(pTecsClient conn, char *dev); +/* set device type +------------------------------------------------------------------------*/ + +char *TeccGetDev(pTecsClient conn); +/* get device type +------------------------------------------------------------------------*/ + +int TeccGet(pTecsClient conn, float *temp); +/* set temperature +------------------------------------------------------------------------*/ + +int TeccSet(pTecsClient conn, float temp); +/* get temperature +------------------------------------------------------------------------*/ + +int TeccSend(pTecsClient conn, char *cmd, char *reply, int replyLen); +/* send a command transparently to the controller + replyLen is the maximal length of reply +------------------------------------------------------------------------*/ + +void TeccClose(pTecsClient conn); +/* close connection and free ressources +------------------------------------------------------------------------*/ + diff --git a/tecs/util.c b/tecs/util.c new file mode 100644 index 00000000..7e901e12 --- /dev/null +++ b/tecs/util.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include +#include +#include "errhdl.h" +#include "util.h" + +/* when changing FBUF_LEN, change also the constant in the fscanf call in subroutine LscExeCmd */ +#define FBUF_LEN 132 + +char *str_split(char *str, char sep, char *list[], int *n) { + int i; + char *s, *e; + + s=str; + for (i=0; i<*n; i++) { + list[i]=s; + e=strchr(s, sep); + if (e==NULL) { *n=i+1; return(NULL); } + s=e+1; + e--; + while (e>str && *e==' ') e--; /* trim sequence */ + e[1]='\0'; + } + return(s); +} + +char *str_split1(char *str, char sep) { + char *s, *e; + + e=strchr(str, sep); + if (e==NULL) { + s=NULL; + e=str+strlen(str); + } else { + s=e+1; + } + e--; + while (e>str && *e==' ') e--; /* trim sequence */ + e[1]='\0'; + return(s); +} + +char *str_ntrim(char *dest, int ldest, const char *src, int lsrc) { + char *s, *e; + + if (lsrcdest && *e==' ') e--; /* trim sequence */ + e[1]='\0'; + return(s); +} + +char *str_read_until(FILE *fil, char *term, char *buf, char *end) { + char *s; + char fmt[24]; + int i, l, siz; + char ch; + + siz=end-buf-1; + if (siz<1) return(NULL); + sprintf(fmt, "%s%d[^%s%s", "%", siz, term, "]%n%c"); + i=fscanf(fil, fmt, buf, &l, &ch); + if (i<0) { /* eof */ + buf[0]='\0'; + return(&buf[0]); + } else if (i==0) { /* fscanf returns 0 if first char is terminator */ + buf[0]=fgetc(fil); + return(&buf[0]); + } else if (i==1) { /* terminator not found -> read until eof */ + buf[l]='\0'; + return(&buf[l]); + } else { + buf[l]=ch; + if (l==siz && NULL==strchr(term, ch)) return(NULL); + return(&buf[l]); + } +} + +char *str_read_arg(char *file, char *args[], int nargs) { + FILE *fil; + char *str, *s, *e, *p, *q; + char ch; + int i, l, size; + struct stat statbuf; + + i=stat(file, &statbuf); + if (i<0) ERR_MSG("file not found"); + size=statbuf.st_size+4; + if (nargs>0) size+=size/2+100; /* max size */ + while (1) { + ERR_SP(str=malloc(size)); + e=&str[size-1]; + ERR_SP(fil=fopen(file, "r")); + s=str; + while (1) { + p=str_read_until(fil, "#!", s, e); + if (p==NULL) break; + if (*p=='!') { + q=str_read_until(fil, "\n", p, e); + if (q==NULL) { p=NULL; break; } + s=p; *s='\n'; s++; + } else if (*p=='#') { + ch=fgetc(fil); + i=ch-'0'; + if (i<0 || i>=nargs) { + s=p+1; *s=ch; s++; + } else { + l=strlen(args[i]); + if (s+l>=e) { p=NULL; break; } + strcpy(p, args[i]); + s=p+l; + } + } else { + assert(*p=='\0'); + break; + } + } + ERR_SI(fclose(fil)); + if (p!=NULL) break; + size=size*3/2; /* allocation not sufficient -> try again */ + free(str); + } + assert(strlen(str)ch2) { + return(i); + } + return(0); +} + +int str_ncpy(char *dst, const char *src, int n) { + strncpy(dst, src, n); + if (dst[n-1]!='\0') { + dst[n-1]='\0'; + ERR_MSG("destination string too short"); + } + return(0); + OnError: return(-1); +} + +void util_delay(int tmo_msec) { + struct timeval tmo; + + tmo.tv_sec=tmo_msec / 1000; + tmo.tv_usec=(tmo_msec % 1000)*1000+1; + select(1,NULL,NULL,NULL,&tmo); +} diff --git a/tecs/util.h b/tecs/util.h new file mode 100644 index 00000000..77e57077 --- /dev/null +++ b/tecs/util.h @@ -0,0 +1,65 @@ +char *str_ntrim(char *dest, int ldest, const char *src, int lsrc); +/* + copy characters 0 to lsrc-1 from src to dest (max ldest chars). +*/ + +char *str_split1(char *str, char separator); +/* + trims text before separator in *str and returns + a pointer to the first character after separator +*/ + +char *str_split(char *str, char sep, char *list[], int *n); +/* + split string into *n strings using separator sep. + spaces at the end of the elements are trimmed + attention: *str is modified ('\0' placed at the end of the elements) + + if *n separators are found, result points to string after *n-th separator + else result is NULL + *n contains number of elements stored in list +*/ + +char *str_read_arg(char *file, char *args[], int nargs); +/* + return one string containing the contents of file *file + the contents are treated in the following way: + - #0,#1,...#n is replaced by the corresponding argument *args[n] (n=0..nargs-1, nargs<10) + - at the end of each line spaces and comments separated by ! are trimmed +*/ + +void str_replace_char(char *str, char ch, char rep); +/* + replace all occurences of character ch by character rep in string *str +*/ + +void str_upcase(char *str); +/* + convert *str to uppercase +*/ + +int str_cmp(const char *str1, const char *str2); +/* + compare *str1 with *str2 + the comparison is not case sensitive + if result=0: strings are equal + else + result>0 <==> *str1>*str2 + first different character is at position abs(result)-1 +*/ + + +int str_ncpy(char *dst, const char *src, int n); +/* + 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 +*/ + + +#define str_copy(DST,SRC) str_ncpy(DST,SRC,sizeof(DST)) + +void util_delay(int tmo_msec); +/* + usleep is not available on VMS 6 +*/