/*-------------------------------------------------------------- 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 ===================================*/ #if 0 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; } #endif /*-------------------------------------------------------------------*/ #if 0 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; } #endif /*----------------------------------------------------------------*/ 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 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 ==================*/ #if 0 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; } #endif /*------------------------------------------------------------------------------*/ 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; 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 */ #if 0 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); } return 0; } #endif /*----------------------------------------------------------------------*/ 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; 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 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 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 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; 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; 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)); if(!pNew){ return NULL; } self = (pTcpDoCho)malloc(sizeof(TcpDoCho)); if(!self){ free(pNew); 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); return NULL; } 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; }