Files
sicspsi/tecs/tecs_serial.c
zolliker 94075f06c7 - cleaned up makefiles
- polished code to avoid warnings
2005-03-08 11:12:23 +00:00

259 lines
6.3 KiB
C

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <time.h>
#include <sys/time.h>
#include "rs232c_def.h"
#include "asynsrv_def.h"
#include "sinq_prototypes.h"
#include "myc_err.h"
#include "tecs_serial.h"
#include "coc_logfile.h"
#include "coc_util.h"
#include "myc_str.h"
#include "myc_mem.h"
#define ASYNSRV_TYPE 1
#define TERMSRV_TYPE 2
#define EOT '\r'
typedef struct {
char host[64];
int type; /* = ASYNSRV_TYPE */
struct AsynSrv__info asyn_info; /* Contains skt, host, port & chan */
struct RS__MsgStruct to_host;
struct RS__RespStruct from_host;
} AsynSrvChan;
typedef struct {
char host[64];
int type; /* = TERMSRV_TYPE */
char res[SER_BUF_LEN];
int fd, tmo;
int (*idleHdl)(int,int);
} TermSrvChan;
void SerA_error(void) {
char *a_txt;
int a_cod, a_my, a_vms;
AsynSrv_ErrInfo(&a_txt, &a_cod, &a_my, &a_vms);
ErrMsg("asynsrv error"); ErrTxt(a_txt,0);
}
int SerWait(int tmo_msec, int fd) {
struct timeval tmo;
fd_set mask;
int i;
FD_ZERO(&mask);
FD_SET(fd, &mask);
tmo.tv_sec=tmo_msec / 1000;
tmo.tv_usec=(tmo_msec % 1000) % 1000 +1;
ERR_SI(i=select(fd+1,&mask,NULL,NULL,&tmo));
if (i==0) return(0); /* timeout */
return(1);
OnError: return(-1);
}
SerChannel *SerOpen(const char *hostPort, int msecTmo, int (*idleHdl)(int,int)) {
AsynSrvChan *aser;
TermSrvChan *tser;
char hbuf[64], cport[16], host[32];
char *p, *c;
struct sockaddr_in sadr;
int iret;
time_t t1, t2;
static int ecnt;
time(&t1);
str_copy(hbuf, hostPort);
p=str_split(host, hbuf, ':');
assert(p!=NULL);
c=str_split(cport, p, '/');
if (msecTmo==0) msecTmo=5000;
if (c!=NULL) {
NEW(aser, AsynSrvChan); aser->type=ASYNSRV_TYPE;
str_copy(aser->asyn_info.host, host);
aser->asyn_info.port=atoi(cport);
aser->asyn_info.chan=atoi(c);
iret=AsynSrv_Open(&aser->asyn_info);
if (iret==1) {
iret=AsynSrv_Config(&aser->asyn_info, "msecTmo", msecTmo, "idleHdl", idleHdl, NULL);
}
if (iret!=1) { SerA_error(); goto OnError; }
time(&t2);
ecnt=0;
logfileOut(LOG_MAIN, "connection to %s:%d/%d opened (%d sec)\n",
aser->asyn_info.host, aser->asyn_info.port, aser->asyn_info.chan,
t2-t1);
str_copy(aser->host, hostPort);
return((SerChannel *)aser);
} else {
NEW(tser, TermSrvChan); tser->type=TERMSRV_TYPE;
tser->tmo=msecTmo;
if (idleHdl==NULL) {
tser->idleHdl=SerWait;
} else {
tser->idleHdl=idleHdl;
}
ERR_I(CocCreateSockAdr(&sadr, host, atoi(p)));
ERR_SI(tser->fd=socket(AF_INET, SOCK_STREAM, 0));
ERR_SI(connect(tser->fd, (struct sockaddr *)&sadr, sizeof(sadr)));
time(&t2);
ecnt=0;
logfileOut(LOG_MAIN, "connected to %s (%d sec)\n", hostPort, t2-t1);
str_copy(tser->host, hostPort);
return ((SerChannel *)tser);
}
OnError:
time(&t2);
if (ecnt<4) {
logfileOut(LOG_MAIN, "failed after %d sec\n", t2-t1);
ecnt++;
}
return(NULL);
}
int SerSetTmo(SerChannel *serch, int msecTmo) {
AsynSrvChan *aser;
TermSrvChan *tser;
int iret;
if (serch->type==ASYNSRV_TYPE) {
aser=(AsynSrvChan *)serch;
iret=AsynSrv_Config(&aser->asyn_info, "msecTmo", msecTmo, NULL);
if (iret!=1) { SerA_error(); goto OnError; }
} else if (serch->type==TERMSRV_TYPE) {
tser=(TermSrvChan *)serch;
tser->tmo=msecTmo;
}
return 0;
OnError: return -1;
}
void SerClose(SerChannel *serch) {
AsynSrvChan *aser;
TermSrvChan *tser;
if (serch->type==ASYNSRV_TYPE) {
aser=(AsynSrvChan *)serch;
AsynSrv_Close(&aser->asyn_info, 1);
} else if (serch->type==TERMSRV_TYPE) {
tser=(TermSrvChan *)serch;
close(tser->fd);
}
serch->type=0;
}
SerChannel *SerCheck(SerChannel *serch) {
if (serch==NULL || serch->type==0) {
return(NULL);
} else {
return(serch);
}
}
char *SerCmd(SerChannel *serch, char *cmnd) {
int l, n;
AsynSrvChan *aser;
TermSrvChan *tser;
char *result, *pos;
char junk[256];
int iret, incomplete;
l=strlen(cmnd);
if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS);
cmnd[l]=EOT; l++;
cmnd[l]='\0';
logfileOut(LOG_SER, ">%s\n", cmnd);
if (serch->type==ASYNSRV_TYPE) {
aser=(AsynSrvChan *)serch;
iret=AsynSrv_SendCmnds(&aser->asyn_info, &aser->to_host, &aser->from_host, cmnd, NULL);
if (iret!=1) {
SerA_error();
SerClose(serch);
return(NULL);
}
result=AsynSrv_GetReply(&aser->asyn_info, &aser->from_host, NULL);
if (result==NULL) ERR_MSG("empty result");
} else if (serch->type==TERMSRV_TYPE) {
tser=(TermSrvChan *)serch;
ERR_I(iret=SerWait(0, tser->fd));
while (iret>0) { /* skip contents in type-ahead buffer */
ERR_SI(l=recv(tser->fd, junk, sizeof(junk)-1, 0));
if (l==0) {
ErrMsg("disconnected");
SerClose(serch);
goto OnError;
}
junk[l]='\0';
logfileOut(LOG_MAIN, "skipped: '%s'\n", junk);
ERR_I(iret=SerWait(0, tser->fd));
}
iret=send(tser->fd, cmnd, l, 0);
if (iret<0) {
ErrMsg("disconnected");
SerClose(serch);
goto OnError;
}
n=sizeof(tser->res);
pos=tser->res;
result=NULL;
incomplete=1;
while (incomplete) {
/* Wait for an event on tser->fd or a timeout tmo */
iret=tser->idleHdl(tser->tmo, tser->fd);
if (iret==0) {
if (result==NULL) ERR_MSG("timeout");
ERR_MSG("missing terminator");
}
ERR_SI(l=recv(tser->fd, pos, n, 0));
if (l==0) {
ErrMsg("disconnected");
SerClose(serch);
goto OnError;
}
n -= l;
if (n==0) ERR_MSG("answer too long");
while (l>0) {
if (*pos>' ') {
if (result==NULL) result=pos; /* skip trailing white space */
} else if (*pos<' ') { /* all control characters are treated as terminators */
if (result!=NULL) {
*pos='\0';
incomplete=0;
}
}
pos++; l--;
}
}
} else {
serch->type=0;
ERR_MSG("invalid channel");
}
logfileOut(LOG_SER, "<%s\n", result);
return(result);
OnError:
return(NULL);
}
/* obsolete ?
char *SerCmdC(SerChannel *serch, const char *cmnd) {
char cmd[SER_BUF_LEN];
int l;
l=strlen(cmnd);
if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS);
strcpy(cmd, cmnd);
return(SerCmd(serch, cmd));
OnError: return(NULL);
}
*/