diff --git a/site_ansto/Makefile b/site_ansto/Makefile index 1306c959..5f7c7029 100644 --- a/site_ansto/Makefile +++ b/site_ansto/Makefile @@ -75,7 +75,7 @@ OBJ= site_ansto.o anstoutil.o\ lakeshore340.o lakeshore340driv.o \ nhq200.o nhq200driv.o \ counterdriv.o safetyplc.o\ - ../psi/tcpdocho.o ../psi/tcpdornier.o \ + ../psi/tcpdornier.o \ anstohttp.o \ hmcontrol_ansto.o diff --git a/site_ansto/hardsup/chopper.c b/site_ansto/hardsup/chopper.c new file mode 100644 index 00000000..1b9d7163 --- /dev/null +++ b/site_ansto/hardsup/chopper.c @@ -0,0 +1,1034 @@ +/*-------------------------------------------------------------- + This is a driver for the newer Astrium == Dornier chopper + systems which use a TCP/IP server for communication. + This driver has to take care of some ugliness: + - As of december 2005, the communication is in unicode! + To go from ASCII to unicode and back one has to + add a 0x00 before each character or to remove it. + - The controller is slow in responding and the controller + must be watched in the environment monitor. This is taken + care of by a special SICS task which updates the status + regularly and returning cached values anytime else. + + + Inititial Implementation: Mark Koennecke, December 2005 + ------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*======================================================================== + Our private data structure + ========================================================================*/ +#define ASYNMODE 0 +#define SYNCMODE 1 +typedef struct{ + prs232 controller; + int iRefreshIntervall; + time_t nextRefresh; + long lTask; + pStringDict parameters; + int lastError; + int numChoppers; + int mode; + int timeout; + char user[132]; + char pword[132]; + int stop; + int busy; + char *config; +}TcpDoCho, *pTcpDoCho; + +static int fixDirection(pTcpDoCho self, int choNum, char *value, int value_len); + +/*----------------------------------------------------------------------- +Error codes: +-----------------------------------------------------------------------*/ +#define WRONGMODE -8301 +#define BADCONVERSION -8302 +#define FAILEDCOMMAND -8303 +#define BADWRITE -8304 +#define BADRESPONSE -8306 +#define UNDRIVABLE -8307 +#define BADPAR -8308 +#define ESTOP -8309 +#define BADVALUE -8310 + +extern char *trim(char *str); +#define ABS(x) (x < 0 ? -(x) : (x)) + +#define SPEEDTOL 2 +#define PHASETOL 0.2 +#define VALUE_LEN 80 +/*=============== support functions ===================================*/ +static int asciiToUnicode(char *input, char **output){ + int len, i; + char *result = NULL; + + len = strlen(input); + result = (char *)malloc(2*len*sizeof(char)); + if(result == NULL){ + return 0; + } + memset(result,0,2*len*sizeof(char)); + for(i = 0; i < len; i++){ + result[i*2] = input[i]; + } + *output = result; + return 2*len; +} +/*-------------------------------------------------------------------*/ +static int unicodeToAscii(char *input, int len, char **output){ + int i, alen; + char *result = NULL; + + alen = len/2; + + result = (char *)malloc((alen+1)*sizeof(char)); + if(result == NULL){ + return 0; + } + memset(result,0,(alen+1)*sizeof(char)); + for(i = 0; i < alen; i++){ + result[i] = input[i*2]; + } + *output = result; + return alen; +} +/*----------------------------------------------------------------*/ +static int tcpDoChoSend(pTcpDoCho self, char *command, int choNum, + char *value){ + char buffer[1024]; + int sendlen, status; + + /* + format and send command + */ + self->lastError = 0; + if(choNum < 0){ + snprintf(buffer,1023,"#SOS#%s \r\n",command); + } else if(value != NULL){ + snprintf(buffer,1023,"#SOS#%s%1.1d: %s\r\n",command, choNum, + value); + } else { + snprintf(buffer,1023,"#SOS#%s%1.1d:\r\n",command, choNum); + } + sendlen = strlen(buffer); + if(sendlen == 0){ + self->lastError = BADCONVERSION; + return 0; + } + status = send(self->controller->pSock->sockid,buffer,sendlen,0); + if(status < 0){ + self->lastError = BADWRITE; + return 0; + } + return 1; +} +/*----------------------------------------------------------------*/ +static int statusComplete(char *statusMessage){ + char *pPtr = NULL; + + /* + currently the status message has no terminator. I try to find + the last component of the message which happens to be TIME and + the last # after that + */ + pPtr = strstr(statusMessage,"TIME"); + if(pPtr != NULL){ + pPtr = strstr(pPtr+6,"#"); + if(pPtr != NULL){ + return 1; + } else { + return 0; + } + } else { + return 0; + } +} +/*---------------------------------------------------------------*/ +static int readChopperNum(char *entry){ + int num; + char *pPtr = NULL; + + pPtr = strstr(entry,"CH"); + if(pPtr == NULL){ + return -1; + } + sscanf(pPtr+3,"%d",&num); + return num; +} +/*---------------------------------------------------------------*/ +static void addEntry(pTcpDoCho self, int choNum, char *entry){ + char name[80], value[VALUE_LEN], *pPtr = NULL; + char num[5]; + + memset(name,0,80); + memset(value,0,80); + snprintf(num,5,"_%1.1d",choNum); + pPtr = strstr(entry,"="); + if(pPtr != NULL){ + strncpy(name,entry,pPtr -entry); + strcpy(value,pPtr+1); +#if 0 + if(strcmp(name,"ASPEED") ==0) { + fixDirection(self, choNum, value, VALUE_LEN); + if (errno != 0) return; + } +#endif + strncat(trim(name),num,80-strlen(trim(name))); + if(StringDictExists(self->parameters,name)){ + StringDictUpdate(self->parameters,name,trim(value)); + } else { + StringDictAddPair(self->parameters,name,trim(value)); + } + } +} +/*----------------------------------------------------------------*/ +static int parseStatus(pTcpDoCho self, char *statusMessage){ + int choNum; + char entry[80], *pPtr; + + pPtr = statusMessage; + + /* skip over SOS */ + pPtr = stptok(pPtr,entry,79,"#"); + pPtr = stptok(pPtr,entry,79,"#"); + pPtr = stptok(pPtr,entry,79,"#"); + + choNum = readChopperNum(entry); + if(choNum < 0){ + self->lastError = BADRESPONSE; + return 0; + } + while((pPtr = stptok(pPtr,entry,79,"#")) != NULL){ + addEntry(self,choNum,entry); + memset(entry,0,80); + } + return 1; +} +/*-----------------------------------------------------------------*/ +static int tcpDoChoReceive(pTcpDoCho self){ + char buffer[1024]; + int len, bytesRead, bufferStart, status; + time_t endTime; + + endTime = time(NULL) + self->timeout; + bufferStart = 0; + bytesRead = 0; + memset(buffer,0,1024*sizeof(char)); + while(time(NULL) < endTime){ + if(availableRS232(self->controller)){ + bytesRead += recv(self->controller->pSock->sockid,buffer+bufferStart, + 1024 - bytesRead,0); + if(bytesRead < 0){ + self->lastError = BADREAD; + return 0; + } + if(strstr(buffer,"State") != NULL){ + if(statusComplete(buffer) == 0) { + continue; + } else { + status = parseStatus(self,buffer); + return status; + } + } + if(strstr(buffer,"ACCEPT") != NULL){ + return 1; + } else if(strstr(buffer,"NCCEPT") != NULL){ + self->lastError = FAILEDCOMMAND; + return 0; + } else { + self->lastError = BADRESPONSE; + return 0; + } + } else { + SicsWait(1); + } + } + self->lastError = TIMEOUT; + return 0; +} +/*-----------------------------------------------------------------*/ +static int tcpDoChoCommand(pTcpDoCho self, char *command, int choNum, + char *value){ + int status; + + status = tcpDoChoSend(self,command,choNum,value); + if(status == 0){ + return 0; + } + return tcpDoChoReceive(self); +} +/*---------------------------------------------------------------*/ +/* TODO Check for response on authentication + * authentication succeeded: #SES#Hello + * authentication failed: #SES#You are not a valid user, try again! + * Make sure that ch2,3,4 are set to MW on init + */ +static int TcpDoChoConnect(pTcpDoCho self){ + int status, sendLen, readLen; + char buffer[256]; + + status = initRS232(self->controller); + if(status != 1){ + self->lastError = status; + return 0; + } + setRS232Timeout(self->controller,5); + + readLen = 255; + readRS232(self->controller,(void *)buffer,&readLen); + + /* + user name + */ + snprintf(buffer,255,"user:%s\r\n",self->user); + sendLen = strlen(buffer); + if(sendLen == 0){ + self->lastError = BADCONVERSION; + return 0; + } + status = send(self->controller->pSock->sockid,buffer,sendLen,0); + if(status < 0){ + self->lastError = BADSEND; + return 0; + } + readLen = 255; + readRS232(self->controller,(void *)buffer,&readLen); + + /* + password + */ + snprintf(buffer,255,"password:%s\r\n",self->pword); + sendLen = strlen(buffer); + if(sendLen == 0){ + self->lastError = BADCONVERSION; + return 0; + } + status = send(self->controller->pSock->sockid,buffer,sendLen,0); + if(status < 0){ + self->lastError = BADSEND; + return 0; + } + readLen = 255; + readRS232(self->controller,(void *)buffer,&readLen); + + /* + TODO: responses should be checked to test for a valid login. + I do not know at this time how the controller reacts upon a + bad login. + */ + + return 1; +} +/*==================== actual driver implementation code ==================*/ +static int TcpChopperTask(void *pData){ + pCodri self = NULL; + pTcpDoCho pPriv = NULL; + int status, code, i; + char buffer[80]; + char error[512]; + + self = (pCodri)pData; + assert(self); + pPriv = (pTcpDoCho)self->pPrivate; + assert(pPriv); + + if(pPriv->stop == 1){ + return 0; + } + + if(time(NULL) > pPriv->nextRefresh){ + if(pPriv->lastError != 0){ + self->GetError(self,&code,buffer,79); + snprintf(error,511,"WARNING: chopper tries to fix: %s",buffer); + WriteToCommandLog("Chopper-task:>>", error); + status = self->TryFixIt(self,code); + if(status == CHFAIL){ + pPriv->nextRefresh = time(NULL) + pPriv->iRefreshIntervall; + return 1; + } + } else { + pPriv->busy = 1; + for(i = 0; i < pPriv->numChoppers; i++){ + status = tcpDoChoCommand(pPriv,"STATE ", i+1,NULL); + if(status != 1){ + /* + force error correction + */ + return 1; + } + } + pPriv->nextRefresh = time(NULL) + pPriv->iRefreshIntervall; + pPriv->busy = 0; + } + } + return 1; +} +/*------------------------------------------------------------------------------*/ +static int TcpDoChoKill(pCodri self){ + pTcpDoCho pPriv = NULL; + + pPriv = (pTcpDoCho)self->pPrivate; + if(!pPriv) + return 1; + + if(pPriv->controller != NULL){ + KillRS232(pPriv->controller); + } + if(pPriv->parameters != NULL){ + DeleteStringDict(pPriv->parameters); + } + if(pPriv->config != NULL){ + free(pPriv->config); + } + free(pPriv); + return 1; +} +/*-------------------------------------------------------------------*/ +static int TcpDoChoConfigure(pCodri pDriv){ + pTcpDoCho self = NULL; + int status; + char *pPtr = NULL; + char command[80]; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + if(self->config != NULL){ + pPtr = self->config; + while( (pPtr = stptok(pPtr,command,79,"\n")) != NULL){ + status = tcpDoChoCommand(self,command,-1,NULL); + if(status != 1){ + return 0; + } + } + } + return 1; +} +/*---------------------------------------------------------------------*/ +static int TcpDoChoInit(pCodri pDriv){ + pTcpDoCho self = NULL; + int status; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + self->lastError = 0; + self->stop = 0; + self->nextRefresh = 0; + + status = TcpDoChoConnect(self); + if(status != 1){ + return 0; + } + + status = TcpDoChoConfigure(pDriv); + if(status != 1){ + return 0; + } +#if 0 + /* start the update task */ + if(self->lTask == 0){ + self->lTask = TaskRegister(pServ->pTasker, + TcpChopperTask, + NULL, + NULL, + pDriv, + 1); + } +#endif + return 1; +} +/*-------------------------------------------------------------------*/ +static void waitForBusy(pTcpDoCho self){ + time_t endTime; + + endTime = time(NULL) + 10 *60; /* max 10 min */ + while(time(NULL) < endTime){ + if(self->busy == 1){ + SicsWait(3); + } else { + return; + } + } + WriteToCommandLog("Chopper-task>> ","WARNING: timeout on busy flag, flag forced"); + self->busy = 0; +} +/*----------------------------------------------------------------------*/ +static int TcpDoChoClose(pCodri pDriv){ + pTcpDoCho self = NULL; + int status; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + self->stop = 1; + if(self->controller != NULL){ + KillRS232(self->controller); + self->controller = NULL; + } + return 1; +} +/*----------------------------------------------------------------------*/ +static int dissectName(char *name, char par[80], int *num){ + char *pPtr = NULL; + + pPtr = strrchr(name,(int)'_'); + if(pPtr == NULL){ + return 0; + } + memset(par,0,80*sizeof(char)); + strncpy(par,name,pPtr - name); + if(sscanf(pPtr+1,"%d",num) != 1){ + return 0; + } + return 1; +} +/* Use this to coerce speed and phase for choppers 2 and 3 + * into the same coordinate convention as chopper 1. + * errno = 0 if successful + * on failure errorcode is set in lastError + */ +static int fixDirection(pTcpDoCho self, int choNum, char *value, int value_len) { + double dValue; + errno=0; + if (choNum == 2 || choNum == 3) { + dValue=strtod(value,NULL); + if (errno != 0) { + self->lastError = BADVALUE; + } + dValue = -1.0*dValue; + snprintf(value, value_len, "%5.1f", dValue); + } +} + +/*----------------------------------------------------------------------*/ +static int TcpDoChoSetPar2(pCodri pDriv, char *parname, char *value){ + + pTcpDoCho self = NULL; + int status, choNum; + char par[80], buffer[80], state[80]; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + + /* + force status requests right after setting something in order + to make the stored status represent the new target values + */ + if(dissectName(parname,par,&choNum)){ + /* + check for emergency stop + */ + snprintf(buffer,79,"State_%1.1d",choNum); + memset(state,0,80*sizeof(char)); + StringDictGet(self->parameters,buffer,state,79); + if(strstr(state,"E-Stop") != NULL){ + self->lastError = ESTOP; + return 0; + } + + if(strcmp(par,"speed") == 0){ + waitForBusy(self); + status = tcpDoChoCommand(self,"SPEED ",choNum,trim(value)); + tcpDoChoCommand(self,"STATE ",choNum,NULL); + if(status != 1){ + return 0; + } else { + return 1; + } + } else if(strcmp(par,"phase") == 0){ + waitForBusy(self); + if (errno != 0) + return 0; + status = tcpDoChoCommand(self,"PHASE ",choNum,trim(value)); + tcpDoChoCommand(self,"STATE ",choNum,NULL); + if(status != 1){ + return 0; + } else { + return 1; + } + } + } + self->lastError = UNDRIVABLE; + return 0; +} +/*-----------------------------------------------------------------------*/ +static int TcpDoChoHalt(pCodri pDriv){ + + pTcpDoCho self = NULL; + int status; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + waitForBusy(self); + tcpDoChoCommand(self,"ESTOP :",-1,NULL); + return 1; +} +/*-----------------------------------------------------------------------*/ +static int TcpDoChoSetPar(pCodri pDriv, char *parname, float fValue){ + + pTcpDoCho self = NULL; + int status, choNum; + char value[80]; + char par[80]; + + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + if(dissectName(parname,par,&choNum)){ + if(strcmp(par,"speed") == 0){ + snprintf(value,79,"%5.1f", fValue); + return TcpDoChoSetPar2(pDriv,parname,value); + } else if(strcmp(par,"phase") == 0){ + snprintf(value,79,"%6.2f",fValue); + return TcpDoChoSetPar2(pDriv,parname,value); + } + } + if(strcmp(parname,"updateintervall") == 0){ + sprintf(value,"%d",(int)fValue); + StringDictUpdate(self->parameters,"updateintervall",value); + self->iRefreshIntervall = (int)fValue; + return 1; + } else { + snprintf(value,79,"%f",fValue); + return TcpDoChoSetPar2(pDriv,parname,value); + } +} +/*---------------------------------------------------------------------*/ +static int TcpDoChoGetPar(pCodri pDriv, char *parname, + char *pBuffer, int iBuflen){ + pTcpDoCho self = NULL; + int status = 0, choNum, i, j, ready; + char par[80], buffer[80], value[80]; + float val, aspeed, rspeed, aphase, rphase, delta; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + if(strcmp(parname,"status") == 0){ + ready=1; + for (i=1; i<=4; i++) { + tcpDoChoCommand(self,"STATE ",i,NULL); + snprintf(buffer,80,"MONIT_%1.1d", i); + status = StringDictGet(self->parameters,buffer,value,80); + if (strcmp(value,"ok") != 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: monitor %d = %s", i, value); + ready=0; + break; + } + snprintf(buffer,80,"State_%1.1d", i); + status = StringDictGet(self->parameters,buffer,value,80); + if (strcmp(value,"Brake") == 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: Chopper %d braking",i); + ready=0; + break; + } else if (strcmp(value,"Commutation") == 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: Calibrating"); + ready=0; + break; + } else if (strcmp(value,"Inactive") == 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: Inactive, may need calibrating"); + ready=0; + break; + } else if (strcmp(value,"E-Stop") == 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: State is EMERGENCY STOP"); + ready=0; + break; + } else if (i>1 && strcmp(value,"Asynchron.") == 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: Chopper %d is set to Asynchronous",i); + ready=0; + break; + } + snprintf(buffer,80,"ASPEED_%1.1d", i); + status = StringDictGet(self->parameters,buffer,value,80); + sscanf(value, "%f", &aspeed); + snprintf(buffer,80,"RSPEED_%1.1d", i); + status = StringDictGet(self->parameters,buffer,value,80); + sscanf(value, "%f", &rspeed); + delta = ABS(ABS(aspeed) - ABS(rspeed)); + if(delta > SPEEDTOL){ + snprintf(pBuffer, iBuflen, "NOTREADY: Current speed %5.2f != requested speed %5.2f for chopper %d", aspeed, rspeed,i); + ready=0; + break; + } + if (i > 1) { + snprintf(buffer,80,"APHASE_%1.1d", i); + status = StringDictGet(self->parameters,buffer,value,80); + if (strcmp(value,"999.99") == 0) { + snprintf(pBuffer, iBuflen, "NOTREADY: phase=%s on CH%d, press 'Accept' on Astrium program", value,i); + ready=0; + break; + } + sscanf(value, "%f", &aphase); + snprintf(buffer,80,"RPHASE_%1.1d", i); + status = StringDictGet(self->parameters,buffer,value,80); + sscanf(value, "%f", &rphase); + delta = ABS(aphase - rphase); + if(delta > PHASETOL) { + snprintf(pBuffer, iBuflen, "NOTREADY: Current phase %5.2f != requested phase %5.2f for chopper %d", aphase, rphase,i); + ready=0; + break; + } + } + } + if (ready) { + snprintf(pBuffer, iBuflen, "READY"); + return 1; + } else { + /* Get rest of state before returning */ + for (j=i+1; j<=4; j++) { + tcpDoChoCommand(self,"STATE ",j,NULL); + } + return 1; + } + } + + if(strcmp(parname,"frequency") == 0){ + status = StringDictGet(self->parameters,"ASPEED_1",value,80); + sscanf(value, "%f", &aspeed); + snprintf(pBuffer, iBuflen, "%5.2f", aspeed/60.0); + return 1; + } + + memset(par,0,80); + dissectName(parname,par,&choNum); + if(strcmp(par,"speed") == 0){ + snprintf(buffer,80,"ASPEED_%1.1d", choNum); + status = StringDictGet(self->parameters,buffer,pBuffer,iBuflen); + } else if(strcmp(par,"phase") == 0){ + snprintf(buffer,80,"APHASE_%1.1d", choNum); + status = StringDictGet(self->parameters,buffer,pBuffer,iBuflen); + } else { + status = StringDictGet(self->parameters,parname,pBuffer,iBuflen); + } + return status; +} +/*----------------------------------------------------------------------*/ +static int TcpDoChoCheckPar(pCodri pDriv, char *parname){ + pTcpDoCho self = NULL; + int status = 0, choNum; + float val, soll, delta; + char value[80], csoll[80], par[80], buffer[80], state[80]; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + /* + check for flags first + */ + if(self->busy){ + return HWBusy; + } + if(self->lastError != 0) { + return HWFault; + } + + /* + updateintervall is always Idle + */ + if(strcmp(parname,"updateintervall") == 0){ + return HWIdle; + } + + /* + check for emergency stop + */ + snprintf(buffer,79,"State_%1.1d",choNum); + memset(state,0,80*sizeof(char)); + StringDictGet(self->parameters,buffer,state,79); + if(strstr(state,"E-Stop") != NULL){ + self->lastError = HWFault; + return 0; + } + + memset(par,0,80); + dissectName(parname,par,&choNum); + if(strcmp(par,"speed") == 0){ + snprintf(buffer,79,"RSPEED_%1.1d", choNum); + StringDictGet(self->parameters,buffer,csoll,79); + sscanf(csoll,"%f",&soll); + snprintf(buffer,79,"ASPEED_%1.1d", choNum); + StringDictGet(self->parameters,buffer,value,79); + sscanf(value,"%f",&val); + delta = ABS(soll - val); + if(delta > SPEEDTOL){ + return HWBusy; + } else { + return HWIdle; + } + } else if(strcmp(par,"phase") == 0){ + snprintf(buffer,79,"RPHASE_%1.1d", choNum); + StringDictGet(self->parameters,buffer,csoll,79); + sscanf(value,"%f",&soll); + snprintf(buffer,79,"APHASE_%1.1d", choNum); + StringDictGet(self->parameters,buffer,value,79); + sscanf(value,"%f",&val); + delta = ABS(soll - val); + if(delta > PHASETOL){ + return HWBusy; + } else { + return HWIdle; + } + } + self->lastError = BADPAR; + return HWFault; +} +/*---------------------------------------------------------------------------*/ +static int TcpDoChoError(pCodri pDriv, int *iCode, char *pError, int iLen){ + pTcpDoCho self = NULL; + int status = 0; + float val, soll, delta; + char value[80]; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + *iCode = self->lastError; + switch(self->lastError){ + case WRONGMODE: + strncpy(pError,"Chopper in wrong mode",iLen); + break; + case BADCONVERSION: + strncpy(pError,"Bad ASCII to unicode conversion",iLen); + break; + case FAILEDCOMMAND: + strncpy(pError,"Command not accepted",iLen); + break; + case BADWRITE: + strncpy(pError,"Failed to write to chopper controller",iLen); + break; + case BADRESPONSE: + strncpy(pError,"Chopper controller send invalid command",iLen); + break; + case UNDRIVABLE: + strncpy(pError,"Parameter cannot be changed",iLen); + break; + case BADPAR: + strncpy(pError,"No such parameter",iLen); + break; + case BADVALUE: + strncpy(pError,"Invalid parameter value",iLen); + break; + case ESTOP: + strncpy(pError,"Emergency stop is engaged",iLen); + break; + default: + getRS232Error(self->lastError,pError,iLen); + break; + } + return 1; +} +/*---------------------------------------------------------------------*/ +static int TcpDoChoFix(pCodri pDriv, int iCode){ + pTcpDoCho self = NULL; + int status = 0; + float val, soll, delta; + char value[80]; + + assert(pDriv != NULL); + self = (pTcpDoCho)pDriv->pPrivate; + assert(self != NULL); + + self->lastError = 0; + switch(iCode){ + case BADCONVERSION: + case BADRESPONSE: + return CHREDO; + break; + case WRONGMODE: + case FAILEDCOMMAND: + case UNDRIVABLE: + case BADPAR: + case ESTOP: + return CHFAIL; + break; + default: + closeRS232(self->controller); + status = TcpDoChoConnect(self); + if(status == 1){ + return CHREDO; + } else { + return CHFAIL; + } + break; + } + return CHFAIL; +} +/*-------------------------------------------------------------------*/ +pCodri MakeTcpDoChoDriver(char *tclArray, SConnection *pCon){ + pCodri pNew = NULL; + pTcpDoCho self = NULL; + const char *pPtr = NULL; + char buffer[132]; + int port, i, count; + Tcl_DString pars; + char *parnames[] = {"State", + "ASPEED", + "RSPEED", + "APHASE", + "RPHASE", + "AVETO", + "DIR", + "MONIT", + "FLOWR", + "WTEMP", + "MTEMP", + "MVIBR", + "MVACU", + "speed", + "phase", + NULL, + }; + + /* + allocate memory + */ + pNew = (pCodri)malloc(sizeof(Codri)); + self = (pTcpDoCho)malloc(sizeof(TcpDoCho)); + if(!pNew || !self){ + return NULL; + } + memset(pNew,0,sizeof(Codri)); + memset(self,0,sizeof(TcpDoCho)); + + /* port and host name */ + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"port",TCL_GLOBAL_ONLY); + if(!pPtr){ + SCWrite(pCon,"ERROR: port not found in configuration array for TCP Dornier Chopper", + eError); + free(pNew); + free(self); + return NULL; + } + sscanf(pPtr,"%d",&port); + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"host",TCL_GLOBAL_ONLY); + if(!pPtr){ + SCWrite(pCon,"ERROR: host not found in configuration array for TCP Dornier Chopper", + eError); + free(pNew); + free(self); + return NULL; + } + memset(buffer,0,132); + strncpy(buffer,pPtr, 131); + self->controller = createRS232(buffer,port); + + /* number of choppers */ + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"nchopper",TCL_GLOBAL_ONLY); + if(!pPtr){ + SCWrite(pCon,"ERROR: nchopper not found in configuration array for TCP Dornier Chopper", + eError); + free(pNew); + free(self); + return NULL; + } + sscanf(pPtr,"%d",&port); + if(port < 0 || port > 8){ + SCWrite(pCon,"ERROR: number of choppers not in range 1 - 8",eError); + free(pNew); + free(self); + } + self->numChoppers = port; + + /* timeout */ + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"timeout",TCL_GLOBAL_ONLY); + if(!pPtr){ + SCWrite(pCon,"ERROR: timeout not found in configuration array for TCP Dornier Chopper", + eError); + free(pNew); + free(self); + return NULL; + } + sscanf(pPtr,"%d",&port); + self->timeout = port; + + /* username and password */ + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"user",TCL_GLOBAL_ONLY); + if(!pPtr){ + SCWrite(pCon,"ERROR: user not found in configuration array for TCP Dornier Chopper", + eError); + free(pNew); + free(self); + return NULL; + } + strncpy(self->user,pPtr, 131); + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"password",TCL_GLOBAL_ONLY); + if(!pPtr){ + SCWrite(pCon,"ERROR: password not found in configuration array for TCP Dornier Chopper", + eError); + free(pNew); + free(self); + return NULL; + } + strncpy(self->pword,pPtr, 131); + + /* + chopper configuration + */ + pPtr = Tcl_GetVar2(pServ->pSics->pTcl,tclArray,"config",TCL_GLOBAL_ONLY); + if(pPtr != NULL){ + self->config = strdup(pPtr); + } + + + /* initialize some more */ + self->parameters = CreateStringDict(); + if(self->parameters == NULL || self->controller == NULL){ + SCWrite(pCon,"ERROR: out of memory in MakeTcpDoCho",eError); + free(pNew); + free(self); + return NULL; + } + self->iRefreshIntervall = 60; + pNew->Init = TcpDoChoInit; + pNew->Close = TcpDoChoClose; + pNew->Delete = TcpDoChoKill; + pNew->SetPar = TcpDoChoSetPar; + pNew->SetPar2 = TcpDoChoSetPar2; + pNew->GetPar = TcpDoChoGetPar; + pNew->CheckPar = TcpDoChoCheckPar; + pNew->GetError = TcpDoChoError; + pNew->TryFixIt = TcpDoChoFix; + pNew->Halt = TcpDoChoHalt; + StringDictAddPair(self->parameters,"updateintervall","60"); + pNew->pPrivate = self; + + /* + create parameter list + */ + Tcl_DStringInit(&pars); + count = 0; + Tcl_DStringAppend(&pars,"updateintervall",15); + while(parnames[count] != NULL){ + for(i = 0; i < self->numChoppers; i++){ + snprintf(buffer,131,",%s_%1.1d", parnames[count], i + 1); + Tcl_DStringAppend(&pars,buffer,strlen(buffer)); + } + count++; + } + pNew->pParList = strdup(Tcl_DStringValue(&pars)); + Tcl_DStringFree(&pars); + return pNew; +} diff --git a/site_ansto/hardsup/makefile b/site_ansto/hardsup/makefile index ec7a0584..560eeaa7 100644 --- a/site_ansto/hardsup/makefile +++ b/site_ansto/hardsup/makefile @@ -10,7 +10,7 @@ SRC = . CC = gcc CFLAGS = -g -DLINUX $(DFORTIFY) -I$(SRC) -I../.. -Wall -HOBJ= serialsinq.o nhq200util.o itc4util.o lh45util.o lakeshore340util.o asynsrv_utility.o geterrno.o strjoin.o +HOBJ= serialsinq.o nhq200util.o itc4util.o lh45util.o lakeshore340util.o asynsrv_utility.o geterrno.o strjoin.o chopper.o libhlib.a: $(HOBJ) rm -f libhlib.a