Files
sicspsi/ltc11.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

751 lines
19 KiB
C

/*-------------------------------------------------------------------------
L T C 1 1
an environment control device driver for a Neocera LTC-11 temperature
controller.
copyright: see copyright.h
Mark Koennecke, November 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 "ltc11.h"
/*
#define debug 1
*/
/*-----------------------------------------------------------------------
The LTC11 Data Structure
*/
typedef struct {
void *pData;
char *pHost;
int iPort;
int iChannel;
int iMode;
int iSensor;
int iControlHeat;
int iControlAnalog;
int iLastError;
time_t lastRequest;
float fLast;
} LTC11Driv, *pLTC11Driv;
/*-----------------------------------------------------------------------
A couple of defines for LTC11 modes and special error conditions
*/
#define ANALOG 2
#define HEATER 1
#define MISERABLE 3
/* errors */
#define BADSTATE -920
#define NOCONN -921
#define BADANSWER -923
#define BADCONFIRM -924
/*-----------------------------------------------------------------------*/
static void LTC11Unlock(pLTC11Driv self)
{
SerialNoReply(&(self->pData), "SLLOCK 0;");
}
/*-------------------------------------------------------------------------
The LTC11 can either control a heater or an analog output. It is a common
task to figure out which mode is active. If the value returned from QOUT
is 3, no sensor is defined, if it is 6 it is in monitor mode, in both cases
control is NOT there.
*/
int LTC11GetMode(pEVDriver pEva, int *iMode)
{
pLTC11Driv self = NULL;
int iRet, iiMode;
char pBueffel[80];
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
/* query the state, it can be in an invalid mode */
iRet = SerialWriteRead(&(self->pData), "QISTATE?;", pBueffel, 79);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
if (strcmp(pBueffel, "?TMO") == 0) {
self->iLastError = TIMEOUT;
return 0;
}
if (sscanf(pBueffel, "%d", &iiMode) != 1) {
self->iLastError = EL734__BAD_ILLG;
return 0;
}
if ((iiMode != 1) && (iiMode != 2)) {
self->iLastError = BADSTATE;
*iMode = MISERABLE;
return 0;
}
/* check the sensor in heater mode */
iRet = SerialWriteRead(&(self->pData), "QOUT?1;", pBueffel, 79);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
if (strcmp(pBueffel, "?TMO") == 0) {
self->iLastError = TIMEOUT;
return 0;
}
if (sscanf(pBueffel, "%d", &iiMode) != 1) {
self->iLastError = EL734__BAD_ILLG;
return 0;
}
if ((iiMode != 3) && (iiMode != 6)) {
*iMode = HEATER;
self->iControlHeat = iiMode;
return 1;
}
/* check the sensor in analog mode */
iRet = SerialWriteRead(&(self->pData), "QOUT?2;", pBueffel, 79);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
if (strcmp(pBueffel, "?TMO") == 0) {
self->iLastError = TIMEOUT;
return 0;
}
if (sscanf(pBueffel, "%d", &iiMode) != 1) {
self->iLastError = EL734__BAD_ILLG;
return 0;
}
if ((iiMode != 3) && (iiMode != 6)) {
*iMode = ANALOG;
self->iControlAnalog = iiMode;
return 1;
}
/* if we are here something is very bad */
self->iLastError = BADSTATE;
return 0;
}
/*-----------------------------------------------------------------------
iMode below 10 will be interpreted as heater control, above 10 as analog
control.
*/
int LTC11SetMode(pEVDriver pEva, int iMode)
{
pLTC11Driv self = NULL;
int iRet, iiMode;
char pBueffel[80], pCommand[20];
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
if (iMode < 10) { /* heater mode */
sprintf(pCommand, "SHCONT%1.1d;", iMode);
iRet = SerialNoReply(&(self->pData), pCommand);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
return 1;
} else {
iMode -= 10;
sprintf(pCommand, "SACONT%1.1d;", iMode);
iRet = SerialNoReply(&(self->pData), pCommand);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
return 1;
}
/* should not get here */
self->iLastError = BADSTATE;
return 0;
}
/*-------------------------------------------------------------------------*/
static int LTC11Get(pEVDriver pEva, float *fValue)
{
pLTC11Driv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[46];
char c;
float fVal;
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
if (time(NULL) < self->lastRequest) {
*fValue = self->fLast;
return 1;
} else {
self->lastRequest = time(NULL) + 5; /* buffer 5 seconds */
}
sprintf(pCommand, "QSAMP?%1.1d;", self->iSensor);
iRet = SerialWriteRead(&(self->pData), pCommand, pBueffel, 79);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
if (strcmp(pBueffel, "?TMO") == 0) {
self->iLastError = TIMEOUT;
return 0;
}
iRet = sscanf(pBueffel, "%f%c", fValue, &c);
if (iRet != 2) {
self->iLastError = BADANSWER;
return 0;
}
if ((c != 'K') && (c != 'C') && (c != 'F') && (c != 'N')
&& (c != 'V') && (c != 'O')) {
self->iLastError = BADANSWER;
return 0;
}
self->fLast = *fValue;
return 1;
}
/*-------------------------------------------------------------------------*/
static int LTC11Run(pEVDriver pEva, float fVal)
{
pLTC11Driv self = NULL;
int iRet, iMode;
char pBueffel[80];
char pCommand[40];
float fTest = 0.0, fDelta;
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
if (self->pData == NULL) {
self->iLastError = NOCONN;
return 0;
}
/* find our operation mode */
iRet = LTC11GetMode(pEva, &iMode);
if ((iRet < 1) || (iMode == MISERABLE)) {
return 0;
}
/* format command */
sprintf(pCommand, "SETP %d,%f;", iMode, fVal);
/* send command */
iRet = SerialNoReply(&(self->pData), pCommand);
if (iRet != 1) {
self->iLastError = iRet;
LTC11Unlock(self);
return 0;
}
/* read back */
sprintf(pCommand, "QSETP?%d;", iMode);
iRet = SerialWriteRead(&(self->pData), pCommand, pBueffel, 79);
LTC11Unlock(self);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
/* check confirmation */
if (strcmp(pBueffel, "?TMO") == 0) {
self->iLastError = TIMEOUT;
return 0;
}
sscanf(pBueffel, "%f", &fTest);
fDelta = fVal - fTest;
if (fDelta < 0.0)
fDelta = -fDelta;
if (fDelta > 0.1) {
self->iLastError = BADCONFIRM;
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
static int LTC11Error(pEVDriver pEva, int *iCode, char *pError,
int iErrLen)
{
pLTC11Driv self = NULL;
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
*iCode = self->iLastError;
switch (*iCode) {
case NOCONN:
strlcpy(pError, "No Connection to Bruker Controller", iErrLen);
break;
case MISERABLE:
case BADSTATE:
strlcpy(pError, "The LTC-11 is in a very bad state", iErrLen);
break;
case BADANSWER:
strlcpy(pError, "The LTC-11 returned a bad reply", iErrLen);
break;
case BADCONFIRM:
strlcpy(pError, "The LTC-11 did not accept the new set point",
iErrLen);
break;
case TIMEOUT:
strlcpy(pError, "Timeout receiving data from LTC-11", iErrLen);
break;
default:
SerialError(*iCode, pError, iErrLen);
break;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int LTC11Send(pEVDriver pEva, char *pCommand, char *pReply,
int iReplyLen)
{
pLTC11Driv self = NULL;
int iRet;
self = (pLTC11Driv) 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 LTC11Init(pEVDriver pEva)
{
pLTC11Driv self = NULL;
int iRet;
char pBueffel[80], pCommand[20];
self = (pLTC11Driv) 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), ";");
SerialATerm(&(self->pData), "1;");
SerialConfig(&(self->pData), 30000);
self->iSensor = 1;
/* initialize control sensors to unknown, then call GetMode
to get real values
*/
self->iControlHeat = 6;
self->iControlAnalog = 6;
LTC11GetMode(pEva, &iRet);
return 1;
}
/*-------------------------------------------------------------------------*/
static int LTC11Close(pEVDriver pEva)
{
pLTC11Driv self = NULL;
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
SerialClose(&(self->pData));
self->pData = 0;
return 1;
}
/*---------------------------------------------------------------------------*/
static int LTC11Fix(pEVDriver self, int iError)
{
pLTC11Driv pMe = NULL;
int iRet;
char pCommand[20], pBueffel[80];
assert(self);
pMe = (pLTC11Driv) 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:
LTC11Close(self);
iRet = LTC11Init(self);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
case EL734__FORCED_CLOSED:
case NOCONN:
iRet = LTC11Init(self);
if (iRet) {
return DEVREDO;
} else {
return DEVFAULT;
}
break;
/* fixable LTC11 Errors */
case MISERABLE:
case BADSTATE:
iRet = SerialNoReply(&(pMe->pData), "SCONT;");
LTC11Unlock(pMe);
return DEVREDO;
break;
case BADANSWER:
case BADCONFIRM:
case TIMEOUT:
return DEVREDO;
break;
default:
return DEVFAULT;
break;
}
return DEVFAULT;
}
/*------------------------------------------------------------------------*/
void KillLTC11(void *pData)
{
pLTC11Driv pMe = NULL;
pMe = (pLTC11Driv) pData;
assert(pMe);
if (pMe->pHost) {
free(pMe->pHost);
}
free(pMe);
}
/*------------------------------------------------------------------------*/
pEVDriver CreateLTC11Driver(int argc, char *argv[])
{
pEVDriver pNew = NULL;
pLTC11Driv pSim = NULL;
/* check for arguments */
if (argc < 3) {
return NULL;
}
pNew = CreateEVDriver(argc, argv);
pSim = (pLTC11Driv) malloc(sizeof(LTC11Driv));
memset(pSim, 0, sizeof(LTC11Driv));
if (!pNew || !pSim) {
return NULL;
}
pNew->pPrivate = pSim;
pNew->KillPrivate = KillLTC11;
/* initalise LTC11Driver */
pSim->iLastError = 0;
pSim->pHost = strdup(argv[0]);
pSim->iPort = atoi(argv[1]);
pSim->iChannel = atoi(argv[2]);
/* initialise function pointers */
pNew->SetValue = LTC11Run;
pNew->GetValue = LTC11Get;
pNew->Send = LTC11Send;
pNew->GetError = LTC11Error;
pNew->TryFixIt = LTC11Fix;
pNew->Init = LTC11Init;
pNew->Close = LTC11Close;
return pNew;
}
/*------------------------------------------------------------------------*/
static int LTC11AssignControl(pEVDriver pEva, int iMode, int iSensor)
{
pLTC11Driv self = NULL;
int iRet, iRead = 0;
char pBueffel[80], pCommand[50];
self = (pLTC11Driv) pEva->pPrivate;
assert(self);
assert((iMode == HEATER) || (iMode == ANALOG));
if (!self->pData) {
self->iLastError = NOCONN;
return 0;
}
sprintf(pCommand, "SOSEN %d,%d;", iMode, iSensor);
iRet = SerialNoReply(&(self->pData), pCommand);
if (iRet != 1) {
self->iLastError = iRet;
return 0;
}
sprintf(pCommand, "QOUT?%d;", iMode);
iRet = SerialWriteRead(&(self->pData), pCommand, pBueffel, 79);
LTC11Unlock(self);
if (strcmp(pBueffel, "?TMO") == 0) {
self->iLastError = TIMEOUT;
return 0;
}
sscanf(pBueffel, "%d;", &iRead);
if (iRead != iSensor) {
self->iLastError = BADCONFIRM;
return 0;
}
if (iMode == ANALOG) {
self->iControlAnalog = iSensor;
} else {
self->iControlHeat = iSensor;
}
/* switch back to control mode */
SerialNoReply(&(self->pData), "SCONT;");
return 1;
}
/*--------------------------------------------------------------------------
handle LTC11 specific commands:
- sensor requests or sets read sensor
- mode requests or sets operation mode
- controlheat requests or sets sensor for heater control
- controlanalog requests or sets sensor for analog control
in all other cases fall back and call EVControllerWrapper to handle it or
eventually throw an error.
*/
int LTC11Action(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pEVControl self = NULL;
int iRet, iMode;
char pBueffel[256], pError[132];
pLTC11Driv pMe = NULL;
float fVal;
self = (pEVControl) pData;
assert(self);
pMe = (pLTC11Driv) self->pDriv->pPrivate;
assert(pMe);
if (argc > 1) {
strtolower(argv[1]);
/*------ sensor */
if (strcmp(argv[1], "sensor") == 0) {
if (argc > 2) { /* set case */
/* check permission */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iMode);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: needed integer, got %s", argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
pMe->iSensor = iMode;
SCSendOK(pCon);
return 1;
} else { /* get case */
sprintf(pBueffel, "%s.sensor = %d", argv[0], pMe->iSensor);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
/*------ controlanalog */
if (strcmp(argv[1], "controlanalog") == 0) {
if (argc > 2) { /* set case */
/* check permission */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iMode);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: needed integer, got %s", argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = LTC11AssignControl(self->pDriv, ANALOG, iMode);
if (iRet != 1) {
self->pDriv->GetError(self->pDriv, &iMode, pError, 131);
sprintf(pBueffel, "ERROR: failed to set sensor: %s", pError);
SCWrite(pCon, pBueffel, eError);
return 0;
}
SCSendOK(pCon);
return 1;
} else { /* get case */
sprintf(pBueffel, "%s.controlanalog = %d", argv[0],
pMe->iControlAnalog);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
/*------ controlheat */
if (strcmp(argv[1], "controlheat") == 0) {
if (argc > 2) { /* set case */
/* check permission */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iMode);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: needed integer, got %s", argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = LTC11AssignControl(self->pDriv, HEATER, iMode);
if (iRet != 1) {
self->pDriv->GetError(self->pDriv, &iMode, pError, 131);
sprintf(pBueffel, "ERROR: failed to set sensor: %s", pError);
SCWrite(pCon, pBueffel, eError);
return 0;
}
SCSendOK(pCon);
return 1;
} else { /* get case */
sprintf(pBueffel, "%s.controlheat = %d", argv[0],
pMe->iControlHeat);
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
/*-------- mode */
else if (strcmp(argv[1], "mode") == 0) {
if (argc > 2) { /* set case */
/* check permission */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iMode);
if (iRet != TCL_OK) {
sprintf(pBueffel, "ERROR: needed integer, got %s", argv[2]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
iRet = LTC11SetMode(self->pDriv, iMode);
if (iRet != 1) {
self->pDriv->GetError(self->pDriv, &iMode, pError, 131);
sprintf(pBueffel, "ERROR: failed to set mode %s", pError);
SCWrite(pCon, pBueffel, eError);
return 0;
} else {
SCSendOK(pCon);
return 1;
}
} else { /* get case */
iRet = LTC11GetMode(self->pDriv, &iMode);
if (iRet != 1) {
self->pDriv->GetError(self->pDriv, &iMode, pError, 131);
sprintf(pBueffel, "ERROR: failed to get mode %s", pError);
SCWrite(pCon, pBueffel, eError);
return 0;
}
if (iMode == ANALOG) {
sprintf(pBueffel, "%s.mode = Analog Control", argv[0]);
} else {
sprintf(pBueffel, "%s.mode = Heater Control", argv[0]);
}
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 */
sprintf(pBueffel, "%s.sensor = %d", argv[0], pMe->iSensor);
SCWrite(pCon, pBueffel, eValue);
sprintf(pBueffel, "%s.controlanalog = %d", argv[0],
pMe->iControlAnalog);
SCWrite(pCon, pBueffel, eValue);
sprintf(pBueffel, "%s.controlheat = %d", argv[0], pMe->iControlHeat);
SCWrite(pCon, pBueffel, eValue);
iRet = LTC11GetMode(self->pDriv, &iMode);
if (iRet != 1) {
self->pDriv->GetError(self->pDriv, &iMode, pError, 131);
sprintf(pBueffel, "ERROR: failed to get mode %s", pError);
SCWrite(pCon, pBueffel, eError);
}
if (iMode == ANALOG) {
sprintf(pBueffel, "%s.mode = Analog Control", argv[0]);
} else {
sprintf(pBueffel, "%s.mode = Heater Control", argv[0]);
}
SCWrite(pCon, pBueffel, eValue);
return 1;
} else {
return EVControlWrapper(pCon, pSics, pData, argc, argv);
}
}
return EVControlWrapper(pCon, pSics, pData, argc, argv);
}