605 lines
16 KiB
C
605 lines
16 KiB
C
/*--------------------------------------------------------------------------
|
|
W E S T 4 1 0 0 D R I V
|
|
|
|
This file contains the implementation of a driver for the
|
|
Lakeshore 340 Temperature controller.
|
|
|
|
|
|
Mark Koennecke, Juli 1997
|
|
Mark Lesha, January 2006 (based on ITC4 code)
|
|
Paul Barron, January 2008 (Note: This is based on the old LAKESHORE340 code and
|
|
not the new LS340 code written by Rodney Davies Feb 08)
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <fortify.h>
|
|
#include <conman.h>
|
|
#include <servlog.h>
|
|
#include <fortify.h>
|
|
|
|
typedef struct __EVDriver *pEVDriver;
|
|
|
|
#include <evdriver.i>
|
|
/* Do we need these ?
|
|
#include <sics.h>
|
|
#include <modriv.h>
|
|
*/
|
|
#include <rs232controller.h>
|
|
#include "hardsup/west4100util.h"
|
|
#include "hardsup/el734_def.h"
|
|
#include "hardsup/el734fix.h"
|
|
|
|
#define SHITTYVALUE -777
|
|
/*------------------------- The Driver ------------------------------------*/
|
|
|
|
pEVDriver CreateWEST4100Driver(int argc, char *argv[]);
|
|
int ConfigWEST4100(pEVDriver self);
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
typedef struct {
|
|
pWEST4100 pData;
|
|
char *pHost;
|
|
int iPort;
|
|
int iChannel;
|
|
int iAddress;
|
|
int iNumSensors;
|
|
char iSensorList[10];
|
|
char iControlSensor[10];
|
|
int iTransaction;
|
|
int iProcessValue;
|
|
int iSetpoint;
|
|
int iWorkingSetpoint;
|
|
int iAlarm1;
|
|
int iAlarm2;
|
|
int iPowerLimit;
|
|
int iRampRate;
|
|
int iTmo;
|
|
int iLastError;
|
|
} WEST4100Driv, *pWEST4100Driv;
|
|
/*----------------------------------------------------------------------------*/
|
|
static int GetWEST4100Pos(pEVDriver self, float *fPos)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv)self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet = WEST4100_Read(&pMe->pData,fPos);
|
|
if(iRet <= 0 )
|
|
{
|
|
pMe->iLastError = iRet;
|
|
return 0;
|
|
}
|
|
if( (*fPos < 0) || (*fPos > 10000) )
|
|
{
|
|
*fPos = -999.;
|
|
pMe->iLastError = SHITTYVALUE;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------------*/
|
|
static int WEST4100Run(pEVDriver self, float fVal)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet = WEST4100_Set(&pMe->pData,fVal);
|
|
if(iRet != 1)
|
|
{
|
|
pMe->iLastError = iRet;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int WEST4100Error(pEVDriver self, int *iCode, char *error, int iErrLen)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv)self->pPrivate;
|
|
assert(pMe);
|
|
|
|
*iCode = pMe->iLastError;
|
|
if(pMe->iLastError == SHITTYVALUE)
|
|
{
|
|
strncpy(error,"Invalid temperature returned from WEST4100, check sensor",iErrLen);
|
|
}
|
|
else
|
|
{
|
|
WEST4100_ErrorTxt(&pMe->pData,pMe->iLastError,error,iErrLen);
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int WEST4100Send(pEVDriver self, char *pCommand, char *pReply, int iLen)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet = WEST4100_Send(&pMe->pData,pCommand, pReply,iLen);
|
|
if(iRet <= 0)
|
|
{
|
|
pMe->iLastError = iRet;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int WEST4100Init(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
pMe->pData = NULL;
|
|
iRet = WEST4100_Open(&pMe->pData, pMe->pHost, pMe->iAddress, pMe->iTransaction);
|
|
if(iRet != 1)
|
|
{
|
|
if(iRet == WEST4100__NOWEST4100)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
pMe->iLastError = iRet;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int WEST4100Close(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
//int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Close(&pMe->pData);
|
|
return 1;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static int WEST4100Fix(pEVDriver self, int iError)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )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:
|
|
WEST4100Close(self);
|
|
iRet = WEST4100Init(self);
|
|
if(iRet)
|
|
{
|
|
return DEVREDO;
|
|
}
|
|
else
|
|
{
|
|
return DEVFAULT;
|
|
}
|
|
break;
|
|
/* handable protocoll errors */
|
|
case EL734__BAD_TMO:
|
|
return DEVREDO;
|
|
break;
|
|
case -501: /* Bad_COM */
|
|
return DEVREDO;
|
|
case -504: /* Badly formatted */
|
|
return DEVREDO;
|
|
default:
|
|
return DEVFAULT;
|
|
break;
|
|
}
|
|
return DEVFAULT;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
#if 0
|
|
static int WEST4100Halt(pEVDriver *self)
|
|
{
|
|
assert(self);
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
/*------------------------------------------------------------------------*/
|
|
void KillWEST4100(void *pData)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
|
|
pMe = (pWEST4100Driv)pData;
|
|
assert(pMe);
|
|
|
|
if(pMe->pHost)
|
|
{
|
|
free(pMe->pHost);
|
|
}
|
|
free(pMe);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
pEVDriver CreateWEST4100Driver(int argc, char *argv[])
|
|
{
|
|
pEVDriver pNew = NULL;
|
|
pWEST4100Driv pSim = NULL;
|
|
|
|
/* check for arguments */
|
|
if(argc < 3)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pSim = (pWEST4100Driv)malloc(sizeof(WEST4100Driv));
|
|
if(!pSim) {
|
|
return NULL;
|
|
}
|
|
pNew = CreateEVDriver(argc,argv);
|
|
if(!pNew) {
|
|
free(pSim);
|
|
return NULL;
|
|
}
|
|
memset(pSim,0,sizeof(WEST4100Driv));
|
|
pNew->pPrivate = pSim;
|
|
pNew->KillPrivate = KillWEST4100;
|
|
|
|
/* initalise pWEST4100Driver */
|
|
// This is where parameters are initialised using values from the configuration file eg. sertemp 1 2
|
|
pSim->iAddress = atoi(argv[1]);
|
|
pSim->iTransaction = atoi(argv[2]);
|
|
pSim->iLastError = 0;
|
|
pSim->iTmo = 10;
|
|
|
|
pSim->pHost = strdup(argv[0]);
|
|
pSim->iPort = 0;
|
|
pSim->iChannel = 0;
|
|
|
|
|
|
/* initialise function pointers */
|
|
pNew->SetValue = WEST4100Run;
|
|
pNew->GetValue = GetWEST4100Pos;
|
|
pNew->Send = WEST4100Send;
|
|
pNew->GetError = WEST4100Error;
|
|
pNew->TryFixIt = WEST4100Fix;
|
|
pNew->Init = WEST4100Init;
|
|
pNew->Close = WEST4100Close;
|
|
|
|
return pNew;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int ConfigWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet = WEST4100_Config(&pMe->pData, pMe->iTmo, pMe->iAddress,pMe->iTransaction);
|
|
if(iRet < 0)
|
|
{
|
|
pMe->iLastError = iRet;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int WEST4100Query(pEVDriver self, int parameterAddress, int *parameterValue)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
// int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
if((parameterAddress>0 && parameterAddress<=35) || (parameterAddress>=122 && parameterAddress<=133))
|
|
return WEST4100_Query(&pMe->pData, parameterAddress, parameterValue);
|
|
else
|
|
printf("Parameter %d out of range.\n",parameterAddress);
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int WEST4100Write(pEVDriver self, int parameterAddress, int parameterValue)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
// int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
if((parameterAddress>0 && parameterAddress<=35) || (parameterAddress>=122 && parameterAddress<=133))
|
|
return WEST4100_Write(&pMe->pData, parameterAddress, parameterValue);
|
|
else
|
|
printf("Parameter %d out of range.\n",parameterAddress);
|
|
|
|
return 0;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetAddressWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
// int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
return pMe->iAddress;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetTransactWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
// int iRet;
|
|
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
return pMe->iTransaction;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetProcessValueWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 1, &fVal);
|
|
|
|
pMe->iProcessValue = fVal;
|
|
|
|
return pMe->iProcessValue;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetWorkingSetpointWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 21, &fVal);
|
|
|
|
pMe->iWorkingSetpoint = fVal;
|
|
|
|
return pMe->iWorkingSetpoint;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int SetSetpointWEST4100(pEVDriver self, int Setpoint)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet=WEST4100_Write(&pMe->pData, 2, Setpoint);
|
|
|
|
pMe->iSetpoint = Setpoint;
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetSetpointWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 2, &fVal);
|
|
|
|
pMe->iSetpoint = fVal;
|
|
|
|
return pMe->iSetpoint;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int SetRampRateWEST4100(pEVDriver self, int RampRate)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet=WEST4100_Write(&pMe->pData, 24, RampRate);
|
|
|
|
pMe->iRampRate = RampRate;
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetRampRateWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 24, &fVal);
|
|
|
|
pMe->iRampRate = fVal;
|
|
|
|
return pMe->iRampRate;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int SetAlarm1WEST4100(pEVDriver self, int Alarm1)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet=WEST4100_Write(&pMe->pData, 13, Alarm1);
|
|
|
|
pMe->iAlarm1 = Alarm1;
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetAlarm1WEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 13, &fVal);
|
|
|
|
pMe->iAlarm1 = fVal;
|
|
|
|
return pMe->iAlarm1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int SetAlarm2WEST4100(pEVDriver self, int Alarm2)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet=WEST4100_Write(&pMe->pData, 14, Alarm2);
|
|
|
|
pMe->iAlarm2 = Alarm2;
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetAlarm2WEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 14, &fVal);
|
|
|
|
pMe->iAlarm2 = fVal;
|
|
|
|
return pMe->iAlarm2;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int SetPowerLimitWEST4100(pEVDriver self, int PowerLimit)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
iRet=WEST4100_Write(&pMe->pData, 20, PowerLimit);
|
|
|
|
pMe->iPowerLimit = PowerLimit;
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetPowerLimitWEST4100(pEVDriver self)
|
|
{
|
|
pWEST4100Driv pMe = NULL;
|
|
int fVal;
|
|
|
|
assert(self);
|
|
pMe = (pWEST4100Driv )self->pPrivate;
|
|
assert(pMe);
|
|
|
|
WEST4100_Query(&pMe->pData, 20, &fVal);
|
|
|
|
pMe->iPowerLimit = fVal;
|
|
|
|
return pMe->iPowerLimit;
|
|
}
|