1386 lines
36 KiB
C
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;
|
|
}
|