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