- Fixed a bug fix with Fixed motor in TAS code
- Made AMOR write HDF-5 data in chunks - Added driver for a PSI-DSP magnet controller as used at SLS - Added code for directly accessing RS232 controllers connected to a terminal server, thereby bypassing the SerPortServer - A rounding problem in the PSD histogram memory was resolved.
This commit is contained in:
619
rs232controller.c
Normal file
619
rs232controller.c
Normal file
@ -0,0 +1,619 @@
|
||||
/*---------------------------------------------------------------------
|
||||
R S 2 3 2 C o n t r o l l e r
|
||||
|
||||
A general object which represents a controller connected to the network
|
||||
via a terminal server. This bypasses David Maden's SerPortServer software.
|
||||
Basic facilities are provided for writinga nd reading to and from the
|
||||
device. For more information see the rs232controller.tex file.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
Mark Koennecke, October 2001
|
||||
-----------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "splitter.h"
|
||||
#include "rs232controller.h"
|
||||
|
||||
/*
|
||||
own error codes
|
||||
*/
|
||||
#define NOTCONNECTED -2700
|
||||
#define BADMEMORY -2701
|
||||
#define TIMEOUT -2702
|
||||
#define FAILEDCONNECT -2703
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
void setRS232SendTerminator(prs232 self, char *term)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if(self->sendTerminator != NULL)
|
||||
{
|
||||
free(self->sendTerminator);
|
||||
}
|
||||
|
||||
if(term != NULL)
|
||||
{
|
||||
self->sendTerminator = strdup(term);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->sendTerminator = NULL;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
void setRS232ReplyTerminator(prs232 self, char *term)
|
||||
{
|
||||
assert(self);
|
||||
if(self->replyTerminator != NULL)
|
||||
{
|
||||
free(self->replyTerminator);
|
||||
}
|
||||
|
||||
if(term != NULL)
|
||||
{
|
||||
self->replyTerminator = strdup(term);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->replyTerminator = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
void setRS232Timeout(prs232 self, int timeout)
|
||||
{
|
||||
assert(self);
|
||||
self->timeout = timeout;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
int writeRS232(prs232 self, void *data, int dataLen)
|
||||
{
|
||||
char *pPtr = NULL;
|
||||
int iRet;
|
||||
|
||||
|
||||
assert(self);
|
||||
|
||||
/*
|
||||
catch an unconnected socket
|
||||
*/
|
||||
if(!self->pSock)
|
||||
{
|
||||
return NOTCONNECTED;
|
||||
}
|
||||
|
||||
/*
|
||||
do the terminator processing, if required.
|
||||
If new data had to be allocated in order to add the terminator,
|
||||
pPtr is not NULL. I any other case it is.
|
||||
*/
|
||||
if(self->sendTerminator != NULL)
|
||||
{
|
||||
pPtr = (char *)data;
|
||||
if(strstr(pPtr,self->sendTerminator) == NULL)
|
||||
{
|
||||
/*
|
||||
the terminator is missing. add it.
|
||||
*/
|
||||
pPtr = (char *)malloc((dataLen + strlen(self->sendTerminator) +2)
|
||||
*sizeof(char));
|
||||
if(!pPtr)
|
||||
{
|
||||
return BADMEMORY;
|
||||
}
|
||||
strcpy(pPtr,(char *) data);
|
||||
strcat(pPtr,self->sendTerminator);
|
||||
dataLen += strlen(self->sendTerminator);
|
||||
data = pPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPtr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
send
|
||||
*/
|
||||
iRet = NETWrite(self->pSock,data,dataLen);
|
||||
|
||||
if(pPtr != NULL)
|
||||
free(pPtr);
|
||||
|
||||
return iRet;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int readRS232(prs232 self, void *data, int *dataLen)
|
||||
{
|
||||
long lRead;
|
||||
int iRet;
|
||||
size_t rLength;
|
||||
|
||||
assert(self);
|
||||
/*
|
||||
catch an unconnected socket
|
||||
*/
|
||||
if(!self->pSock)
|
||||
{
|
||||
return NOTCONNECTED;
|
||||
}
|
||||
|
||||
iRet = NETAvailable(self->pSock,self->timeout);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
else if(iRet == 0)
|
||||
{
|
||||
*dataLen = 0;
|
||||
return TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
rLength = *dataLen;
|
||||
lRead = recv(self->pSock->sockid, data,rLength,0);
|
||||
if(lRead >= 0)
|
||||
{
|
||||
*dataLen = lRead;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)lRead;
|
||||
}
|
||||
}
|
||||
/*
|
||||
not reached
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int availableRS232(prs232 self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
/*
|
||||
catch an unconnected socket
|
||||
*/
|
||||
if(!self->pSock)
|
||||
{
|
||||
return NOTCONNECTED;
|
||||
}
|
||||
|
||||
return NETAvailable(self->pSock,self->timeout);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
int transactRS232(prs232 self, void *send, int sendLen,
|
||||
void *reply, int replyLen)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
|
||||
/*
|
||||
catch an unconnected socket
|
||||
*/
|
||||
if(!self->pSock)
|
||||
{
|
||||
return NOTCONNECTED;
|
||||
}
|
||||
|
||||
/*
|
||||
write data
|
||||
*/
|
||||
iRet = writeRS232(self,send,sendLen);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
read
|
||||
*/
|
||||
memset(reply,0,replyLen);
|
||||
iRet = NETReadTillTerm(self->pSock,self->timeout,self->replyTerminator,
|
||||
reply, replyLen);
|
||||
if(iRet == 0)
|
||||
{
|
||||
return TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
void getRS232Error(int iCode, char *errorBuffer,
|
||||
int errorBufferLen)
|
||||
{
|
||||
/*
|
||||
the error code is either one of our errors, or an errno code from
|
||||
the system
|
||||
*/
|
||||
switch(iCode)
|
||||
{
|
||||
case BADMEMORY:
|
||||
strncpy(errorBuffer,
|
||||
"Out of memory for appending terminators",
|
||||
errorBufferLen);
|
||||
break;
|
||||
case NOTCONNECTED:
|
||||
strncpy(errorBuffer,
|
||||
"Not connected!",
|
||||
errorBufferLen);
|
||||
break;
|
||||
case TIMEOUT:
|
||||
strncpy(errorBuffer,
|
||||
"Timeout reading data",
|
||||
errorBufferLen);
|
||||
break;
|
||||
case FAILEDCONNECT:
|
||||
strncpy(errorBuffer,
|
||||
"Failed to connect to terminal server",
|
||||
errorBufferLen);
|
||||
break;
|
||||
default:
|
||||
strncpy(errorBuffer,strerror(errno),
|
||||
errorBufferLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
int initRS232(prs232 self)
|
||||
{
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
|
||||
if(self->pSock != NULL)
|
||||
{
|
||||
NETClosePort(self->pSock);
|
||||
self->pSock = NULL;
|
||||
}
|
||||
self->pSock = NETConnect(self->pHost, self->iPort);
|
||||
if(!self->pSock)
|
||||
return FAILEDCONNECT;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static void KillRS232(void *pData)
|
||||
{
|
||||
prs232 self = (prs232)pData;
|
||||
if(!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(self->pDes)
|
||||
{
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if(self->sendTerminator != NULL)
|
||||
{
|
||||
free(self->sendTerminator);
|
||||
}
|
||||
if(self->replyTerminator != NULL)
|
||||
{
|
||||
free(self->replyTerminator);
|
||||
}
|
||||
if(self->pSock)
|
||||
{
|
||||
NETClosePort(self->pSock);
|
||||
}
|
||||
if(self->pHost)
|
||||
{
|
||||
free(self->pHost);
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int checkSet(SConnection *pCon, int argc, int rights)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(SCMatchRights(pCon,rights))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
not reached
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void encodeTerminator(char *result, char *terminator)
|
||||
{
|
||||
int i, len;
|
||||
char pBuffer[10];
|
||||
|
||||
if(terminator == NULL)
|
||||
{
|
||||
result[0] = '\0';
|
||||
}
|
||||
len = strlen(terminator);
|
||||
sprintf(pBuffer,"0x%x",(int)terminator[0]);
|
||||
strcpy(result,pBuffer);
|
||||
for(i = 1; i < len; i++)
|
||||
{
|
||||
sprintf(pBuffer,"0x%x",(int)terminator[i]);
|
||||
strcat(result,pBuffer);
|
||||
}
|
||||
}
|
||||
extern char *stptok(char *pPtr, char *pToken, int tokenLen, char *term);
|
||||
/*--------------------------------------------------------------------*/
|
||||
char *decodeTerminator(char *code)
|
||||
{
|
||||
int count = 0, icode;
|
||||
char *pResult;
|
||||
char *pPtr, pToken[10];
|
||||
|
||||
/*
|
||||
max 10 terminators!
|
||||
*/
|
||||
pResult = (char *)malloc(10*sizeof(char));
|
||||
if(!pResult)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
memset(pResult,0,10);
|
||||
|
||||
pToken[0] = '0';
|
||||
/*
|
||||
I seem to get an empty token on the first call to stptok, this is why
|
||||
I do 2 stptoks. Strange and wonderful.
|
||||
*/
|
||||
pPtr = stptok(code,pToken+1,9,"0");
|
||||
pPtr = stptok(pPtr,pToken+1,9,"0");
|
||||
while(pPtr != NULL)
|
||||
{
|
||||
sscanf(pToken,"%x",&icode);
|
||||
pResult[count] = (char)icode;
|
||||
count++;
|
||||
pPtr = stptok(pPtr,pToken+1,9,"0");
|
||||
}
|
||||
return pResult;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
int RS232Action(SConnection *pCon, SicsInterp *pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
prs232 self = NULL;
|
||||
char pError[256];
|
||||
char pBuffer[8192], pReply[8192];
|
||||
char *pPtr = NULL;
|
||||
int iRet, iRead = 8191;
|
||||
|
||||
self = (prs232)pData;
|
||||
assert(self);
|
||||
assert(pCon);
|
||||
|
||||
/*
|
||||
check for arguments
|
||||
*/
|
||||
if(argc < 2)
|
||||
{
|
||||
sprintf(pError,"ERROR: insufficient no of arguments to %s",argv[0]);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"sendterminator") == 0)
|
||||
{
|
||||
if(checkSet(pCon,argc,usMugger))
|
||||
{
|
||||
pPtr = decodeTerminator(argv[2]);
|
||||
setRS232SendTerminator(self,pPtr);
|
||||
if(pPtr)
|
||||
free(pPtr);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
encodeTerminator(pBuffer,self->sendTerminator);
|
||||
sprintf(pError,"%s.sendTerminator = \"%s\"",argv[0],
|
||||
pBuffer);
|
||||
SCWrite(pCon,pError,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"timeout") == 0)
|
||||
{
|
||||
if(checkSet(pCon,argc,usMugger))
|
||||
{
|
||||
setRS232Timeout(self,atoi(argv[2]));
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pError,"%s.Timeout = %d",argv[0],self->timeout);
|
||||
SCWrite(pCon,pError,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"replyterminator") == 0)
|
||||
{
|
||||
if(checkSet(pCon,argc,usMugger))
|
||||
{
|
||||
pPtr = decodeTerminator(argv[2]);
|
||||
setRS232ReplyTerminator(self,pPtr);
|
||||
if(pPtr)
|
||||
free(pPtr);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
encodeTerminator(pBuffer,self->replyTerminator);
|
||||
sprintf(pError,"%s.replyTerminator = \"%s\"",argv[0],
|
||||
pBuffer);
|
||||
SCWrite(pCon,pError,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"write") == 0)
|
||||
{
|
||||
Arg2Text(argc-2,argv+2,pBuffer,8191);
|
||||
iRet = writeRS232(self,pBuffer,strlen(pBuffer));
|
||||
if(iRet < 0)
|
||||
{
|
||||
getRS232Error(iRet,pError,255);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[1],"read") == 0)
|
||||
{
|
||||
if(!availableRS232(self))
|
||||
{
|
||||
SCWrite(pCon,"Nothing to read!",eError);
|
||||
return 1;
|
||||
}
|
||||
iRet = readRS232(self,pBuffer,&iRead);
|
||||
if(iRet < 0)
|
||||
{
|
||||
getRS232Error(iRet,pError,255);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
SCWrite(pCon,pBuffer,eValue);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[1],"available") == 0)
|
||||
{
|
||||
iRet = availableRS232(self);
|
||||
if(iRet < 0)
|
||||
{
|
||||
getRS232Error(iRet,pError,255);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
else if(iRet == 0)
|
||||
{
|
||||
SCWrite(pCon,"No data pending",eValue);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCWrite(pCon,"Data available",eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"send") == 0)
|
||||
{
|
||||
Arg2Text(argc-2,argv+2,pBuffer,8191);
|
||||
iRet = transactRS232(self,pBuffer,strlen(pBuffer),
|
||||
pReply,iRead);
|
||||
if(iRet < 0)
|
||||
{
|
||||
getRS232Error(iRet,pError,255);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
SCWrite(pCon,pReply,eValue);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[1],"init") == 0)
|
||||
{
|
||||
iRet = initRS232(self);
|
||||
if(iRet != 1)
|
||||
{
|
||||
sprintf(pError,"ERROR: reinitializing connection to %s at %d failed",
|
||||
self->pHost, self->iPort);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pError,"ERROR: %s does not understand %s",argv[0], argv[1]);
|
||||
SCWrite(pCon,pError,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
int RS232Factory(SConnection *pCon, SicsInterp *pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
prs232 pNew = NULL;
|
||||
int iRet;
|
||||
char pError[256];
|
||||
|
||||
if(argc < 4)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: insufficient no of arguments to RS232Factory",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
create data structure and open port
|
||||
*/
|
||||
pNew = (prs232)malloc(sizeof(rs232));
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in RS232Factory",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pNew, 0, sizeof(rs232));
|
||||
|
||||
pNew->pHost = strdup(argv[2]);
|
||||
pNew->iPort = atoi(argv[3]);
|
||||
pNew->sendTerminator = strdup("\r");
|
||||
pNew->replyTerminator = strdup("\n");
|
||||
pNew->timeout = 1000;
|
||||
pNew->pDes = CreateDescriptor("RS232 Controller");
|
||||
if(!pNew->pDes || !pNew->pHost ||
|
||||
!pNew->replyTerminator || !pNew->sendTerminator)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: out of memory in RS232Factory",eError);
|
||||
return 0;
|
||||
}
|
||||
pNew->pSock = NETConnect(pNew->pHost, pNew->iPort);
|
||||
if(!pNew->pSock)
|
||||
{
|
||||
sprintf(pError,"ERROR: failed to connect to %s at port %d",
|
||||
pNew->pHost, pNew->iPort);
|
||||
SCWrite(pCon,pError,eError);
|
||||
}
|
||||
|
||||
/*
|
||||
create the command
|
||||
*/
|
||||
iRet = AddCommand(pSics,argv[1],RS232Action, KillRS232, pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pError,"ERROR: duplicate command %s not created", argv[1]);
|
||||
SCWrite(pCon,pError,eError);
|
||||
KillRS232(pNew);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user