/** * This is the implementation of a chopper driver for the MARS Chopper cascade * as provided by the Forschungszentrum Juelich. The original host protocol * from Juelich has been changed on our request; Gerd Theidel did some of that * Turbo Pascal coding. * * copyright: see file COPYRIGHT * * Mark Koennecke, June-July 2006 * * Parameter updating is to slow, therefore it happens in two groups now: * actspeed and actphase are requested more frequently, so they go separate * * Mark Koennecke, October 2006 */ #include #include #include #include #include #define CHOCOINTERNAL #include #include #include #include #include #include /*----------------------------- error codes -----------------------------*/ #define FRAMEERROR -801 #define CKERROR -802 #define BADCOMMAND -803 #define WRONGNOPAR -804 #define ILLPAR -805 #define PARRANGE -806 #define BADERR -807 #define BADREPLY -808 #define NOTPAR -809 #define BADTEXT -810 #define ROPAR -811 #define NOMEM -812 #define HALT -813 /*--------------------- update flags -------------------------------------*/ #define ALL 1 #define SPEED 2 /*--------------------- wait after set -----------------------------------*/ #define STWAIT 5 /*------------------------- chopper internal names -----------------------*/ #define CH1N "snail" #define CH2N "master" #define CH3N "rabbit" #define CH4N "four" #define CH5N "five" /*=============== Juelich chopper private data structure ================== */ typedef struct { prs232 controller; pHdb parNode; int errorCode; time_t lastUpdate; int updateIntervall; int speedUpdate; int halt; }JulCho, *pJulCho; /*------------------------------------------------------------------------*/ typedef struct { char prefix[10]; char postfix[10]; char comCode[10]; pJulCho pDriv; } julCBData, *pJulCBData; /*================= internal support functions ============================*/ static int calculateJulCheckSum(char *realCommand){ int i, checkSum = 0; for(i = 1; i < strlen(realCommand); i++){ checkSum += (int)realCommand[i]; } return checkSum; } /*------------------------------------------------------------------------*/ static int testJulError(char *reply){ char *pPtr = NULL, *pEnd = NULL; int code, status; if(strstr(reply,"ERR") == NULL){ return 1; } pPtr = &reply[9]; /* #ERR:CCC: */ pEnd = strchr(pPtr,'{'); if(pEnd == NULL){ return BADERR; } *pEnd = '\0'; code = atoi(pPtr); switch(code){ case 1: status = FRAMEERROR; break; case 2: status = CKERROR; break; case 3: status = BADCOMMAND; break; case 4: status = WRONGNOPAR; break; case 5: status = ILLPAR; break; case 6: status = PARRANGE; break; default: status = BADERR; break; } return status; } /*------------------------------------------------------------------------*/ static void readClean(prs232 controller){ char buffer[1024]; int count = 0, bufSize; while(availableRS232(controller) == 1 && count < 20){ bufSize = 1024; readRS232(controller,buffer, &bufSize); } } /*-------------------------------------------------------------------------*/ static int JulChoTransact(pJulCho self, char *command, char *reply, int replyLen){ int status, length, checkSum; char realCommand[1024], checkString[30]; strcpy(realCommand,"#"); strcat(realCommand,command); checkSum = calculateJulCheckSum(realCommand); snprintf(checkString,30,"{%d}$", checkSum); strcat(realCommand,checkString); /* * clean the socket: If someone whacked the keyboard and the * controller did not repsond, the line might be full of shit */ readClean(self->controller); status = transactRS232(self->controller, realCommand,strlen(realCommand), (void *)reply, replyLen); if(status <= 0){ return status; } status = testJulError(reply); return status; } /*---------------------------------------------------------------------------*/ static hdbCallbackReturn JulChoSetCallback(pHdb node, void *userData, pHdbMessage message){ pJulCBData cbData = NULL; char command[256], reply[256]; pHdbDataMessage mm = NULL; int status; cbData = (pJulCBData)userData; if(cbData == NULL){ return hdbContinue; } /* * Is this for us? */ mm = GetHdbSetMessage(message); if(mm == NULL){ return hdbContinue; } if(mm->v->dataType == HIPINT){ snprintf(command,255,"%s %s%d%s",cbData->comCode, cbData->prefix, (int)mm->v->v.intValue,cbData->postfix); } else if(mm->v->dataType == HIPFLOAT){ snprintf(command,255,"%s %s%f%s",cbData->comCode, cbData->prefix, (float)mm->v->v.doubleValue,cbData->postfix); } else { assert(0); /* this is a programming error */ } cbData->pDriv->halt = 0; status = JulChoTransact(cbData->pDriv, command, reply, 255); if(status < 0) { cbData->pDriv->errorCode = status; return hdbAbort; } return hdbContinue; } /*------------------------------------------------------------------------------*/ static pHdbCallback MakeJulChoSetCallback(pJulCho driv, char *command, char *prefix, char *postfix){ pJulCBData cbData = NULL; pHdbCallback hdbCB = NULL; hdbCB = malloc(sizeof(hdbCallback)); cbData = malloc(sizeof(julCBData)); if(cbData == NULL || hdbCB == NULL){ return NULL; } cbData->pDriv = driv; strncpy(cbData->comCode,command,9); strncpy(cbData->prefix,prefix,9); strncpy(cbData->postfix,postfix,9); hdbCB->next = NULL; hdbCB->previous = NULL; hdbCB->killFunc = free; hdbCB->userCallback = JulChoSetCallback; hdbCB->userData = cbData; return hdbCB; } /*--------------------------------------------------------------------------*/ static int splitJulChoInt(char *reply, int data[5]){ char number[10]; char *pPtr = NULL; int count = 0; pPtr = stptok(reply,number,10,":"); pPtr = stptok(pPtr,number,10,":"); while(pPtr != NULL && count < 5){ data[count] = atoi(number); count++; pPtr = stptok(pPtr,number,10,":"); } if(count < 4){ return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int splitJulChoDouble(char *reply, double data[5]){ char number[10]; char *pPtr = NULL; int count = 0; pPtr = stptok(reply,number,10,":"); pPtr = stptok(pPtr,number,10,":"); while(pPtr != NULL && count < 5){ data[count] = (double)atof(number); count++; pPtr = stptok(pPtr,number,10,":"); } if(count < 4){ return 0; } return 1; } /*--------------------------------------------------------------------------*/ static int setJulChoIntPar(pHdb root, char *par, int data[5]){ char path[256]; hdbValue v; pHdb node = NULL; memset(&v,0,sizeof(hdbValue)); v.dataType = HIPINT; snprintf(path,255,"%s/%s",CH1N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.intValue = (long)data[0]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH2N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.intValue = (long)data[1]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH3N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.intValue = (long)data[2]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH4N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.intValue = (long)data[3]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH5N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.intValue = (long)data[4]; UpdateHipadabaPar(node,v,NULL); return 1; } /*--------------------------------------------------------------------------*/ static int setJulChoDoublePar(pHdb root, char *par, double data[5]){ char path[256]; hdbValue v; pHdb node = NULL; memset(&v,0,sizeof(hdbValue)); v.dataType = HIPFLOAT; snprintf(path,255,"%s/%s",CH1N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.doubleValue = data[0]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH2N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.doubleValue = data[1]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH3N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.doubleValue = data[2]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH4N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.doubleValue = data[3]; UpdateHipadabaPar(node,v,NULL); snprintf(path,255,"%s/%s",CH5N,par); node = GetHipadabaNode(root,path); assert(node != NULL); v.v.doubleValue = data[4]; UpdateHipadabaPar(node,v,NULL); return 1; } /*--------------------------------------------------------------------------*/ static void updateJulChoFlag(pHdb node, char *choppername, char *parname, int code, int mask){ char path[256]; hdbValue v; pHdb target = NULL; v.dataType = HIPINT; snprintf(path,255,"%s/%s",choppername,parname); if((mask & code) > 0) { v.v.intValue = 1; } else { v.v.intValue = 0; } target = GetHipadabaNode(node,path); assert(target != NULL); UpdateHipadabaPar(target,v,NULL); } /*---------------------------------------------------------------------------*/ static int setJulChoFlags(pHdb node, int intData[5]){ char *chNames[] = {CH1N, CH2N, CH3N, CH4N, CH5N, NULL}; char path[256]; int i, code; hdbValue v; memset(&v,0,sizeof(hdbValue)); v.dataType = HIPINT; for(i = 0; i < 5; i++){ code = intData[i]; updateJulChoFlag(node,chNames[i],"microok",code,1); updateJulChoFlag(node,chNames[i],"atspeed",code,2); updateJulChoFlag(node,chNames[i],"atphase",code,4); updateJulChoFlag(node,chNames[i],"magneton",code,8); updateJulChoFlag(node,chNames[i],"dcon",code,16); updateJulChoFlag(node,chNames[i],"driveon",code,32); updateJulChoFlag(node,chNames[i],"currentdc",code,64); updateJulChoFlag(node,chNames[i],"lockopen",code,128); updateJulChoFlag(node,chNames[i],"diskopen",code,256); updateJulChoFlag(node,chNames[i],"diskclosed",code,512); updateJulChoFlag(node,chNames[i],"speedoverflow",code,1024); updateJulChoFlag(node,chNames[i],"bearingfailed",code,2048); updateJulChoFlag(node,chNames[i],"voltagetohigh",code,4096); } return 1; } /*--------------------------------------------------------------------------*/ static int ReadJulChoFlags(pJulCho self){ int status, intData[5]; char reply[256]; status = JulChoTransact(self,"RSC",reply,255); /* fprintf(stdout,"Chopper flags = %s\n", reply);*/ if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoInt(reply,intData)){ self->errorCode = BADREPLY; } setJulChoFlags(self->parNode, intData); return 1; } /*---------------------------------------------------------------------------*/ static int UpdateJulChoParameters(pJulCho self, int what){ int status, intData[5]; double doubleData[5]; char reply[255]; assert(what == ALL || what == SPEED); if(what == SPEED){ if(time(NULL) < self->speedUpdate + self->updateIntervall){ return 1; } } else{ if(time(NULL) < self->lastUpdate + self->updateIntervall){ return 1; } } status = JulChoTransact(self,"RAS",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoInt(reply,intData)){ self->errorCode = BADREPLY; } setJulChoIntPar(self->parNode,"actspeed",intData); status = JulChoTransact(self,"RAP",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"actphase",doubleData); if(what != ALL){ self->speedUpdate = time(NULL); return 1; } status = JulChoTransact(self,"RNS",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoInt(reply,intData)){ self->errorCode = BADREPLY; } setJulChoIntPar(self->parNode,"nomspeed",intData); status = JulChoTransact(self,"RNP",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"nomphase",doubleData); status = JulChoTransact(self,"RGW",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"gatewidth",doubleData); status = JulChoTransact(self,"RNC",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"nomcurrent",doubleData); status = JulChoTransact(self,"RAC",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"actcurrent",doubleData); status = JulChoTransact(self,"RAV",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"voltage",doubleData); status = JulChoTransact(self,"RIT",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"inverter_temperature",doubleData); status = JulChoTransact(self,"RST",reply,255); if(status < 0){ self->errorCode = status; return 0; } if(!splitJulChoDouble(reply,doubleData)){ self->errorCode = BADREPLY; } setJulChoDoublePar(self->parNode,"stator_temperature",doubleData); status = ReadJulChoFlags(self); self->lastUpdate = time(NULL); self->speedUpdate = time(NULL); return status; } /*------------------------------------------------------------------------*/ static void JulChoErrorcodeToString(int code, char *pError, int iLen){ switch(code){ case FRAMEERROR: strncpy(pError,"Frame error",iLen); break; case CKERROR: strncpy(pError,"Checksum error",iLen); break; case BADCOMMAND: strncpy(pError,"Bad Command",iLen); break; case WRONGNOPAR: strncpy(pError,"Wrong number of parameters",iLen); break; case ILLPAR: strncpy(pError,"Illegal parameter",iLen); break; case PARRANGE: strncpy(pError,"Parameter out of range",iLen); break; case BADERR: strncpy(pError,"Controller error not recognised",iLen); break; case BADREPLY: strncpy(pError,"Unexpected reply",iLen); break; case NOTPAR: strncpy(pError,"Unsupported parameter",iLen); break; case BADTEXT: strncpy(pError,"Failed to convert text to number",iLen); break; case ROPAR: strncpy(pError,"Read only Parameter",iLen); break; case NOMEM: strncpy(pError,"Out of memory formatting parameter",iLen); break; case HALT: strncpy(pError,"User requested HALT; choppers status undefined ",iLen); break; case SICSCBRANGE: strncpy(pError,"Parameter value out of range",iLen); break; case SICSCBRO: strncpy(pError,"Parameter is READ-ONLY",iLen); break; default: getRS232Error(code, pError, iLen); break; } } /*------------------------------------------------------------------------*/ static int testParGroup(char *name){ if(strstr(name,"actspeed") != NULL || strstr(name,"actphase") != NULL){ return SPEED; } else { return ALL; } } /*-------------------------------------------------------------------------*/ static hdbCallbackReturn JulChoGetCallback(pHdb currentNode, void *userData, pHdbMessage message){ pJulCho self = NULL; SConnection *pCon = NULL; int status; char error[128], buffer[256]; pHdbDataMessage mm = NULL; self = (pJulCho)userData; assert(self != NULL); mm = GetHdbGetMessage(message); if(mm == NULL){ return hdbContinue; } pCon = (SConnection *)mm->callData; status = UpdateJulChoParameters(self,testParGroup(currentNode->name)); if(status != 1 && pCon != NULL){ JulChoErrorcodeToString(self->errorCode, error,127); snprintf(buffer,255,"ERROR: %s occurred reading par",error); SCWrite(pCon,buffer,eError); } return hdbContinue; } /*--------------------------------------------------------------------------*/ static int AppendJulChoROPar(pHdb parent, char *name, int type){ pHdb child = NULL; child = AddSICSHdbROPar(parent,name,makeHdbValue(type,1)); if(child != NULL){ return 1; } else { return 0; } } /*---------------------------------------------------------------------------*/ static int ConfigureSingleJulCho(pHdb parent, pJulCho driv, char *prefix, char *postfix){ pHdb child = NULL; pHdbCallback pCb = NULL; /* * write parameters */ child = MakeHipadabaNode("nomphase",HIPFLOAT,0); if(child == NULL){ return 0; } pCb = MakeCheckPermissionCallback(usUser); if(pCb == NULL){ return 0; } AppendHipadabaCallback(child,pCb); pCb = MakeFloatRangeCallback(5.0, 355.); if(pCb == NULL){ return 0; } AppendHipadabaCallback(child,pCb); pCb = MakeJulChoSetCallback(driv,"SPH", prefix,postfix); if(pCb == NULL){ return 0; } AppendHipadabaCallback(child,pCb); AddHipadabaChild(parent,child,NULL); child = MakeHipadabaNode("gatewidth",HIPFLOAT,0); if(child == NULL){ return 0; } pCb = MakeCheckPermissionCallback(usUser); if(pCb == NULL){ return 0; } AppendHipadabaCallback(child,pCb); pCb = MakeJulChoSetCallback(driv,"SGW", prefix,postfix); if(pCb == NULL){ return 0; } AppendHipadabaCallback(child,pCb); AddHipadabaChild(parent,child,NULL); if(!AppendJulChoROPar(parent,"nomspeed",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"actspeed",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"actphase",HIPFLOAT)){ return 0; } if(!AppendJulChoROPar(parent,"nomcurrent",HIPFLOAT)){ return 0; } if(!AppendJulChoROPar(parent,"actcurrent",HIPFLOAT)){ return 0; } if(!AppendJulChoROPar(parent,"voltage",HIPFLOAT)){ return 0; } if(!AppendJulChoROPar(parent,"inverter_temperature",HIPFLOAT)){ return 0; } if(!AppendJulChoROPar(parent,"stator_temperature",HIPFLOAT)){ return 0; } if(!AppendJulChoROPar(parent,"microok",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"atspeed",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"atphase",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"magneton",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"dcon",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"driveon",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"currentdc",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"lockopen",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"diskopen",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"diskclosed",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"speedoverflow",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"bearingfailed",HIPINT)){ return 0; } if(!AppendJulChoROPar(parent,"voltagetohigh",HIPINT)){ return 0; } /* * append get callbacks */ child = parent->child; while(child != NULL){ AppendHipadabaCallback(child, MakeHipadabaCallback(JulChoGetCallback,driv,NULL)); child = child->next; } return 1; } /*--------------------------------------------------------------------------*/ static int InitJulChoPar(pJulCho driv){ pHdb child = NULL, parChild = NULL; pHdbCallback pCb = NULL; child = MakeHipadabaNode(CH1N,HIPNONE,0); if(child == NULL){ return 0; } if(!ConfigureSingleJulCho(child,driv,"","::::")){ return 0; } AddHipadabaChild(driv->parNode,child,NULL); child = MakeHipadabaNode(CH2N,HIPNONE,0); if(child == NULL){ return 0; } if(!ConfigureSingleJulCho(child,driv,":",":::")){ return 0; } /** * the master speed can be set, the slaves not, thus remove the read only * set callback and replace by a speed setting callback */ parChild = GetHipadabaNode(child,"nomspeed"); assert(parChild != NULL); /* * delete the callback cahin in order to remove the * read only callback */ DeleteCallbackChain(parChild); parChild->callBackChain = NULL; pCb = MakeCheckPermissionCallback(usUser); if(pCb == NULL){ return 0; } AppendHipadabaCallback(parChild,pCb); pCb = MakeJulChoSetCallback(driv,"SMS","",""); if(pCb == NULL){ return 0; } AppendHipadabaCallback(parChild,pCb); AppendHipadabaCallback(parChild, MakeHipadabaCallback(JulChoGetCallback,driv,NULL)); AddHipadabaChild(driv->parNode,child,NULL); child = MakeHipadabaNode(CH3N,HIPNONE,0); if(child == NULL){ return 0; } if(!ConfigureSingleJulCho(child,driv,"::","::")){ return 0; } AddHipadabaChild(driv->parNode,child,NULL); child = MakeHipadabaNode(CH4N,HIPNONE,0); if(child == NULL){ return 0; } if(!ConfigureSingleJulCho(child,driv,":::",":")){ return 0; } AddHipadabaChild(driv->parNode,child,NULL); child = MakeHipadabaNode(CH5N,HIPNONE,0); if(child == NULL){ return 0; } if(!ConfigureSingleJulCho(child,driv,"::::","")){ return 0; } AddHipadabaChild(driv->parNode,child,NULL); return 1; } /*================= actual interface functions ==============================*/ static int JulChoInit(pCodri pDriv){ pJulCho self = NULL; int status; self = (pJulCho)pDriv->pPrivate; status = initRS232(self->controller); if(status < 1){ self->errorCode = status; } setRS232SendTerminator(self->controller,"$"); setRS232ReplyTerminator(self->controller,"$"); setRS232Timeout(self->controller,2000); return 1; } /*---------------------------------------------------------------------------*/ static int JulChoClose(pCodri pDriv){ pJulCho self = NULL; self = (pJulCho)pDriv->pPrivate; closeRS232(self->controller); return 1; } /*---------------------------------------------------------------------------*/ static int JulChoKill(pCodri pDriv){ pJulCho self = NULL; if(pDriv == NULL){ return 1; } self = (pJulCho)pDriv->pPrivate; JulChoClose(pDriv); if(self->controller != NULL){ KillRS232(self->controller); self->controller = NULL; } free(self); return 1; } /*--------------------------------------------------------------------------- * The set and get routines introduce phase and speed values which map to * nomspeed when setting and actspeed when reading. This ugly hack saves me * to introduce another drive adapter which set one parameter and reads * another *---------------------------------------------------------------------------*/ static int JulChoSetPar2(pCodri pDriv, char *parname, char *pValue){ pJulCho self = NULL; pHdb target = NULL; hdbValue v; char error[64], *pPtr = NULL; int status; if(strcmp(parname,"master/speed") == 0){ status = JulChoSetPar2(pDriv,"master/nomspeed", pValue); if(status == 1) { SicsWait(10); } return status; } else if(strcmp(parname,"master/phase") == 0){ return JulChoSetPar2(pDriv,"master/nomphase", pValue); } else if(strcmp(parname,"snail/phase") == 0){ return JulChoSetPar2(pDriv,"snail/nomphase", pValue); } else if(strcmp(parname,"rabbit/phase") == 0){ return JulChoSetPar2(pDriv,"rabbit/nomphase", pValue); } else if(strcmp(parname, "four/phase") == 0){ return JulChoSetPar2(pDriv,"four/nomphase", pValue); } else if(strcmp(parname,"five/phase") == 0){ return JulChoSetPar2(pDriv,"five/nomphase", pValue); } self = (pJulCho)pDriv->pPrivate; target = GetHipadabaNode(self->parNode,parname); if(target == NULL){ self->errorCode = NOTPAR; return 0; } v.dataType = target->value.dataType; if(!readHdbValue(&v,pValue,error,63)){ self->errorCode = BADTEXT; return 0; } self->errorCode = 0; status = SetHipadabaPar(target,v,NULL); if(status == 0 && self->errorCode == 0){ self->errorCode = status; return 0; } /* * The SicsWait is here to allow the chopper to update his status flags. * There were occurrences where the chopper was still driving but the * status flag did not reflect this. */ SicsWait(STWAIT); self->lastUpdate = 0; return status; } /*-------------------------------------------------------------------------------*/ static int JulChoSetPar(pCodri pDriv, char *parname, float fValue){ pJulCho self = NULL; pHdb target = NULL; hdbValue v; char error[64]; int status; if(strcmp(parname,"master/speed") == 0){ status = JulChoSetPar(pDriv,"master/nomspeed", fValue); if(status == 1) { SicsWait(10); } return status; } else if(strcmp(parname,"master/phase") == 0){ return JulChoSetPar(pDriv,"master/nomphase", fValue); } else if(strcmp(parname,"snail/phase") == 0){ return JulChoSetPar(pDriv,"snail/nomphase", fValue); } else if(strcmp(parname,"rabbit/phase") == 0){ return JulChoSetPar(pDriv,"rabbit/nomphase", fValue); } else if(strcmp(parname, "four/phase") == 0){ return JulChoSetPar(pDriv,"four/nomphase", fValue); } else if(strcmp(parname,"five/phase") == 0){ return JulChoSetPar(pDriv,"five/nomphase", fValue); } self = (pJulCho)pDriv->pPrivate; target = GetHipadabaNode(self->parNode,parname); if(target == NULL){ self->errorCode = NOTPAR; return 0; } v.dataType = target->value.dataType; if(v.dataType == HIPINT){ v.v.intValue = (int)fValue; } else { v.v.doubleValue = (double)fValue; } self->errorCode = 0; status = SetHipadabaPar(target,v,NULL); if(status == 0 && self->errorCode == 0){ self->errorCode = status; return 0; } /* * The SicsWait is here to allow the chopper to update his status flags. * There were occurrences where the chopper was still driving but the * status flag did not reflect this. */ SicsWait(STWAIT); self->lastUpdate = 0; return status; } /*---------------------------------------------------------------------------*/ static int JulChoHalt(pCodri pDriv){ pJulCho self = NULL; self = (pJulCho)pDriv->pPrivate; self->halt = 1; /* * empty function on Philips request */ return 1; } /*--------------------------------------------------------------------------*/ static int JulChoGetPar(pCodri pDriv, char *parname, char *pBuffer, int iBufLen){ pJulCho self = NULL; pHdb target = NULL; pDynString val = NULL; if(strcmp(parname,"master/speed") == 0){ return JulChoGetPar(pDriv,"master/actspeed", pBuffer,iBufLen); } else if(strcmp(parname,"master/phase") == 0){ return JulChoGetPar(pDriv,"master/actphase", pBuffer,iBufLen); } else if(strcmp(parname,"snail/phase") == 0){ return JulChoGetPar(pDriv,"snail/actphase", pBuffer,iBufLen); } else if(strcmp(parname,"rabbit/phase") == 0){ return JulChoGetPar(pDriv,"rabbit/actphase", pBuffer,iBufLen); } else if(strcmp(parname, "four/phase") == 0){ return JulChoGetPar(pDriv,"four/actphase", pBuffer,iBufLen); } else if(strcmp(parname,"five/phase") == 0){ return JulChoGetPar(pDriv,"five/actphase", pBuffer,iBufLen); } self = (pJulCho)pDriv->pPrivate; target = GetHipadabaNode(self->parNode,parname); if(target == NULL){ self->errorCode = NOTPAR; return 0; } if(!UpdateJulChoParameters(self,testParGroup(parname))){ return 0; } val = formatValue(target->value, target); if(val == NULL){ self->errorCode = NOMEM; return 0; } strncpy(pBuffer,GetCharArray(val), iBufLen); DeleteDynString(val); return 1; } /*---------------------------------------------------------------------------*/ static int JulChoCheckPar(pCodri pDriv, char *parname){ pJulCho self = NULL; int i, status; char path[256], reply[256]; pHdb target = NULL; char *chNames[] = {CH1N, CH2N, CH3N, CH4N, CH5N, NULL}; self = (pJulCho)pDriv->pPrivate; if(self->halt == 1){ self->errorCode = HALT; return HWFault; } /* * For the Juelich chopper this means checking the atspeed, atphase * flags */ if(!ReadJulChoFlags(self)){ return HWFault; } for(i = 0; i < 5; i++){ snprintf(path,255,"%s/atspeed", chNames[i]); target = GetHipadabaNode(self->parNode,path); assert(target != NULL); if(target->value.v.intValue == 0){ return HWBusy; } snprintf(path,255,"%s/atphase",chNames[i]); target = GetHipadabaNode(self->parNode,path); assert(target != NULL); if(target->value.v.intValue == 0){ return HWBusy; } } status = JulChoTransact(self,"RSC",reply,255); if(status < 0){ self->errorCode = status; return HWFault; } /* fprintf(stdout,"Chopper Flags at finish: %s\n", reply);*/ return HWIdle; } /*---------------------------------------------------------------------------*/ static int JulChoError(pCodri pDriv, int *iCode, char *pError, int iLen){ pJulCho self = NULL; self = (pJulCho)pDriv->pPrivate; *iCode = self->errorCode; JulChoErrorcodeToString(self->errorCode, pError, iLen); return 1; } /*---------------------------------------------------------------------------*/ static int JulChoFix(pCodri pDriv, int code){ pJulCho self = NULL; self = (pJulCho)pDriv->pPrivate; switch(code){ case TIMEOUT: case CKERROR: case BADERR: case BADREPLY: return CHREDO; break; case NOTCONNECTED: if(initRS232(self->controller) == 1){ return CHREDO; } else { return CHFAIL; } break; case INCOMPLETE: case BADSEND: case BADREAD: closeRS232(self->controller); if(initRS232(self->controller) == 1){ return CHREDO; } else { return CHFAIL; } break; default: return CHFAIL; break; } } /*---------------------------------------------------------------------------*/ static pCodri MakeJulChoDriver(char *pHost, int port, pHdb parNode){ pCodri pDriv = NULL; pJulCho self = NULL; int i; pDynString names = NULL; char *chNames[] = {CH1N, CH2N, CH3N, CH4N, CH5N, NULL}; char path[256], *par = NULL; pDriv = malloc(sizeof(Codri)); self = malloc(sizeof(JulCho)); names = CreateDynString(256,256); if(pDriv == NULL && self == NULL && names == NULL){ return NULL; } memset(pDriv,0,sizeof(Codri)); memset(self,0,sizeof(JulCho)); self->parNode = parNode; self->controller = createRS232(pHost,port); if(self->controller == NULL){ free(self); free(pDriv); return NULL; } self->updateIntervall = 10; if(!InitJulChoPar(self)){ free(self); free(pDriv); return NULL; } pDriv->pPrivate = self; pDriv->Init = JulChoInit; pDriv->Close = JulChoClose; pDriv->Delete = JulChoKill; pDriv->SetPar = JulChoSetPar; pDriv->SetPar2 = JulChoSetPar2; pDriv->GetPar = JulChoGetPar; pDriv->CheckPar = JulChoCheckPar; pDriv->GetError = JulChoError; pDriv->TryFixIt = JulChoFix; pDriv->Halt = JulChoHalt; for(i = 0; i < 5; i++){ snprintf(path,255,"%s/nomspeed,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/actspeed,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/nomphase,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/actphase,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/gatewidth,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/nomcurrent,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/actcurrent,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/voltage,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/inverter_temperature,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/stator_temperature,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/microok,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/atspeed,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/atphase,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/magneton,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/dcon,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/driveon,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/currentdc,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/lockopen,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/diskopen,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/diskclosed,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/speedoverflow,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/bearingfailed,",chNames[i]); DynStringConcat(names,path); snprintf(path,255,"%s/voltagetohigh,",chNames[i]); DynStringConcat(names,path); } par = GetCharArray(names); par[strlen(par) -1] = '\0'; pDriv->pParList = strdup(par); DeleteDynString(names); if(pDriv->pParList == NULL){ JulChoKill(pDriv); free(pDriv); return NULL; } return pDriv; } /*--------------------------------------------------------------------------*/ int JulChoFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pChoco pNew = NULL; pCodri pDriv = NULL; pObjectDescriptor pDes = NULL; char pBueffel[132]; int iRet, iPort, iChannel; int iSingle = 0; if(argc < 4) { SCWrite(pCon, "ERROR: Insufficient number of arguments to MakeJulCho", eError); return 0; } /* first try to get everything done */ pNew = (pChoco)malloc(sizeof(Choco)); pDes = CreateDescriptor("Chopper"); pDes->parNode = MakeHipadabaNode(argv[1], HIPNONE,0); /* do driver */ pDriv = MakeJulChoDriver(argv[2],atoi(argv[3]),pDes->parNode); if(pDriv == NULL){ sprintf(pBueffel,"ERROR: Failed to initialize JulCho Driver"); SCWrite(pCon,pBueffel,eError); return 0; } if( (pNew == NULL) || (pDes == NULL) || (pDriv == NULL) ) { SCWrite(pCon,"ERROR: No memory left to create controller",eError); return 0; } pNew->pDes = pDes; pNew->pDriv = pDriv; /* initialize driver */ iRet = pDriv->Init(pDriv); if(!iRet){ SCWrite(pCon,"ERROR: Failed to initialize driver",eError); KillChoco(pNew); return 0; } /* install as command */ iRet = AddCommand(pSics, argv[1],ChocoAction,KillChoco,pNew); if(!iRet){ sprintf(pBueffel,"ERROR: duplicate command %s NOT created", argv[1]); SCWrite(pCon,pBueffel,eError); return 0; } return 1; }