972 lines
24 KiB
C
972 lines
24 KiB
C
/*--------------------------------------------------------------
|
|
This is a driver for the newer Astrium == Dornier chopper
|
|
systems which use a TCP/IP server for communication.
|
|
This driver has to take care of some ugliness:
|
|
- As of december 2005, the communication is in unicode!
|
|
To go from ASCII to unicode and back one has to
|
|
add a 0x00 before each character or to remove it.
|
|
- The controller is slow in responding and the controller
|
|
must be watched in the environment monitor. This is taken
|
|
care of by a special SICS task which updates the status
|
|
regularly and returning cached values anytime else.
|
|
|
|
|
|
Inititial Implementation: Mark Koennecke, December 2005
|
|
------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include <fortify.h>
|
|
#include <sics.h>
|
|
#include <stringdict.h>
|
|
#include <rs232controller.h>
|
|
#include <codri.h>
|
|
#include <stptok.h>
|
|
#include <commandlog.h>
|
|
/*========================================================================
|
|
Our private data structure
|
|
========================================================================*/
|
|
#define ASYNMODE 0
|
|
#define SYNCMODE 1
|
|
|
|
typedef struct {
|
|
prs232 controller;
|
|
int iRefreshIntervall;
|
|
time_t nextRefresh;
|
|
long lTask;
|
|
pStringDict parameters;
|
|
int lastError;
|
|
int numChoppers;
|
|
int mode;
|
|
int timeout;
|
|
char user[132];
|
|
char pword[132];
|
|
int stop;
|
|
int busy;
|
|
char *config;
|
|
} TcpDoCho, *pTcpDoCho;
|
|
/*-----------------------------------------------------------------------
|
|
Error codes:
|
|
-----------------------------------------------------------------------*/
|
|
#define WRONGMODE -8301
|
|
#define BADCONVERSION -8302
|
|
#define FAILEDCOMMAND -8303
|
|
#define BADWRITE -8304
|
|
#define BADRESPONSE -8306
|
|
#define UNDRIVABLE -8307
|
|
#define BADPAR -8308
|
|
#define ESTOP -8309
|
|
|
|
extern char *trim(char *str);
|
|
#define ABS(x) (x < 0 ? -(x) : (x))
|
|
|
|
#define SPEEDTOL 2
|
|
#define PHASETOL .5
|
|
/*=============== support functions ===================================*/
|
|
static int asciiToUnicode(char *input, char **output)
|
|
{
|
|
int len, i;
|
|
char *result = NULL;
|
|
|
|
len = strlen(input);
|
|
result = (char *) malloc(2 * len * sizeof(char));
|
|
if (result == NULL) {
|
|
return 0;
|
|
}
|
|
memset(result, 0, 2 * len * sizeof(char));
|
|
for (i = 0; i < len; i++) {
|
|
result[i * 2] = input[i];
|
|
}
|
|
*output = result;
|
|
return 2 * len;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
static int unicodeToAscii(char *input, int len, char **output)
|
|
{
|
|
int i, alen;
|
|
char *result = NULL;
|
|
|
|
alen = len / 2;
|
|
|
|
result = (char *) malloc((alen + 1) * sizeof(char));
|
|
if (result == NULL) {
|
|
return 0;
|
|
}
|
|
memset(result, 0, (alen + 1) * sizeof(char));
|
|
for (i = 0; i < alen; i++) {
|
|
result[i] = input[i * 2];
|
|
}
|
|
*output = result;
|
|
return alen;
|
|
}
|
|
|
|
/*----------------------------------------------------------------*/
|
|
static int tcpDoChoSend(pTcpDoCho self, char *command, int choNum,
|
|
char *value)
|
|
{
|
|
char buffer[1024];
|
|
int sendlen, status;
|
|
|
|
/*
|
|
format and send command
|
|
*/
|
|
self->lastError = 0;
|
|
if (choNum < 0) {
|
|
snprintf(buffer, 1023, "#SOS#%s \r\n", command);
|
|
} else if (value != NULL) {
|
|
snprintf(buffer, 1023, "#SOS#%s%1.1d: %s\r\n", command, choNum, value);
|
|
} else {
|
|
snprintf(buffer, 1023, "#SOS#%s%1.1d:\r\n", command, choNum);
|
|
}
|
|
sendlen = strlen(buffer);
|
|
if (sendlen == 0) {
|
|
self->lastError = BADCONVERSION;
|
|
return 0;
|
|
}
|
|
status = send(self->controller->pSock->sockid, buffer, sendlen, 0);
|
|
if (status < 0) {
|
|
self->lastError = BADWRITE;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------*/
|
|
static int statusComplete(char *statusMessage)
|
|
{
|
|
char *pPtr = NULL;
|
|
|
|
/*
|
|
currently the status message has no terminator. I try to find
|
|
the last component of the message which happens to be TIME and
|
|
the last # after that
|
|
*/
|
|
pPtr = strstr(statusMessage, "TIME");
|
|
if (pPtr != NULL) {
|
|
pPtr = strstr(pPtr + 6, "#");
|
|
if (pPtr != NULL) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------*/
|
|
static int readChopperNum(char *entry)
|
|
{
|
|
int num;
|
|
char *pPtr = NULL;
|
|
|
|
pPtr = strstr(entry, "CH");
|
|
if (pPtr == NULL) {
|
|
return -1;
|
|
}
|
|
sscanf(pPtr + 3, "%d", &num);
|
|
return num;
|
|
}
|
|
|
|
/*---------------------------------------------------------------*/
|
|
static void addEntry(pTcpDoCho self, int choNum, char *entry)
|
|
{
|
|
char name[80], value[80], *pPtr = NULL;
|
|
char num[5];
|
|
|
|
memset(name, 0, 80);
|
|
memset(value, 0, 80);
|
|
snprintf(num, 5, "_%1.1d", choNum);
|
|
pPtr = strstr(entry, "=");
|
|
if (pPtr != NULL) {
|
|
strncpy(name, entry, pPtr - entry);
|
|
strncat(trim(name), num, 80 - strlen(trim(name)));
|
|
strcpy(value, pPtr + 1);
|
|
if (StringDictExists(self->parameters, name)) {
|
|
StringDictUpdate(self->parameters, name, trim(value));
|
|
} else {
|
|
StringDictAddPair(self->parameters, name, trim(value));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------*/
|
|
static int parseStatus(pTcpDoCho self, char *statusMessage)
|
|
{
|
|
int choNum;
|
|
char entry[80], *pPtr;
|
|
|
|
pPtr = statusMessage;
|
|
|
|
/* skip over SOS */
|
|
pPtr = stptok(pPtr, entry, 79, "#");
|
|
pPtr = stptok(pPtr, entry, 79, "#");
|
|
pPtr = stptok(pPtr, entry, 79, "#");
|
|
|
|
choNum = readChopperNum(entry);
|
|
if (choNum < 0) {
|
|
self->lastError = BADRESPONSE;
|
|
return 0;
|
|
}
|
|
while ((pPtr = stptok(pPtr, entry, 79, "#")) != NULL) {
|
|
addEntry(self, choNum, entry);
|
|
memset(entry, 0, 80);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------*/
|
|
static int tcpDoChoReceive(pTcpDoCho self)
|
|
{
|
|
char buffer[1024];
|
|
int len, bytesRead, bufferStart, status;
|
|
time_t endTime;
|
|
|
|
endTime = time(NULL) + self->timeout;
|
|
bufferStart = 0;
|
|
bytesRead = 0;
|
|
memset(buffer, 0, 1024 * sizeof(char));
|
|
while (time(NULL) < endTime) {
|
|
if (availableRS232(self->controller)) {
|
|
bytesRead +=
|
|
recv(self->controller->pSock->sockid, buffer + bufferStart,
|
|
1024 - bytesRead, 0);
|
|
if (bytesRead < 0) {
|
|
self->lastError = BADREAD;
|
|
return 0;
|
|
}
|
|
if (strstr(buffer, "State") != NULL) {
|
|
if (statusComplete(buffer) == 0) {
|
|
continue;
|
|
} else {
|
|
status = parseStatus(self, buffer);
|
|
return status;
|
|
}
|
|
}
|
|
if (strstr(buffer, "ACCEPT") != NULL) {
|
|
return 1;
|
|
} else if (strstr(buffer, "NCCEPT") != NULL) {
|
|
self->lastError = FAILEDCOMMAND;
|
|
return 0;
|
|
} else {
|
|
self->lastError = BADRESPONSE;
|
|
return 0;
|
|
}
|
|
} else {
|
|
SicsWait(1);
|
|
}
|
|
}
|
|
self->lastError = TIMEOUT;
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------*/
|
|
static int tcpDoChoCommand(pTcpDoCho self, char *command, int choNum,
|
|
char *value)
|
|
{
|
|
int status;
|
|
|
|
status = tcpDoChoSend(self, command, choNum, value);
|
|
if (status == 0) {
|
|
return 0;
|
|
}
|
|
return tcpDoChoReceive(self);
|
|
}
|
|
|
|
/*---------------------------------------------------------------*/
|
|
static int TcpDoChoConnect(pTcpDoCho self)
|
|
{
|
|
int status, sendLen, readLen;
|
|
char buffer[256];
|
|
|
|
status = initRS232(self->controller);
|
|
if (status != 1) {
|
|
self->lastError = status;
|
|
return 0;
|
|
}
|
|
setRS232Timeout(self->controller, 5);
|
|
|
|
readLen = 255;
|
|
readRS232(self->controller, (void *) buffer, &readLen);
|
|
|
|
/*
|
|
user name
|
|
*/
|
|
snprintf(buffer, 255, "user:%s\r\n", self->user);
|
|
sendLen = strlen(buffer);
|
|
if (sendLen == 0) {
|
|
self->lastError = BADCONVERSION;
|
|
return 0;
|
|
}
|
|
status = send(self->controller->pSock->sockid, buffer, sendLen, 0);
|
|
if (status < 0) {
|
|
self->lastError = BADSEND;
|
|
return 0;
|
|
}
|
|
readLen = 255;
|
|
readRS232(self->controller, (void *) buffer, &readLen);
|
|
|
|
/*
|
|
password
|
|
*/
|
|
snprintf(buffer, 255, "password:%s\r\n", self->pword);
|
|
sendLen = strlen(buffer);
|
|
if (sendLen == 0) {
|
|
self->lastError = BADCONVERSION;
|
|
return 0;
|
|
}
|
|
status = send(self->controller->pSock->sockid, buffer, sendLen, 0);
|
|
if (status < 0) {
|
|
self->lastError = BADSEND;
|
|
return 0;
|
|
}
|
|
readLen = 255;
|
|
readRS232(self->controller, (void *) buffer, &readLen);
|
|
|
|
/*
|
|
TODO: responses should be checked to test for a valid login.
|
|
I do not know at this time how the controller reacts upon a
|
|
bad login.
|
|
*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*==================== actual driver implementation code ==================*/
|
|
static int TcpChopperTask(void *pData)
|
|
{
|
|
pCodri self = NULL;
|
|
pTcpDoCho pPriv = NULL;
|
|
int status, code, i;
|
|
char buffer[80];
|
|
char error[512];
|
|
|
|
self = (pCodri) pData;
|
|
assert(self);
|
|
pPriv = (pTcpDoCho) self->pPrivate;
|
|
assert(pPriv);
|
|
|
|
if (pPriv->stop == 1) {
|
|
return 0;
|
|
}
|
|
|
|
if (time(NULL) > pPriv->nextRefresh) {
|
|
if (pPriv->lastError != 0) {
|
|
self->GetError(self, &code, buffer, 79);
|
|
snprintf(error, 511, "WARNING: chopper tries to fix: %s", buffer);
|
|
WriteToCommandLog("Chopper-task:>>", error);
|
|
status = self->TryFixIt(self, code);
|
|
if (status == CHFAIL) {
|
|
pPriv->nextRefresh = time(NULL) + pPriv->iRefreshIntervall;
|
|
return 1;
|
|
}
|
|
} else {
|
|
pPriv->busy = 1;
|
|
for (i = 0; i < pPriv->numChoppers; i++) {
|
|
status = tcpDoChoCommand(pPriv, "STATE ", i + 1, NULL);
|
|
if (status != 1) {
|
|
/*
|
|
force error correction
|
|
*/
|
|
return 1;
|
|
}
|
|
}
|
|
pPriv->nextRefresh = time(NULL) + pPriv->iRefreshIntervall;
|
|
pPriv->busy = 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------*/
|
|
static int TcpDoChoKill(pCodri self)
|
|
{
|
|
pTcpDoCho pPriv = NULL;
|
|
|
|
pPriv = (pTcpDoCho) self->pPrivate;
|
|
if (!pPriv)
|
|
return 1;
|
|
|
|
if (pPriv->controller != NULL) {
|
|
KillRS232(pPriv->controller);
|
|
}
|
|
if (pPriv->parameters != NULL) {
|
|
DeleteStringDict(pPriv->parameters);
|
|
}
|
|
if (pPriv->config != NULL) {
|
|
free(pPriv->config);
|
|
}
|
|
free(pPriv);
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
static int TcpDoChoConfigure(pCodri pDriv)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status;
|
|
char *pPtr = NULL;
|
|
char command[80];
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
if (self->config != NULL) {
|
|
pPtr = self->config;
|
|
while ((pPtr = stptok(pPtr, command, 79, "\n")) != NULL) {
|
|
status = tcpDoChoCommand(self, command, -1, NULL);
|
|
if (status != 1) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int TcpDoChoInit(pCodri pDriv)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status;
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
self->lastError = 0;
|
|
self->stop = 0;
|
|
self->nextRefresh = 0;
|
|
|
|
status = TcpDoChoConnect(self);
|
|
if (status != 1) {
|
|
return 0;
|
|
}
|
|
|
|
status = TcpDoChoConfigure(pDriv);
|
|
if (status != 1) {
|
|
return 0;
|
|
}
|
|
|
|
/* start the update task */
|
|
if (self->lTask == 0) {
|
|
self->lTask = TaskRegister(pServ->pTasker,
|
|
TcpChopperTask, NULL, NULL, pDriv, 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
static void waitForBusy(pTcpDoCho self)
|
|
{
|
|
time_t endTime;
|
|
|
|
endTime = time(NULL) + 10 * 60; /* max 10 min */
|
|
while (time(NULL) < endTime) {
|
|
if (self->busy == 1) {
|
|
SicsWait(3);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
WriteToCommandLog("Chopper-task>> ",
|
|
"WARNING: timeout on busy flag, flag forced");
|
|
self->busy = 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
static int TcpDoChoClose(pCodri pDriv)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status;
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
self->stop = 1;
|
|
if (self->controller != NULL) {
|
|
KillRS232(self->controller);
|
|
self->controller = NULL;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
static int dissectName(char *name, char par[80], int *num)
|
|
{
|
|
char *pPtr = NULL;
|
|
|
|
pPtr = strrchr(name, (int) '_');
|
|
if (pPtr == NULL) {
|
|
return 0;
|
|
}
|
|
memset(par, 0, 80 * sizeof(char));
|
|
strncpy(par, name, pPtr - name);
|
|
if (sscanf(pPtr + 1, "%d", num) != 1) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
static int TcpDoChoSetPar2(pCodri pDriv, char *parname, char *value)
|
|
{
|
|
|
|
pTcpDoCho self = NULL;
|
|
int status, choNum;
|
|
char par[80], buffer[80], state[80];
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
|
|
/*
|
|
force status requests right after setting something in order
|
|
to make the stored status represent the new target values
|
|
*/
|
|
if (dissectName(parname, par, &choNum)) {
|
|
/*
|
|
check for emergency stop
|
|
*/
|
|
snprintf(buffer, 79, "State_%1.1d", choNum);
|
|
memset(state, 0, 80 * sizeof(char));
|
|
StringDictGet(self->parameters, buffer, state, 79);
|
|
if (strstr(state, "E-Stop") != NULL) {
|
|
self->lastError = ESTOP;
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(par, "speed") == 0) {
|
|
waitForBusy(self);
|
|
status = tcpDoChoCommand(self, "SPEED ", choNum, trim(value));
|
|
tcpDoChoCommand(self, "STATE ", choNum, NULL);
|
|
if (status != 1) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else if (strcmp(par, "phase") == 0) {
|
|
waitForBusy(self);
|
|
status = tcpDoChoCommand(self, "PHASE ", choNum, trim(value));
|
|
tcpDoChoCommand(self, "STATE ", choNum, NULL);
|
|
if (status != 1) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
self->lastError = UNDRIVABLE;
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int TcpDoChoHalt(pCodri pDriv)
|
|
{
|
|
|
|
pTcpDoCho self = NULL;
|
|
int status;
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
waitForBusy(self);
|
|
tcpDoChoCommand(self, "ESTOP :", -1, NULL);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int TcpDoChoSetPar(pCodri pDriv, char *parname, float fValue)
|
|
{
|
|
|
|
pTcpDoCho self = NULL;
|
|
int status, choNum;
|
|
char value[80];
|
|
char par[80];
|
|
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
if (dissectName(parname, par, &choNum)) {
|
|
if (strcmp(par, "speed") == 0) {
|
|
snprintf(value, 79, "%5.1f", fValue);
|
|
return TcpDoChoSetPar2(pDriv, parname, value);
|
|
} else if (strcmp(par, "phase") == 0) {
|
|
snprintf(value, 79, "%6.2f", fValue);
|
|
return TcpDoChoSetPar2(pDriv, parname, value);
|
|
}
|
|
}
|
|
if (strcmp(parname, "updateintervall") == 0) {
|
|
sprintf(value, "%d", (int) fValue);
|
|
StringDictUpdate(self->parameters, "updateintervall", value);
|
|
self->iRefreshIntervall = (int) fValue;
|
|
return 1;
|
|
} else {
|
|
snprintf(value, 79, "%f", fValue);
|
|
return TcpDoChoSetPar2(pDriv, parname, value);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int TcpDoChoGetPar(pCodri pDriv, char *parname,
|
|
char *pBuffer, int iBuflen)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status = 0, choNum;
|
|
char par[80], buffer[80];
|
|
float val;
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
memset(par, 0, 80);
|
|
dissectName(parname, par, &choNum);
|
|
if (strcmp(par, "speed") == 0) {
|
|
snprintf(buffer, 80, "ASPEED_%1.1d", choNum);
|
|
status = StringDictGet(self->parameters, buffer, pBuffer, iBuflen);
|
|
} else if (strcmp(par, "phase") == 0) {
|
|
snprintf(buffer, 80, "APHASE_%1.1d", choNum);
|
|
status = StringDictGet(self->parameters, buffer, pBuffer, iBuflen);
|
|
} else {
|
|
status = StringDictGet(self->parameters, parname, pBuffer, iBuflen);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
static int TcpDoChoCheckPar(pCodri pDriv, char *parname)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status = 0, choNum;
|
|
float val, soll, delta;
|
|
char value[80], csoll[80], par[80], buffer[80], state[80];
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
/*
|
|
check for flags first
|
|
*/
|
|
if (self->busy) {
|
|
return HWBusy;
|
|
}
|
|
if (self->lastError != 0) {
|
|
return HWFault;
|
|
}
|
|
|
|
/*
|
|
updateintervall is always Idle
|
|
*/
|
|
if (strcmp(parname, "updateintervall") == 0) {
|
|
return HWIdle;
|
|
}
|
|
|
|
/*
|
|
check for emergency stop
|
|
*/
|
|
snprintf(buffer, 79, "State_%1.1d", choNum);
|
|
memset(state, 0, 80 * sizeof(char));
|
|
StringDictGet(self->parameters, buffer, state, 79);
|
|
if (strstr(state, "E-Stop") != NULL) {
|
|
self->lastError = HWFault;
|
|
return 0;
|
|
}
|
|
|
|
memset(par, 0, 80);
|
|
dissectName(parname, par, &choNum);
|
|
if (strcmp(par, "speed") == 0) {
|
|
snprintf(buffer, 79, "RSPEED_%1.1d", choNum);
|
|
StringDictGet(self->parameters, buffer, csoll, 79);
|
|
sscanf(csoll, "%f", &soll);
|
|
snprintf(buffer, 79, "ASPEED_%1.1d", choNum);
|
|
StringDictGet(self->parameters, buffer, value, 79);
|
|
sscanf(value, "%f", &val);
|
|
delta = ABS(soll - val);
|
|
if (delta > SPEEDTOL) {
|
|
return HWBusy;
|
|
} else {
|
|
return HWIdle;
|
|
}
|
|
} else if (strcmp(par, "phase") == 0) {
|
|
snprintf(buffer, 79, "RPHASE_%1.1d", choNum);
|
|
StringDictGet(self->parameters, buffer, csoll, 79);
|
|
sscanf(value, "%f", &soll);
|
|
snprintf(buffer, 79, "APHASE_%1.1d", choNum);
|
|
StringDictGet(self->parameters, buffer, value, 79);
|
|
sscanf(value, "%f", &val);
|
|
delta = ABS(soll - val);
|
|
if (delta > PHASETOL) {
|
|
return HWBusy;
|
|
} else {
|
|
return HWIdle;
|
|
}
|
|
}
|
|
self->lastError = BADPAR;
|
|
return HWFault;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int TcpDoChoError(pCodri pDriv, int *iCode, char *pError, int iLen)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status = 0;
|
|
float val, soll, delta;
|
|
char value[80];
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
*iCode = self->lastError;
|
|
switch (self->lastError) {
|
|
case WRONGMODE:
|
|
strncpy(pError, "Chopper in wrong mode", iLen);
|
|
break;
|
|
case BADCONVERSION:
|
|
strncpy(pError, "Bad ASCII to unicode conversion", iLen);
|
|
break;
|
|
case FAILEDCOMMAND:
|
|
strncpy(pError, "Command not accepted", iLen);
|
|
break;
|
|
case BADWRITE:
|
|
strncpy(pError, "Failed to write to chopper controller", iLen);
|
|
break;
|
|
case BADRESPONSE:
|
|
strncpy(pError, "Chopper controller send invalid command", iLen);
|
|
break;
|
|
case UNDRIVABLE:
|
|
strncpy(pError, "Parameter cannot be changed", iLen);
|
|
break;
|
|
case BADPAR:
|
|
strncpy(pError, "No such parameter", iLen);
|
|
break;
|
|
case ESTOP:
|
|
strncpy(pError, "Emergency stop is engaged", iLen);
|
|
break;
|
|
default:
|
|
getRS232Error(self->lastError, pError, iLen);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int TcpDoChoFix(pCodri pDriv, int iCode)
|
|
{
|
|
pTcpDoCho self = NULL;
|
|
int status = 0;
|
|
float val, soll, delta;
|
|
char value[80];
|
|
|
|
assert(pDriv != NULL);
|
|
self = (pTcpDoCho) pDriv->pPrivate;
|
|
assert(self != NULL);
|
|
|
|
self->lastError = 0;
|
|
switch (iCode) {
|
|
case BADCONVERSION:
|
|
case BADRESPONSE:
|
|
return CHREDO;
|
|
break;
|
|
case WRONGMODE:
|
|
case FAILEDCOMMAND:
|
|
case UNDRIVABLE:
|
|
case BADPAR:
|
|
case ESTOP:
|
|
return CHFAIL;
|
|
break;
|
|
default:
|
|
closeRS232(self->controller);
|
|
status = TcpDoChoConnect(self);
|
|
if (status == 1) {
|
|
return CHREDO;
|
|
} else {
|
|
return CHFAIL;
|
|
}
|
|
break;
|
|
}
|
|
return CHFAIL;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
pCodri MakeTcpDoChoDriver(char *tclArray, SConnection * pCon)
|
|
{
|
|
pCodri pNew = NULL;
|
|
pTcpDoCho self = NULL;
|
|
const char *pPtr = NULL;
|
|
char buffer[132];
|
|
int port, i, count;
|
|
Tcl_DString pars;
|
|
char *parnames[] = { "State",
|
|
"ASPEED",
|
|
"RSPEED",
|
|
"APHASE",
|
|
"RPHASE",
|
|
"AVETO",
|
|
"DIR",
|
|
"MONIT",
|
|
"FLOWR",
|
|
"WTEMP",
|
|
"MTEMP",
|
|
"MVIBR",
|
|
"MVACU",
|
|
"speed",
|
|
"phase",
|
|
NULL,
|
|
};
|
|
|
|
/*
|
|
allocate memory
|
|
*/
|
|
pNew = (pCodri) malloc(sizeof(Codri));
|
|
self = (pTcpDoCho) malloc(sizeof(TcpDoCho));
|
|
if (!pNew || !self) {
|
|
return NULL;
|
|
}
|
|
memset(pNew, 0, sizeof(Codri));
|
|
memset(self, 0, sizeof(TcpDoCho));
|
|
|
|
/* port and host name */
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "port", TCL_GLOBAL_ONLY);
|
|
if (!pPtr) {
|
|
SCWrite(pCon,
|
|
"ERROR: port not found in configuration array for TCP Dornier Chopper",
|
|
eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
sscanf(pPtr, "%d", &port);
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "host", TCL_GLOBAL_ONLY);
|
|
if (!pPtr) {
|
|
SCWrite(pCon,
|
|
"ERROR: host not found in configuration array for TCP Dornier Chopper",
|
|
eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
memset(buffer, 0, 132);
|
|
strncpy(buffer, pPtr, 131);
|
|
self->controller = createRS232(buffer, port);
|
|
|
|
/* number of choppers */
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "nchopper",
|
|
TCL_GLOBAL_ONLY);
|
|
if (!pPtr) {
|
|
SCWrite(pCon,
|
|
"ERROR: nchopper not found in configuration array for TCP Dornier Chopper",
|
|
eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
sscanf(pPtr, "%d", &port);
|
|
if (port < 0 || port > 8) {
|
|
SCWrite(pCon, "ERROR: number of choppers not in range 1 - 8", eError);
|
|
free(pNew);
|
|
free(self);
|
|
}
|
|
self->numChoppers = port;
|
|
|
|
/* timeout */
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "timeout",
|
|
TCL_GLOBAL_ONLY);
|
|
if (!pPtr) {
|
|
SCWrite(pCon,
|
|
"ERROR: timeout not found in configuration array for TCP Dornier Chopper",
|
|
eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
sscanf(pPtr, "%d", &port);
|
|
self->timeout = port;
|
|
|
|
/* username and password */
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "user", TCL_GLOBAL_ONLY);
|
|
if (!pPtr) {
|
|
SCWrite(pCon,
|
|
"ERROR: user not found in configuration array for TCP Dornier Chopper",
|
|
eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
strncpy(self->user, pPtr, 131);
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "password",
|
|
TCL_GLOBAL_ONLY);
|
|
if (!pPtr) {
|
|
SCWrite(pCon,
|
|
"ERROR: password not found in configuration array for TCP Dornier Chopper",
|
|
eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
strncpy(self->pword, pPtr, 131);
|
|
|
|
/*
|
|
chopper configuration
|
|
*/
|
|
pPtr =
|
|
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "config", TCL_GLOBAL_ONLY);
|
|
if (pPtr != NULL) {
|
|
self->config = strdup(pPtr);
|
|
}
|
|
|
|
|
|
/* initialize some more */
|
|
self->parameters = CreateStringDict();
|
|
if (self->parameters == NULL || self->controller == NULL) {
|
|
SCWrite(pCon, "ERROR: out of memory in MakeTcpDoCho", eError);
|
|
free(pNew);
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
self->iRefreshIntervall = 60;
|
|
pNew->Init = TcpDoChoInit;
|
|
pNew->Close = TcpDoChoClose;
|
|
pNew->Delete = TcpDoChoKill;
|
|
pNew->SetPar = TcpDoChoSetPar;
|
|
pNew->SetPar2 = TcpDoChoSetPar2;
|
|
pNew->GetPar = TcpDoChoGetPar;
|
|
pNew->CheckPar = TcpDoChoCheckPar;
|
|
pNew->GetError = TcpDoChoError;
|
|
pNew->TryFixIt = TcpDoChoFix;
|
|
pNew->Halt = TcpDoChoHalt;
|
|
StringDictAddPair(self->parameters, "updateintervall", "60");
|
|
pNew->pPrivate = self;
|
|
|
|
/*
|
|
create parameter list
|
|
*/
|
|
Tcl_DStringInit(&pars);
|
|
count = 0;
|
|
Tcl_DStringAppend(&pars, "updateintervall", 15);
|
|
while (parnames[count] != NULL) {
|
|
for (i = 0; i < self->numChoppers; i++) {
|
|
snprintf(buffer, 131, ",%s_%1.1d", parnames[count], i + 1);
|
|
Tcl_DStringAppend(&pars, buffer, strlen(buffer));
|
|
}
|
|
count++;
|
|
}
|
|
pNew->pParList = strdup(Tcl_DStringValue(&pars));
|
|
Tcl_DStringFree(&pars);
|
|
return pNew;
|
|
}
|