/*--------------------------------------------------------------------- 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 #include #include #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; }