Files
sicspsi/bruker.c

883 lines
22 KiB
C

/*-------------------------------------------------------------------------
B r u k e r
An environment control driver and an additonal wrapper function for
controlling a Bruker B-EC-1 magnet controller. This controller can
either control a current or control the current through an external hall
sensor mesuring the magnetic field. In both cases both values: the field
and the current must be readable.
copyright: see copyright.h
Mark Koennecke, October 1998
---------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <tcl.h>
#include <math.h>
#include <assert.h>
#include <fortify.h>
#include <sics.h>
#include <obpar.h>
#include <evcontroller.h>
#include <evcontroller.i>
#include <evdriver.i>
#include "hardsup/serialsinq.h"
#include "hardsup/el734_errcodes.h"
#include "hardsup/el734fix.h"
#include "bruker.h"
/*
#define debug 1
*/
/*-----------------------------------------------------------------------
The Bruker Data Structure
*/
typedef struct {
void *pData;
char *pHost;
int iPort;
int iChannel;
int iMode;
int iLastError;
} BrukerDriv, *pBrukerDriv;
/*-----------------------------------------------------------------------
A couple of defines for Bruker modes and special error conditions
*/
#define FIELD 100
#define CURRENT 200
/* errors */
#define NOFUNC -1601
#define BADARG -1602
#define NOACCESS -1603
#define BADRANGE -1604
#define ERRPENDING -1605
#define NOPOWER -1606
#define NOTFIELD -1607
#define BADINTERN -1608
#define NOCONN -1609
#define BTIMEOUT -1610
#define NOPOLUNIT -1620
/* polarity */
#define PPLUS 0
#define PMINUS 1
#define PBUSY 3
/* rmtrail.c */
extern char *rmtrail(char *p);
/*---------------------------------------------------------------------------
This Bruker thing has a lot of internal error conditions and a few nasty
habits. Such as to lock up after an error ocurred until the error is reset.
Or to switch the power off, when a current above the limit is requested
after setting a bad value for the magnetic field. These problems can be
detected by analysing the return values from the Bruker. Usually the Bruker
returns the command given to the user plus additional values if requested.
On an error a string of the type E0n is appended to the command echo with
n being a small integer. In order to handle this all commands to the Bruker
are processed through this special function which takes care of the error
handling.
*/
static int BrukerCommand(pBrukerDriv self, char *pCommand,
char *pReplyBuffer, int iReplyLen)
{
int iTest, iCode;
char *pPtr;
assert(self);
assert(iReplyLen > 20); /* so small a buffer will hide errors */
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
/* send the command to the Bruker */
rmtrail(pCommand);
iTest =
SerialWriteRead(&(self->pData), pCommand, pReplyBuffer, iReplyLen);
#ifdef debug
printf("Comm: %s , Reply %s\n", pCommand, pReplyBuffer);
#endif
if (iTest != 1) { /* communication error */
self->iLastError = iTest;
return 0;
}
/* identify timeout */
if (strstr(pReplyBuffer, "?TMO") != NULL) {
self->iLastError = BTIMEOUT;
return 0;
}
/* try to find a E0 response indicating a Bruker error */
if ((pPtr = strstr(pReplyBuffer, "E0")) == NULL) {
return 1;
}
/* decode the error */
sscanf(pPtr + 1, "%x", &iCode);
switch (iCode) {
case 1:
self->iLastError = NOFUNC;
break;
case 2:
self->iLastError = BADARG;
break;
case 4:
self->iLastError = NOACCESS;
break;
case 5:
self->iLastError = BADRANGE;
break;
case 7:
self->iLastError = ERRPENDING;
break;
case 9:
self->iLastError = NOPOWER;
break;
case 10:
self->iLastError = NOTFIELD;
break;
default:
self->iLastError = BADINTERN;
break;
}
return 0;
}
/*-------------------------------------------------------------------------*/
int BrukerReadField(pEVControl pEva, float *fField)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign;
int iSign = 1;
float fVal;
self = (pBrukerDriv) pEva->pDriv->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand, "FIE/");
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
if (!iRet) {
*fField = -99;
return 0;
}
pPtr = pBueffel + 4; /* skip over echo */
/* deal with obstructing sign */
if ((pSign = strchr(pPtr, '+')) != NULL) {
*pSign = ' ';
iSign = 1;
}
if ((pSign = strchr(pPtr, '-')) != NULL) {
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr, "%f", &fVal);
*fField = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
int BrukerReadCurrent(pEVControl pEva, float *fField)
{
pBrukerDriv self = NULL;
int iRet, iSign = 1;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign = NULL;
float fVal;
self = (pBrukerDriv) pEva->pDriv->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand, "CHN/");
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
if (!iRet) {
*fField = -99;
return 0;
}
pPtr = pBueffel + 4; /* skip over echo */
/* deal with obstructing sign */
if ((pSign = strchr(pPtr, '+')) != NULL) {
*pSign = ' ';
iSign = 1;
}
if ((pSign = strchr(pPtr, '-')) != NULL) {
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr, "%f", &fVal);
*fField = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerGet(pEVDriver pEva, float *fValue)
{
pBrukerDriv self = NULL;
int iRet=0, iSign = 1;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign = NULL;
float fVal;
self = (pBrukerDriv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
if (self->iMode == FIELD) {
strcpy(pCommand, "CUF/");
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
} else if (self->iMode == CURRENT) {
strcpy(pCommand, "CUR/");
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
} else {
/* programming error */
assert(1);
}
if (!iRet) {
*fValue = -99;
return 0;
}
pPtr = pBueffel + 4; /* skip over echo */
/* deal with obstructing sign */
if ((pSign = strchr(pPtr, '+')) != NULL) {
*pSign = ' ';
iSign = 1;
}
if ((pSign = strchr(pPtr, '-')) != NULL) {
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr, "%f", &fVal);
*fValue = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerRun(pEVDriver pEva, float fVal)
{
pBrukerDriv self = NULL;
int iRet =0;
char pBueffel[80];
char pCommand[40];
char *pPtr;
self = (pBrukerDriv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
if (self->iMode == FIELD) {
sprintf(pCommand, "PTF=%-6.2f", fVal);
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
} else if (self->iMode == CURRENT) {
sprintf(pCommand, "PNT=%-6.2f", fVal);
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
} else {
/* programming error */
assert(1);
}
if (!iRet) {
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
static int BrukerError(pEVDriver pEva, int *iCode, char *pError,
int iErrLen)
{
pBrukerDriv self = NULL;
self = (pBrukerDriv) pEva->pPrivate;
assert(self);
*iCode = self->iLastError;
switch (*iCode) {
case NOFUNC:
strlcpy(pError, "Function not supported", iErrLen);
break;
case BADINTERN:
case BADARG:
strlcpy(pError,
"Programming problem, reset Controller & contact Programmer",
iErrLen);
break;
case NOTFIELD:
strlcpy(pError, "Bruker not switched to field mode", iErrLen);
break;
case BADRANGE:
strlcpy(pError, "Requested value out of range", iErrLen);
break;
case NOACCESS:
strlcpy(pError, "No Access, check key position at Controller",
iErrLen);
break;
case ERRPENDING:
strlcpy(pError, "Error condition pending in Bruker Controller",
iErrLen);
break;
case NOPOWER:
strlcpy(pError,
"Power OFF as consequence of some error in Bruker Controller",
iErrLen);
break;
case NOCONN:
strlcpy(pError, "No Connection to Bruker Controller", iErrLen);
break;
case BTIMEOUT:
strlcpy(pError, "Timeout at serial port", iErrLen);
break;
case NOPOLUNIT:
strlcpy(pError,
"No polarity switching unit, try setting negative current",
iErrLen);
break;
default:
SerialError(*iCode, pError, iErrLen);
break;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int BrukerSend(pEVDriver pEva, char *pCommand, char *pReply,
int iReplyLen)
{
pBrukerDriv self = NULL;
int iRet;
self = (pBrukerDriv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
iRet = SerialWriteRead(&(self->pData), pCommand, pReply, iReplyLen);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int BrukerInit(pEVDriver pEva)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80], pCommand[20];
self = (pBrukerDriv) pEva->pPrivate;
assert(self);
/* open port connection */
self->pData = NULL;
iRet =
SerialOpen(&(self->pData), self->pHost, self->iPort, self->iChannel);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
/* configure serial port terminators */
SerialSendTerm(&(self->pData), "\r");
SerialATerm(&(self->pData), "1\r\n");
/* set power on */
strcpy(pCommand, "DCP=1");
iRet = SerialWriteRead(&(self->pData), pCommand, pBueffel, 80);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
/* switch to current mode as default init mode */
self->iMode = CURRENT;
strcpy(pCommand, "EXT=0");
iRet = SerialWriteRead(&(self->pData), pCommand, pBueffel, 80);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerClose(pEVDriver pEva)
{
pBrukerDriv self = NULL;
self = (pBrukerDriv) pEva->pPrivate;
assert(self);
SerialClose(&(self->pData));
self->pData = 0;
return 1;
}
/*---------------------------------------------------------------------------*/
static int BrukerFix(pEVDriver self, int iError)
{
pBrukerDriv pMe = NULL;
int iRet;
char pCommand[20], pBueffel[80];
assert(self);
pMe = (pBrukerDriv) self->pPrivate;
assert(pMe);
switch (iError) {
/* network errors */
case EL734__BAD_FLUSH:
case EL734__BAD_RECV:
case EL734__BAD_RECV_NET:
case EL734__BAD_RECV_UNKN:
case EL734__BAD_RECVLEN:
case EL734__BAD_RECV1:
case EL734__BAD_RECV1_PIPE:
case EL734__BAD_RNG:
case EL734__BAD_SEND:
case EL734__BAD_SEND_PIPE:
case EL734__BAD_SEND_NET:
case EL734__BAD_SEND_UNKN:
case EL734__BAD_SENDLEN:
BrukerClose(self);
iRet = BrukerInit(self);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
case EL734__FORCED_CLOSED:
case NOCONN:
iRet = BrukerInit(self);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
/* fixable Bruker Errors */
case ERRPENDING:
strcpy(pCommand, "RST=0");
iRet = BrukerCommand(pMe, pCommand, pBueffel, 79);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
case NOPOWER:
strcpy(pCommand, "RST=0");
iRet = BrukerCommand(pMe, pCommand, pBueffel, 79);
strcpy(pCommand, "DCP=1");
iRet = BrukerCommand(pMe, pCommand, pBueffel, 79);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
case NOTFIELD:
strcpy(pCommand, "EXT=2");
iRet = BrukerCommand(pMe, pCommand, pBueffel, 79);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
/* handable protocoll errors */
case EL734__BAD_TMO:
case BTIMEOUT:
case NOFUNC:
return DEVREDO;
break;
default:
return DEVFAULT;
break;
}
return DEVFAULT;
}
/*------------------------------------------------------------------------*/
void KillBruker(void *pData)
{
pBrukerDriv pMe = NULL;
pMe = (pBrukerDriv) pData;
assert(pMe);
if (pMe->pHost) {
free(pMe->pHost);
}
free(pMe);
}
/*------------------------------------------------------------------------*/
pEVDriver CreateBrukerDriver(int argc, char *argv[])
{
pEVDriver pNew = NULL;
pBrukerDriv pSim = NULL;
/* check for arguments */
if (argc < 3) {
return NULL;
}
pNew = CreateEVDriver(argc, argv);
pSim = (pBrukerDriv) malloc(sizeof(BrukerDriv));
memset(pSim, 0, sizeof(BrukerDriv));
if (!pNew || !pSim) {
return NULL;
}
pNew->pPrivate = pSim;
pNew->KillPrivate = KillBruker;
/* initalise pBrukerDriver */
pSim->iLastError = 0;
pSim->pHost = strdup(argv[0]);
pSim->iPort = atoi(argv[1]);
pSim->iChannel = atoi(argv[2]);
/* initialise function pointers */
pNew->SetValue = BrukerRun;
pNew->GetValue = BrukerGet;
pNew->Send = BrukerSend;
pNew->GetError = BrukerError;
pNew->TryFixIt = BrukerFix;
pNew->Init = BrukerInit;
pNew->Close = BrukerClose;
return pNew;
}
/*-------------------------------------------------------------------------*/
int BrukerSetMode(pEVControl pEva, SConnection * pCon, int iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv) pEva->pDriv->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
if (iMode == CURRENT) {
strcpy(pCommand, "EXT=0");
} else if (iMode == FIELD) {
strcpy(pCommand, "EXT=2");
} else {
SCWrite(pCon, "ERROR: Internal: invalid mode for Bruker given",
eError);
return 0;
}
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
if (!iRet) {
strcpy(pBueffel, "ERROR:");
BrukerError(pEva->pDriv, &iRet, (pBueffel + 7), 70);
SCWrite(pCon, pBueffel, eError);
return 0;
}
self->iMode = iMode;
return 1;
}
/*-------------------------------------------------------------------------*/
int BrukerGetPolarity(pEVControl pEva, SConnection * pCon, int *iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv) pEva->pDriv->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand, "POL/");
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
if (!iRet) {
strcpy(pBueffel, "ERROR:");
BrukerError(pEva->pDriv, &iRet, (pBueffel + 7), 70);
SCWrite(pCon, pBueffel, eError);
return 0;
}
pPtr = pBueffel + 4;
sscanf(pPtr, "%d", iMode);
return 1;
}
/*------------------------------------------------------------------------*/
int BrukerSetPolarity(pEVControl pEva, SConnection * pCon, int iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv) pEva->pDriv->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
if (iMode == PPLUS) {
strcpy(pCommand, "POL=0");
} else if (iMode == PMINUS) {
strcpy(pCommand, "POL=1");
} else {
assert(1); /* programming error */
}
iRet = BrukerCommand(self, pCommand, pBueffel, 79);
if ((strstr(pBueffel, "POL=0E01") != NULL) ||
(strstr(pBueffel, "POL=1E01") != NULL)) {
self->iLastError = NOPOLUNIT;
iRet = 0;
}
if (!iRet) {
strcpy(pBueffel, "ERROR:");
BrukerError(pEva->pDriv, &iRet, (pBueffel + 6), 70);
SCWrite(pCon, pBueffel, eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------
handle Bruker specific commands:
- polarity for switching polarity
- field for reading field
- current for reading current
- mode for setting and retrieving the current control mode
- list append our own stuff to the rest
in all other cases fall back and call EVControllerWrapper to handle it or
eventually throw an error.
*/
int BrukerAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pEVControl self = NULL;
int iRet, iMode;
char pBueffel[256];
pBrukerDriv pMe = NULL;
float fVal;
self = (pEVControl) pData;
assert(self);
pMe = (pBrukerDriv) self->pDriv->pPrivate;
assert(pMe);
if (argc > 1) {
strtolower(argv[1]);
/*------ polarity */
if (strcmp(argv[1], "polarity") == 0) {
if (argc > 2) { /* set case */
strtolower(argv[2]);
if (strcmp(argv[2], "plus") == 0) {
iMode = PPLUS;
} else if (strcmp(argv[2], "minus") == 0) {
iMode = PMINUS;
} else {
sprintf(pBueffel, "ERROR: %s is no knwon polarity mode",
argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* check permission */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
/* do it */
iRet = BrukerSetPolarity(self, pCon, iMode);
if (iRet) {
SCSendOK(pCon);
return 1;
} else {
return 0;
}
} else { /* get case */
iRet = BrukerGetPolarity(self, pCon, &iMode);
if (iRet) {
if (iMode == PPLUS) {
sprintf(pBueffel, "%s.polarity = plus", argv[0]);
} else if (iMode == PMINUS) {
sprintf(pBueffel, "%s.polarity = minus", argv[0]);
} else {
assert(1); /* programming problem */
}
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
}
/*-------- control mode */
else if (strcmp(argv[1], "mode") == 0) {
if (argc > 2) { /* set case */
strtolower(argv[2]);
if (strcmp(argv[2], "field") == 0) {
iMode = FIELD;
} else if (strcmp(argv[2], "current") == 0) {
iMode = CURRENT;
} else {
sprintf(pBueffel, "ERROR: %s is no known control mode", argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* check permission */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
/* do it */
iRet = BrukerSetMode(self, pCon, iMode);
if (iRet) {
SCSendOK(pCon);
return 1;
} else {
return 0;
}
} else { /* get case */
if (pMe->iMode == FIELD) {
sprintf(pBueffel, "%s.mode = field", argv[0]);
} else if (pMe->iMode == CURRENT) {
sprintf(pBueffel, "%s.mode = current", argv[0]);
} else {
assert(1); /* programming problem */
}
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
/*-----------field */
else if (strcmp(argv[1], "field") == 0) {
iRet = BrukerReadField(self, &fVal);
if (!iRet) {
strcpy(pBueffel, "ERROR: ");
self->pDriv->GetError(self->pDriv, &iMode, pBueffel + 7, 240);
SCWrite(pCon, pBueffel, eError);
return 0;
}
sprintf(pBueffel, "%s.field = %f Tesla", argv[0], fVal);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
/*----------- current */
else if (strcmp(argv[1], "current") == 0) {
iRet = BrukerReadCurrent(self, &fVal);
if (!iRet) {
strcpy(pBueffel, "ERROR: ");
self->pDriv->GetError(self->pDriv, &iMode, pBueffel + 7, 240);
SCWrite(pCon, pBueffel, eError);
return 0;
}
sprintf(pBueffel, "%s.current = %f A", argv[0], fVal);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
/*--------- list */
else if (strcmp(argv[1], "list") == 0) {
/* print generals first */
EVControlWrapper(pCon, pSics, pData, argc, argv);
/* print our add on stuff */
iRet = BrukerReadCurrent(self, &fVal);
if (!iRet) {
strcpy(pBueffel, "ERROR: ");
self->pDriv->GetError(self->pDriv, &iMode, pBueffel + 7, 240);
SCWrite(pCon, pBueffel, eError);
} else {
sprintf(pBueffel, "%s.current = %f A", argv[0], fVal);
SCWrite(pCon, pBueffel, eValue);
}
iRet = BrukerReadField(self, &fVal);
if (!iRet) {
strcpy(pBueffel, "ERROR: ");
self->pDriv->GetError(self->pDriv, &iMode, pBueffel + 7, 240);
SCWrite(pCon, pBueffel, eError);
} else {
sprintf(pBueffel, "%s.field = %f Tesla", argv[0], fVal);
SCWrite(pCon, pBueffel, eValue);
}
if (pMe->iMode == FIELD) {
sprintf(pBueffel, "%s.mode = field", argv[0]);
} else if (pMe->iMode == CURRENT) {
sprintf(pBueffel, "%s.mode = current", argv[0]);
} else {
sprintf(pBueffel, "ERROR: Programming error");
}
SCWrite(pCon, pBueffel, eValue);
iRet = BrukerGetPolarity(self, pCon, &iMode);
if (iRet) {
if (iMode == PPLUS) {
sprintf(pBueffel, "%s.polarity = plus", argv[0]);
} else if (iMode == PMINUS) {
sprintf(pBueffel, "%s.polarity = minus", argv[0]);
} else if (iMode == PBUSY) {
sprintf(pBueffel, "%s.polarity = busy", argv[0]);
} else {
sprintf(pBueffel, "ERROR: Programming problem");
}
SCWrite(pCon, pBueffel, eValue);
} else {
SCWrite(pCon, "ERROR: cannot read polarity", eError);
}
return 1;
} else {
return EVControlWrapper(pCon, pSics, pData, argc, argv);
}
}
return EVControlWrapper(pCon, pSics, pData, argc, argv);
}