/* This script was adapted from the Newport Socket.cpp code to provide TCP/IP sockets for the XPSC8 motion controller using EPICS asynOctetSyncIO.cc By Jon Kelly July 2005 Re-written by Mark Rivers March 2006 */ /* includes */ #ifdef vxWorks #else #define TRUE 1 #define FALSE 0 typedef int BOOL; #endif #include #include #include #include #include #include #include #include #include #include #include #include /* The maximum number of sockets to XPS controllers. The driver uses * one socket per motor plus one per controller, so a maximum of 9 per controller. * This number is used to create an array because the Newport code uses integers for * the socket ID. */ #define MAX_SOCKETS 1000 #define PORT_NAME_SIZE 100 #define ERROR_STRING_SIZE 100 #define DEFAULT_TIMEOUT 0.2 #define MAX_RETRIES 2 static int nextSocket = 0; /* Pointer to the connection info for each socket the asynUser structure is defined in asynDriver.h */ typedef struct { asynUser *pasynUser; asynUser *pasynUserCommon; double timeout; char errorString[ERROR_STRING_SIZE]; int connected; } socketStruct; static socketStruct socketStructs[MAX_SOCKETS]; /***************************************************************************************/ int ConnectToServer(char *IpAddress, int IpPort, double timeout) { char portName[PORT_NAME_SIZE]; char ipString[PORT_NAME_SIZE]; asynUser *pasynUser, *pasynUserCommon; socketStruct *psock; int status; if (nextSocket >= MAX_SOCKETS) { printf("ConnectToServer: too many open sockets, max=%d\n", MAX_SOCKETS); return -1; } /* Create a new asyn port */ epicsSnprintf(ipString, PORT_NAME_SIZE, "%s:%d TCP", IpAddress, IpPort); epicsSnprintf(portName, PORT_NAME_SIZE, "%s:%d:%d", IpAddress, IpPort, nextSocket); /* Create port with noAutoConnect and noProcessEos options */ drvAsynIPPortConfigure(portName, ipString, 0, 1, 1); /* Connect to driver with asynOctet interface */ status = pasynOctetSyncIO->connect(portName, 0, &pasynUser, NULL); if (status != asynSuccess) { printf("ConnectToServer, error calling pasynOctetSyncIO->connect %s\n", pasynUser->errorMessage); return -1; } psock = &socketStructs[nextSocket]; psock->pasynUser = pasynUser; /* Connect to driver with asynCommon interface */ status = pasynCommonSyncIO->connect(portName, 0, &pasynUserCommon, NULL); if (status != asynSuccess) { printf("ConnectToServer, error calling pasynCommonSyncIO->connect %s\n", pasynUserCommon->errorMessage); return -1; } psock->pasynUserCommon = pasynUserCommon; /* Connect to controller */ status = pasynCommonSyncIO->connectDevice(pasynUserCommon); if (status != asynSuccess) { printf("ConnectToServer, error calling pasynCommonSyncIO->connectDevice port=%s error=%s\n", portName, pasynUserCommon->errorMessage); return -1; } psock->timeout = timeout; psock->connected = 1; strcpy(psock->errorString, ""); nextSocket++; return nextSocket-1; } /***************************************************************************************/ void SetTCPTimeout(int SocketIndex, double TimeOut) { if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) { printf("SetTCPTimeout, SocketIndex=%d, must be >=0 and < %d\n", SocketIndex, nextSocket); return; } socketStructs[SocketIndex].timeout = TimeOut; } /***************************************************************************************/ void SendAndReceive (int SocketIndex, char buffer[], char valueRtrn[], int returnSize) { size_t nbytesOut; size_t nbytesIn; int eomReason; int bufferLength; socketStruct *psock; int status; int retries; int errStat; /* Check to see if the Socket is valid! */ bufferLength = strlen(buffer); if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) { printf("SendAndReceive: invalid SocketIndex %d\n", SocketIndex); strcpy(valueRtrn,"-22"); return; } psock = &socketStructs[SocketIndex]; if (!psock->connected) { printf("SendAndReceive: socket not connected %d\n", SocketIndex); strcpy(valueRtrn,"-22"); return; } /* If timeout > 0. then we do a write read. If < 0. then write. */ if (psock->timeout > 0.0) { status = pasynOctetSyncIO->writeRead(psock->pasynUser, (char const *)buffer, bufferLength, valueRtrn, returnSize, psock->timeout, &nbytesOut, &nbytesIn, &eomReason); if ( status != asynSuccess ) { asynPrint(psock->pasynUser, ASYN_TRACE_ERROR, "SendAndReceive error calling writeRead, output=%s status=%d, error=%s\n", buffer, status, psock->pasynUser->errorMessage); } asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER, "SendAndReceive, sent: '%s', received: '%s'\n", buffer, valueRtrn); } else { /* This is typically used for the "Move" commands, and we don't want to wait for the response */ /* Fake the response by putting "-1" (for error) or "0" (for success) in the return string */ for (retries=0; retrieswriteRead(psock->pasynUser, (char const *)buffer, bufferLength, valueRtrn, returnSize, -psock->timeout, &nbytesOut, &nbytesIn, &eomReason); if (status == asynError) { asynPrint(psock->pasynUser, ASYN_TRACE_ERROR, "SendAndReceive error calling write, output=%s status=%d, error=%s\n", buffer, status, psock->pasynUser->errorMessage); strcpy(valueRtrn, "-1"); break; } asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER, "SendAndReceive, sent: '%s'\n", buffer); /* A timeout is OK */ if (status == asynTimeout) { asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER, "SendAndReceive, timeout on read\n"); break; } else { asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER, "SendAndReceive, read: '%s'\n", valueRtrn); errStat = atoi(valueRtrn); if (errStat == 0) break; /* All done */ if (errStat == -1) continue; /* Error that previous command not complete */ asynPrint(psock->pasynUser, ASYN_TRACE_ERROR, "SendAndReceive unexpected response =%s\n", valueRtrn); break; } } strcpy(valueRtrn, "0"); } } /***************************************************************************************/ void CloseSocket(int SocketIndex) { socketStruct *psock; asynUser *pasynUser; int status; if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) { printf("CloseSocket: invalid SocketIndex %d\n", SocketIndex); return; } psock = &socketStructs[SocketIndex]; pasynUser = psock->pasynUserCommon; status = pasynCommonSyncIO->disconnectDevice(pasynUser); if (status != asynSuccess ) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "CloseSocket: error calling pasynCommonSyncIO->disconnect, status=%d, %s\n", status, pasynUser->errorMessage); return; } psock->connected = 0; } /***************************************************************************************/ void closeXPSSockets(void) { int i; for (i=0; i= nextSocket)) { printf("GetError: invalid SocketIndex %d\n", SocketIndex); return "Invalid socket"; } return socketStructs[SocketIndex].errorString; } /***************************************************************************************/ void strncpyWithEOS(char * szStringOut, const char * szStringIn, int nNumberOfCharToCopy, int nStringOutSize) { if (nNumberOfCharToCopy < nStringOutSize) { strncpy (szStringOut, szStringIn, nNumberOfCharToCopy); szStringOut[nNumberOfCharToCopy] = '\0'; } else { strncpy (szStringOut, szStringIn, nStringOutSize - 1); szStringOut[nStringOutSize - 1] = '\0'; } }