Files
sicspsi/el737hpdrivsps.c
koennecke dec6b04fa6 - Changed strncpy to strlcpy, strncat to strlcat
- Added strlcpy and strlcat to SICS
- Added a driver for the POLDI power supplies
2010-04-13 15:08:40 +00:00

744 lines
19 KiB
C

/*-----------------------------------------------------------------------
This is another driver for the EL737 counter box used at SINQ. The hp in
the name is for high performance, though this only a promise and not yet
proven. This version connects directly to the RS232 port of the counter
box on the terminal server rather then working with David Maden's
SerPortServer program. Other tweaks will be implemented as well, such as
reading the monitors only now and then and not on all calls.
Mark Koennecke, July 2003
This is a special version for MORPHEUS which checks the SPS when in
No Beam state. Because NoBeam can be caused by the shutter being closed
in order to prevent overloading the 2D detector.
Mark Koennecke, March 2007
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <fortify.h>
#include <string.h>
#include <sics.h>
#include <rs232controller.h>
#include <countdriv.h>
#include <splitter.h>
#include "sps.h"
#define MONTHRESH 20
#define STATSEND 0
#define STATRECEIVE 2
#define BADTRANGE -117766
/*-----------------------------------------------------------------------
our own data struture
------------------------------------------------------------------------*/
typedef struct {
prs232 controller;
int monitorCount; /* read monitors if this is above MONTHRESH */
float cachedControl;
int errorCode;
int finishCount; /* need RS = 0 2 times before really sure finished */
int statusMode;
time_t startRequest;
int lastStatus; /* need to remember last status, otherwise I get oscillating
NoBeam and Counting status if the beam goes off
*/
char *badReply;
int readErrorCount; /* need to remember failed reads: on RDOE, upper level
code will see busy's and thus not catch the case of
multiple failures
*/
pSPS sps;
} EL737hpsps, *pEL737hpsps;
/*--------------------- ERROR CODES -------------------------------------*/
#define OFFLINE -1
#define BADRANGE -3
#define BADCOMMAND -4
#define BADPARAM -5
#define NOPARAM -7
#define TOMANYCOUNTS -8
#define SYSERROR -9
#define BADREPLY -10
#define SELECTFAIL -11
#define TIMEOUT737 -12
#define TOMANYREADERRORS -23
#define DETOVERLOAD -24
/*---------------------------------------------------------------------*/
static void setBadReply(pEL737hpsps self, char *reply)
{
if (self->badReply != NULL) {
free(self->badReply);
}
self->badReply = strdup(reply);
}
/*-----------------------------------------------------------------------
search errors in a reply from the EL737. Returns 1 on success or a
negative error code in case of trouble.
------------------------------------------------------------------------*/
static int checkEL737Error(char *pReply)
{
/*
all error start with a ?, if no ? in reply, answer is OK!
*/
if (strstr(pReply, "?") == NULL) {
return 1;
}
/*
Now there is an error and we have to identify it
*/
if (strstr(pReply, "?OF") != NULL) {
return OFFLINE;
} else if (strstr(pReply, "?OV") != NULL) {
return OVERFLOW;
} else if (strstr(pReply, "?1") != NULL) {
return BADRANGE;
} else if (strstr(pReply, "?2") != NULL) {
return BADCOMMAND;
} else if (strstr(pReply, "?3") != NULL) {
return BADPARAM;
} else if (strstr(pReply, "?4") != NULL) {
return BADCOUNTER;
} else if (strstr(pReply, "?5") != NULL) {
return NOPARAM;
} else if (strstr(pReply, "?6") != NULL) {
return TOMANYCOUNTS;
} else {
return SYSERROR;
}
}
/*---------------------------------------------------------------
fixMode checks if we are in STATRECEIVE mode, reads any pending
data and sets the mode to STATSEND. This would fix the problem
if another client wishes to give a command while we are expecting
a status response
---------------------------------------------------------------*/
static void fixMode(pEL737hpsps pPriv)
{
char pBuffer[256];
int len = 255;
if (pPriv->statusMode == STATRECEIVE) {
readRS232TillTerm(pPriv->controller, pBuffer, &len);
pPriv->statusMode = STATSEND;
}
}
/*---------------------------------------------------------------*/
static int EL737SCommand(pEL737hpsps pPriv, char *pCommand,
char *pReply, int replylen)
{
int status;
status = transactRS232(pPriv->controller, pCommand, strlen(pCommand),
pReply, replylen);
if (status < 0) {
pPriv->errorCode = status;
return 0;
}
status = checkEL737Error(pReply);
if (status < 0) {
pPriv->errorCode = status;
return 0;
}
return 1;
}
/*----------------------------------------------------------------*/
static int readRS(pEL737hpsps pPriv, int *RS)
{
int status, len = 131;
char reply[132];
status = readRS232TillTerm(pPriv->controller, reply, &len);
if (status < 0) {
pPriv->readErrorCount++;
pPriv->errorCode = status;
return 0;
}
status = checkEL737Error(reply);
if (status < 0) {
pPriv->readErrorCount++;
pPriv->errorCode = status;
return 0;
}
status = sscanf(reply, "%d", RS);
if (status < 1) {
pPriv->readErrorCount++;
pPriv->errorCode = BADREPLY;
setBadReply(pPriv, reply);
return 0;
}
pPriv->readErrorCount = 0;
return 1;
}
/*-----------------------------------------------------------------*/
static int decodeRS(pEL737hpsps pPriv, int RS)
{
int returnValue;
switch (RS) {
case 0:
pPriv->finishCount++;
if (pPriv->finishCount > 2) {
returnValue = HWIdle;
} else {
returnValue = HWBusy;
}
break;
case 1:
case 2:
pPriv->finishCount = 0;
returnValue = HWBusy;
break;
case 5:
case 6:
pPriv->finishCount = 0;
returnValue = HWNoBeam;
break;
default:
pPriv->finishCount = 0;
returnValue = HWPause;
break;
}
return returnValue;
}
/*-----------------------------------------------------------------*/
static int updateMonitors(struct __COUNTER *self)
{
int status;
int m1, m2, m3, m4, m5, m6, m7, m8;
float fTime;
pEL737hpsps pPriv = NULL;
char reply[132];
pPriv = (pEL737hpsps) self->pData;
if (!EL737SCommand(pPriv, "RA\r", reply, 131)) {
return 0;
}
/*
There are two forms of RA replys: new form with 8 monitors
*/
status = sscanf(reply, "%f %d %d %d %d %d %d %d %d",
&fTime, &m1, &m2, &m3, &m4, &m5, &m6, &m7, &m8);
if (status != 9) {
/*
old form with 4 monitors
*/
status = sscanf(reply, "%d %d %d %d %f", &m1, &m2, &m3, &m4, &fTime);
if (status != 5) {
pPriv->errorCode = BADREPLY;
setBadReply(pPriv, reply);
printf("Bad reply to EL737 RA command: %s\n", reply);
return 0;
}
}
self->lCounts[0] = m2;
self->lCounts[1] = m1;
self->lCounts[2] = m3;
self->lCounts[3] = m4;
self->lCounts[4] = m5;
self->lCounts[5] = m6;
self->lCounts[6] = m7;
self->lCounts[7] = m8;
self->fTime = fTime;
if (self->eMode == eTimer) {
pPriv->cachedControl = fTime;
} else {
pPriv->cachedControl = m1;
}
return 1;
}
/*------------------------------------------------------------------*/
static int EL737SStatus(struct __COUNTER *self, float *fControl)
{
int status, RS, returnValue;
pEL737hpsps pPriv = NULL;
int iBit = 0;
assert(self);
pPriv = (pEL737hpsps) self->pData;
/*
handle STATSEND mode
*/
if (pPriv->statusMode == STATSEND) {
status = writeRS232(pPriv->controller, "RS\r", 3);
if (status < 0) {
pPriv->errorCode = status;
return HWFault;
}
pPriv->statusMode = STATRECEIVE;
pPriv->startRequest = time(NULL);
*fControl = pPriv->cachedControl;
return pPriv->lastStatus;
}
/*
now we are dealing with STATRECEIVE mode.
Check for timeout first.
*/
if (time(NULL) > pPriv->startRequest + 10) {
pPriv->statusMode = STATSEND;
pPriv->errorCode = TIMEOUT737;
pPriv->readErrorCount++;
return HWFault;
}
/*
check availability of data
*/
status = availableNetRS232(pPriv->controller);
if (status == 0) {
*fControl = pPriv->cachedControl;
return pPriv->lastStatus;
} else if (status < 0) {
*fControl = pPriv->cachedControl;
pPriv->statusMode = STATSEND;
pPriv->errorCode = SELECTFAIL;
return HWFault;
}
/*
The snail in the counter box has replied. Read and process
the data
*/
pPriv->statusMode = STATSEND;
if (!readRS(pPriv, &RS)) {
return HWFault;
}
/*
decode it
*/
returnValue = decodeRS(pPriv, RS);
pPriv->lastStatus = returnValue;
/*
check for excessive failed reads
*/
if (pPriv->readErrorCount > 3) {
pPriv->errorCode = TOMANYREADERRORS;
return HWFault;
}
/*
check if we update the monitors and do it
*/
pPriv->monitorCount++;
if (pPriv->monitorCount > MONTHRESH) {
status = updateMonitors(self);
pPriv->monitorCount = 0;
if (!status) {
return HWFault;
}
}
*fControl = pPriv->cachedControl;
if (returnValue == HWNoBeam) {
/* ToDo: put in proper bit address when properly known */
SPSGetStatus(pPriv->sps, 79, &iBit);
if (iBit == 1) {
pPriv->errorCode = DETOVERLOAD;
return HWFault;
}
}
return returnValue;
}
/*-------------------------------------------------------------------*/
static int EL737SStart(struct __COUNTER *self)
{
pEL737hpsps pPriv = NULL;
int status;
char pCommand[50], pReply[30];
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
pPriv->readErrorCount = 0;
if (self->eMode == ePreset) {
snprintf(pCommand, 49, "MP %d\r", (int) self->fPreset);
} else {
if (self->fPreset < .1 || self->fPreset > 200000) {
self->iErrorCode = BADTRANGE;
return HWFault;
}
snprintf(pCommand, 49, "TP %.2f\r", self->fPreset);
}
if (EL737SCommand(pPriv, pCommand, pReply, 29) != 1) {
return 0;
}
pPriv->finishCount = 0;
pPriv->lastStatus = HWBusy;
return 1;
}
/* --------------------------------------------------------------------*/
static int EL737SPause(struct __COUNTER *self)
{
pEL737hpsps pPriv = NULL;
int status;
char pCommand[50], pReply[30];
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
pPriv->lastStatus = HWPause;
return EL737SCommand(pPriv, "PS\r", pReply, 29);
}
/*----------------------------------------------------------------------*/
static int EL737SContinue(struct __COUNTER *self)
{
pEL737hpsps pPriv = NULL;
int status;
char pCommand[50], pReply[30];
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
pPriv->lastStatus = HWBusy;
return EL737SCommand(pPriv, "CO\r", pReply, 29);
}
/*---------------------------------------------------------------------*/
static int EL737SHalt(struct __COUNTER *self)
{
pEL737hpsps pPriv = NULL;
int status;
char pCommand[50], pReply[30];
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
pPriv->lastStatus = HWBusy;
return EL737SCommand(pPriv, "S\r", pReply, 29);
}
/*-------------------------------------------------------------------*/
static int EL737STransfer(struct __COUNTER *self)
{
pEL737hpsps pPriv = NULL;
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
return updateMonitors(self);
}
/*--------------------------------------------------------------------*/
static int EL737SGetError(struct __COUNTER *self, int *iCode,
char *pError, int errLen)
{
pEL737hpsps pPriv = NULL;
assert(self);
pPriv = (pEL737hpsps) self->pData;
*iCode = pPriv->errorCode;
switch (pPriv->errorCode) {
case OFFLINE:
strlcpy(pError, "EL737 is offline", errLen);
break;
case OVERFLOW:
strlcpy(pError, "EL737 reported overflow, communication problem",
errLen);
break;
case BADRANGE:
strlcpy(pError, "EL737 parameter is out of range", errLen);
break;
case BADTRANGE:
strlcpy(pError, "preset timer out of range", errLen);
break;
case BADCOMMAND:
strlcpy(pError, "EL737 received unknown command or is busy", errLen);
break;
case BADPARAM:
strlcpy(pError, "EL737 parameter is awful", errLen);
break;
case NOPARAM:
strlcpy(pError, "EL737 parameter missing", errLen);
break;
case TOMANYCOUNTS:
strlcpy(pError, "EL737 counters overflowed", errLen);
break;
case SYSERROR:
strlcpy(pError, "EL737 has an internal system error", errLen);
break;
case BADREPLY:
snprintf(pError, errLen, "EL737 sent an unexpected reply: %s",
pPriv->badReply);
break;
case SELECTFAIL:
strlcpy(pError, "select system call failed, network trouble", errLen);
break;
case TIMEOUT737:
strlcpy(pError,
"timeout or network problem while waiting for status repsonse",
errLen);
break;
case TOMANYREADERRORS:
strlcpy(pError, "Failed more then three times to read counter box",
errLen);
break;
case DETOVERLOAD:
strlcpy(pError, "Shutter closed due to detector overload", errLen);
break;
default:
getRS232Error(pPriv->errorCode, pError, errLen);
}
return 1;
}
/*--------------------------------------------------------------------*/
static int EL737SFixIt(struct __COUNTER *self, int iCode)
{
pEL737hpsps pPriv = NULL;
int status;
char pReply[50];
char buffer[256];
int dataLen = 255;
int i;
assert(self);
pPriv = (pEL737hpsps) self->pData;
switch (iCode) {
case BADPARAM:
case NOPARAM:
case BADRANGE:
case BADTRANGE:
case OVERFLOW:
return COREDO;
break;
case BADREPLY:
case TIMEOUT737:
case TIMEOUT:
for (i = 0; i < 3; i++) {
status = readRS232TillTerm(pPriv->controller, buffer, &dataLen);
if (status == 1) {
return COREDO;
}
}
/*
If nothing can be read, the only fixable cause is a network breakdown
Try to fix this. If this does not work: give up
*/
closeRS232(pPriv->controller);
SicsWait(60);
status = initRS232(pPriv->controller);
if (status != 1) {
return COTERM;
} else {
return COREDO;
}
break;
case OFFLINE:
EL737SCommand(pPriv, "RMT 1\r", pReply, 49);
EL737SCommand(pPriv, "echo 2\r", pReply, 49);
return COREDO;
break;
case BADCOMMAND: /* can be busy, stop it and try again */
EL737SCommand(pPriv, "S\r", pReply, 49);
return COREDO;
break;
case TOMANYCOUNTS:
case SYSERROR:
case DETOVERLOAD:
return COTERM;
break;
default:
/*
network problem; try to reopen
*/
closeRS232(pPriv->controller);
SicsWait(60);
status = initRS232(pPriv->controller);
if (status != 1) {
return COTERM;
} else {
return COREDO;
}
}
}
/*------------------------------------------------------------------------*/
static int EL737SSet(struct __COUNTER *self, char *name, int iCter,
float fVal)
{
pEL737hpsps pPriv = NULL;
int status;
char pCommand[80], pReply[50];
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
if (strcmp(name, "threshold") == 0) {
sprintf(pCommand, "DL %1.1d %f\r", iCter, fVal);
if (!EL737SCommand(pPriv, pCommand, pReply, 49)) {
return 0;
}
sprintf(pCommand, "DR %1.1d\r", iCter);
if (!EL737SCommand(pPriv, pCommand, pReply, 49)) {
return 0;
}
return 1;
} else {
self->iErrorCode = UNKNOWNPAR;
return 0;
}
}
/*----------------------------------------------------------------------*/
static int EL737SGet(struct __COUNTER *self, char *name, int iCter,
float *fVal)
{
pEL737hpsps pPriv = NULL;
int status;
char pCommand[80], pReply[50];
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
if (strcmp(name, "threshold") == 0) {
sprintf(pCommand, "DL %1.1d\r", iCter);
if (!EL737SCommand(pPriv, pCommand, pReply, 49)) {
return 0;
}
sscanf(pReply, "%f", fVal);
return 1;
} else {
self->iErrorCode = UNKNOWNPAR;
return 0;
}
}
/*--------------------------------------------------------------------*/
static int EL737SSend(struct __COUNTER *self, char *pText, char *pReply,
int iReplyLen)
{
pEL737hpsps pPriv = NULL;
assert(self);
pPriv = (pEL737hpsps) self->pData;
fixMode(pPriv);
return EL737SCommand(pPriv, pText, pReply, iReplyLen);
}
/*---------------------------------------------------------------------*/
static void KillHP(pCounterDriver self)
{
pEL737hpsps pPriv = NULL;
assert(self);
pPriv = (pEL737hpsps) self->pData;
if (!pPriv) {
return;
}
if (pPriv->controller != NULL) {
KillRS232(pPriv->controller);
}
if (pPriv->badReply != NULL) {
free(pPriv->badReply);
}
free(pPriv);
}
/*-------------------------------------------------------------------*/
pCounterDriver MakeEL737hpsps(SConnection * pCon, char *name,
int argc, char *argv[])
{
pCounterDriver pNew = NULL;
pEL737hpsps pPriv = NULL;
char pHost[132];
int port, status;
/*
check arguments
*/
if (argc < 3) {
SCWrite(pCon,
"ERROR: insufficient no af arguments to create EL737HPSPS",
eError);
return NULL;
}
if (!isNumeric(argv[1])) {
SCWrite(pCon, "ERROR: expected numeric argument for port number",
eError);
return NULL;
}
port = atoi(argv[1]);
strlcpy(pHost, argv[0], 131);
/*
allocate a bank worth of memory ...........
*/
pNew = CreateCounterDriver(name, "EL737HPSPS");
pPriv = (pEL737hpsps) malloc(sizeof(EL737hpsps));
if (!pNew || !pPriv) {
return NULL;
}
memset(pPriv, 0, sizeof(EL737hpsps));
pPriv->controller = createRS232(pHost, port);
if (!pPriv->controller) {
DeleteCounterDriver(pNew);
return NULL;
}
pPriv->sps = (pSPS) FindCommandData(pServ->pSics, argv[2], "SPS");
if (pPriv->sps == NULL) {
SCWrite(pCon, "ERROR: SPS not found", eError);
DeleteCounterDriver(pNew);
return NULL;
}
/* assign functions */
pNew->GetStatus = EL737SStatus;
pNew->Start = EL737SStart;
pNew->Halt = EL737SHalt;
pNew->ReadValues = EL737STransfer;
pNew->GetError = EL737SGetError;
pNew->TryAndFixIt = EL737SFixIt;
pNew->Pause = EL737SPause;
pNew->Continue = EL737SContinue;
pNew->Set = EL737SSet;
pNew->Get = EL737SGet;
pNew->Send = EL737SSend;
pNew->KillPrivate = KillHP;
pNew->iNoOfMonitors = 7;
pNew->fTime = 0.;
pNew->pData = pPriv;
/*
initialize connection
*/
setRS232Debug(pPriv->controller, 0);
setRS232ReplyTerminator(pPriv->controller, "\r");
status = initRS232(pPriv->controller);
status = EL737SCommand(pPriv, "RMT 1\r", pHost, 131);
status = EL737SCommand(pPriv, "RMT 1\r", pHost, 131);
status = EL737SCommand(pPriv, "ECHO 2\r", pHost, 131);
return pNew;
}