Files
sicspsi/julcho.c
koennecke eb72d5c486 - Adapted indenation to new agreed upon system
- Fixed bad status in poldi zug driver
2009-02-13 09:01:03 +00:00

1386 lines
36 KiB
C

/**
* 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 <stdlib.h>
#include <assert.h>
#include <time.h>
#include <sics.h>
#include <unistd.h>
#define CHOCOINTERNAL
#include <choco.h>
#include <SCinter.h>
#include <rs232controller.h>
#include <sicshipadaba.h>
#include <stptok.h>
#include <dynstring.h>
/*----------------------------- 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;
}