Add NHQ200 HV Power Supply Driver

r1385 | dcl | 2006-12-21 17:50:19 +1100 (Thu, 21 Dec 2006) | 2 lines
This commit is contained in:
Douglas Clowes
2006-12-21 17:50:19 +11:00
parent 5c550dd169
commit a488705540
8 changed files with 1481 additions and 2 deletions

View File

@@ -70,6 +70,7 @@ OBJ= site_ansto.o anstoutil.o\
motor_asim.o motor_dmc2280.o\
lh45.o lh45driv.o \
lakeshore340.o lakeshore340driv.o \
nhq200.o nhq200driv.o \
counterdriv.o\
../psi/tcpdocho.o ../psi/tcpdornier.o \
anstohttp.o \

View File

@@ -10,7 +10,7 @@ SRC = .
CC = gcc
CFLAGS = -g -DLINUX $(DFORTIFY) -I$(SRC) -I../..
HOBJ= serialsinq.o itc4util.o lh45util.o lakeshore340util.o asynsrv_utility.o geterrno.o strjoin.o
HOBJ= serialsinq.o nhq200util.o itc4util.o lh45util.o lakeshore340util.o asynsrv_utility.o geterrno.o strjoin.o
libhlib.a: $(HOBJ)
rm -f libhlib.a

View File

@@ -0,0 +1,511 @@
/*--------------------------------------------------------------------------
N H Q 2 0 0 U T I L
A few utility functions for dealing with a NHQ200 voltage controller
within the SINQ setup: host -- TCP/IP -- MAC --- RS-232.
Mark Koennecke, Juli 1997
Mark Lesha, January 2006 (based on ITC4 code)
Douglas Clowes, December 2006 (based on LAKESHORE340 code)
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 <stdio.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <fortify.h>
#include <sics.h>
#include <modriv.h>
#include <rs232controller.h>
#include "serialsinq.h"
#include "nhq200util.h"
/* -------------------------------------------------------------------------*/
static int writeNHQ200(prs232 rs232, void *data, int dataLen)
{
int i, iRet;
char reply[1];
int replyLen;
char* request = (char *) data;
char crlf[3] = {0x0D, 0x0A, 0x00};
do {
for (i = 0; i < dataLen; ++i)
{
iRet = NETWrite(rs232->pSock, request + i, 1);
if (iRet <= 0)
{
return BADSEND;
}
replyLen = 1;
iRet = readRS232(rs232, reply, &replyLen);
if(iRet == 0)
{
return TIMEOUT;
}
else if(iRet == -1)
{
return INCOMPLETE;
}
if (replyLen != 1)
printf("replyLen = %d, expected 1\n", replyLen);
else if (reply[0] != request[i])
printf("reply[%d] = %x, expected %x\n", i, reply[i], request[i]);
else
printf("reply[%d] = %x, sent %x\n", i, reply[i], request[i]);
}
if (request == crlf)
break;
if (dataLen >= 2 && memcmp(request + dataLen - 2, crlf, 2) == 0)
break;
request = crlf;
dataLen = 2;
} while (1);
return 1;
}
/*------------------------------------------------------------------------*/
int transactNHQ200(prs232 self, void *send, int sendLen,
void *reply, int replyLen)
{
int iRet, len;
assert(self);
/*
if there is still data on the socket: clear it
*/
while(availableRS232(self)){
len = replyLen;
readRS232(self,reply,&len);
}
/*
write data
*/
iRet = writeNHQ200(self,send,sendLen);
if(iRet <= 0)
{
return BADSEND;
}
/*
read
*/
memset(reply,0,replyLen);
iRet = NETReadTillTerm(self->pSock,self->timeout,self->replyTerminator,
reply, replyLen);
if(self->debug > 0)
{
if(iRet > 0)
{
printf("RS232 IN/TRANS: %s",(char *)reply);
if(strchr((char *)reply,'\n') == NULL)
{
puts("");
}
fflush(stdout);
}
else if(iRet == 0)
{
printf("RS232 IN/TRANS: TIMEOUT\n");
}
else
{
printf("RS232 IN/TRANS/INCOMPLETE: %s",(char *)reply);
}
}
if(iRet == 0)
{
return TIMEOUT;
}
else if(iRet == -1)
{
return INCOMPLETE;
}
else
{
return iRet;
}
}
/*------------------------------------------------------------------------*/
int NHQ200_Check_Status(pNHQ200 self)
/* Can be called to check for correct operation of the NHQ200 */
{
int iRet, iRetry, busy, notbusy;
char pCommand[20];
char pReply[132];
/* Check the busy status. */
/* While busy, wait but not too long - set an upper limit of about 100 queries, */
/* should translate to about 1 or 2 seconds which is enough time for any commands */
/* to complete. Since we don't issue any time-consuming commands, this shouldn't */
/* be necessary anyway. */
/* Register a comms failure if a not-busy response isn't able to be received. */
iRetry=0;
printf("Checking status...");
do
{
sprintf(pCommand,"S1");
usleep(50000); // Required to meet Lakeshore340 spec.
if ((iRet=transactNHQ200(self->controller,pCommand,strlen(pCommand),pReply,79))<=0)
{
printf("Comms error!\n");
return iRet; // Comms problem
}
busy=(strncmp(pReply,"S1=ON",15)!=0);
notbusy=!busy;
if (notbusy)
{
printf("Status OK.\n");
return 1; // Lakeshore 340 is ready to accept command
}
} while((++iRetry<100)&&busy);
/* If we fell out of the loop, the Lakeshore 340 is either still busy */
/* or some bad response was received, log the response. */
sprintf(self->pAns,"BUSY response=%s",pReply);
printf("Busy or bad response received!\n");
return NHQ200__BADREAD;
}
static
int NHQ200_ConfigureAndQueryGen(pNHQ200 self, char *command,
char *configandqueryparameters, char *configonlyparameters,char *diagnosis)
/* Issue a command to the Lakeshore 340, if this works, */
/* issue the corresponding query and check the result is correct. */
/* Log and return any errors. */
{
int iRet;
char pCommand[20];
char pReply[132];
/* Issue a command to the Lakeshore 340. */
if (configandqueryparameters&&*configandqueryparameters)
sprintf(pCommand,"%s %s,%s",command,configandqueryparameters,configonlyparameters);
else
sprintf(pCommand,"%s %s",command,configonlyparameters);
printf("Issuing command: '%s'...\n",pCommand);
usleep(50000); // Required to meet Lakeshore340 spec.
if ((iRet=writeNHQ200(self->controller,pCommand,strlen(pCommand)))!=1)
return iRet;
/* Issue the query corresponding to the command, */
/* then check the parameters match what was set. */
if (configandqueryparameters&&*configandqueryparameters)
sprintf(pCommand,"%s? %s",command,configandqueryparameters);
else
sprintf(pCommand,"%s?",command);
printf("Issuing query: '%s'...\n",pCommand);
usleep(50000); // Required to meet Lakeshore340 spec.
if ((iRet=transactNHQ200(self->controller,pCommand,strlen(pCommand),pReply,79))<=0)
{
printf("transactNHQ200 error! Code=%d.\n",iRet);
printf("DEBUG: pReply='%s' len=%d configonlyparameters='%s' len=%d\n",
pReply,strlen(pReply),configonlyparameters,strlen(configonlyparameters));
return iRet;
}
/* Query should return the same data parameters set in the configuration
(i.e. the configonlyparameters), the configandqueryparameters are used
to index objects and are common to both configuration and query. */
printf("DEBUG: pReply='%s' len=%d configonlyparameters='%s' len=%d\n",
pReply,strlen(pReply),configonlyparameters,strlen(configonlyparameters));
if (strcmp(pReply,configonlyparameters)!=0)
{
printf("Response was bad.\n");
if (diagnosis&&*diagnosis)
sprintf(self->pAns,"%s response=%s (%s.)",command,pReply,diagnosis);
else
sprintf(self->pAns,"%s response=%s",command,pReply);
return NHQ200__BADREAD;
}
printf("Response was good.\n");
return 1;
}
static
int NHQ200_ConfigureAndQuery(pNHQ200 self, char *command,
char *parameters, char *diagnosis)
/* Use for config/query transactions that don't require index parameters in the query. */
{
return NHQ200_ConfigureAndQueryGen(self,command,"",parameters,diagnosis);
}
static
int NHQ200_SetControl(pNHQ200 self, int iControl)
{
}
static
int NHQ200_Setup(pNHQ200 self, int iControl) /* Operations common to both Open and Config functions */
{
int iRet;
char pCommand[20];
char pReply[132];
/* MJL enable RS232 debugging mode. */
setRS232Debug(self->controller,1);
printf("***RS232 debug mode enabled for NHQ200***\n");fflush(stdout);
int sock = self->controller->pSock->sockid;
int flag = 1;
int result = setsockopt(sock, /* socket affected */
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
(char *) &flag, /* the cast is historical cruft */
sizeof(int)); /* length of option value */
if (result < 0)
return NHQ200__BADCOM;
return 1; /* Success */
}
int NHQ200_Open(pNHQ200 *pData, char *pRS232, int iSensor, int iCTRL, int iMode)
{
pNHQ200 self = NULL;
self = (pNHQ200)malloc(sizeof(NHQ200));
if(self == NULL)
{
return NHQ200__BADMALLOC;
}
*pData = self;
self->iControl = iCTRL;
self->iRead = iSensor;
self->iReadOnly = iMode;
/* The NHQ200 doesn't require divisors or multipliers
and they are always forced to 1.0 */
self->fDiv = 1.0;
self->fMult = 1.0;
self->controller = NULL;
self->controller = (prs232)FindCommandData(pServ->pSics,pRS232,
"RS232 Controller");
if(!self->controller){
/*SCWrite(pCon,"ERROR: motor controller not found",eError); */
return NHQ200__BADCOM;
}
if(!self->iReadOnly)
return NHQ200_Setup(self, self->iControl);
}
/*--------------------------------------------------------------------------*/
void NHQ200_Close(pNHQ200 *pData)
{
pNHQ200 self;
self = *pData;
if (!self)
return; // Just in case
/* Try to turn off the heater as a precaution.
*/
/* switch off remote operation */
/* Not sure if this is really necessary but do it just in case */
/*
*/
return;
}
/*--------------------------------------------------------------------------*/
int NHQ200_Config(pNHQ200 *pData, int iTmo, int iRead, int iControl,
float fDiv,float fMult)
{
pNHQ200 self;
self = *pData;
return NHQ200_Setup(self, iControl);
}
/* --------------------------------------------------------------------------*/
int NHQ200_Send(pNHQ200 *pData, char *pCommand, char *pReply, int iLen)
{
int iRet,i,commandlen,isquery;
pNHQ200 self;
self = *pData;
/* Send command direct to the NHQ200 */
commandlen=strlen(pCommand);
usleep(50000); // Required to meet Lakeshore340 spec.
iRet=transactNHQ200(self->controller,pCommand,commandlen,pReply,iLen);
return iRet;
}
/*--------------------------------------------------------------------------*/
int NHQ200_Read(pNHQ200 *pData, float *fVal)
{
char pCommand[20], pReply[132];
int iRet;
float fRead = -9999999.;
pNHQ200 self;
self = *pData;
/* for the NHQ200 there are three temp measurements available */
/* as 'A', 'B', 'C' and 'D'. (This is a bit different from the manual) */
/* We use the Kelvin readings (presumably the cryogenic 'furnace' */
/* operates at low temperatures, so it probably makes more sense) */
switch(self->iRead)
{
case 1:
sprintf(pCommand,"U1");
break;
case 2:
sprintf(pCommand,"U2");
break;
default:
return NHQ200__BADPAR; // But shouldn't happen
}
usleep(50000); // Required to meet Lakeshore340 spec.
iRet = transactNHQ200(self->controller,pCommand,strlen(pCommand),pReply,79);
if (iRet <= 0)
return iRet;
iRet = sscanf(pReply,"%g",&fRead);
if(iRet != 1) // Not a number, probably an error response
{
return NHQ200__BADREAD;
}
*fVal = fRead;
return iRet;
}
/* -------------------------------------------------------------------------*/
int NHQ200_Set(pNHQ200 *pData, float fVal)
{
char pCommand[20], pCommandRead[20], pReply[132], pCommandGo[20];
int iRet, i;
const float fPrecision = 0.1;
float fDelta, fRead;
pNHQ200 self;
self = *pData;
if(self->iReadOnly)
{
return NHQ200__READONLY;
}
/* Note we are using control loop #1 only for temperature control. */
sprintf(pCommand,"D%d=%d", self->iControl, (int) fVal);
sprintf(pCommandRead,"D%d", self->iControl); // To read back and check the set value
/* try three times: send, read, test, if OK return, else resend. */
/* MJL doesn't think this is necessary... left over from itc4 */
for(i = 0; i < 3; i++)
{
/* send Dn=nnn command, we get a blank line response */
usleep(50000); // Required to meet Lakeshore340 spec.
if ((iRet=transactNHQ200(self->controller,pCommand,strlen(pCommand),pReply,131))<=0)
return iRet;
/* read the set value again using the Dn command */
usleep(50000); // Required to meet Lakeshore340 spec.
if ((iRet=transactNHQ200(self->controller,pCommandRead,strlen(pCommandRead),pReply,131))<=0)
return iRet;
printf("Dn: Response %d characters: '%s'\n",iRet,pReply);
if(pReply[0] == '-'&&strlen(pReply)>7)
{
strcpy(self->pAns,pReply);
return NHQ200__BADCOM;
}
/* Convert the value read back. */
/* Note SETP? will return free-format exponentiated number, so use %g. */
if(sscanf(pReply,"%g",&fRead)!=1)
return NHQ200__BADREAD;
printf(" Parsed response OK, value=%g\n",fRead);
/* check the value read back */
printf(" Setpoint=%g actual=%g\n",fVal,fRead);
fDelta = fRead - fVal;
if(fDelta < 0)
fDelta = -fDelta;
printf(" delta=%g precision=%g\n",fDelta,fPrecision);
if(fDelta < fPrecision)
{
/* Success, but check the NHQ200 operating status afterwards, and return */
/* Don't bother to repeat the write if we get an error here as it would indicate
a fault or overload in the NHQ200, not a comms problem */
sprintf(pCommandGo, "G%d", self->iControl);
if ((iRet=transactNHQ200(self->controller,pCommandGo,strlen(pCommandGo),pReply,131))<=0)
return iRet;
printf("SET OK, checking status and returning.\n");
return 1;
}
}
printf("SETP failed!\n");
return NHQ200__BADSET;
}
/* -------------------------------------------------------------------------*/
void NHQ200_ErrorTxt(pNHQ200 *pData,int iCode, char *pError, int iLen)
{
char pBueffel[512];
pNHQ200 self;
self = *pData;
switch(iCode)
{
case NHQ200__BADCOM:
sprintf(pBueffel,"NHQ200: Invalid command or offline, got %s",
self->pAns);
strncpy(pError,pBueffel,iLen);
break;
case NHQ200__BADPAR:
strncpy(pError,"NHQ200: Invalid parameter specified",iLen);
break;
case NHQ200__BADMALLOC:
strncpy(pError,"NHQ200: Error allocating memory in NHQ200",iLen);
break;
case NHQ200__BADREAD:
strncpy(pError,"NHQ200: Badly formatted answer",iLen);
break;
case NHQ200__BADSET:
strncpy(pError,"NHQ200: Failed three times to write new set value to NHQ200",iLen);
break;
case NHQ200__FAULT: // Covers various NHQ200 self-diagnosed fault conditions
sprintf(pBueffel,"NHQ200: Internal fault condition detected: %s",self->pAns);
strncpy(pError,pBueffel,iLen);
break;
case NHQ200__NONHQ200:
sprintf(pBueffel,"NHQ200: Wrong model number (driver is for Model 340 only): %s",self->pAns);
strncpy(pError,pBueffel,iLen);
break;
default:
SerialError(iCode, pError,iLen);
break;
}
}

View File

@@ -0,0 +1,131 @@
/*---------------------------------------------------------------------------
N H Q 2 0 0 U T I L
A few utility functions for talking to a NHQ 200
voltage controller via the SINQ setup: TCP/IP--MAC--RS-232--
NHQ200.
Mark Koennecke, Juli 1997
Mark Lesha, January 2006 (based on ITC4 code)
Douglas Clowes, December 2006 (based on LAKESHORE340 code)
----------------------------------------------------------------------------*/
#ifndef SINQNHQ200
#define SINQNHQ200
/*----------------------- ERRORCODES--------------------------------------
Most functions return a negative error code on failure. Error codes
defined are those defined for serialsinq plus a few additional ones:
*/
#define NHQ200__BADCOM -501
/* command not recognized */
#define NHQ200__BADPAR -502
/* bad parameter to command */
#define NHQ200__BADMALLOC -503
/* error allocating memory */
#define NHQ200__BADREAD -504
/* error analysing command string on Read */
#define NHQ200__FAULT -505
/* fault or overload condition exists in NHQ200 */
#define NHQ200__NONHQ200 -510
/* Controller is not NHQ200 */
#define NHQ200__BADSET -530
/* failed three times to set temperature */
#define NHQ200__READONLY -531
/*------------------------------------------------------------------------*/
typedef struct __NHQ200 {
int iRead;
int iControl;
void *pData;
char pAns[80]; /* should be enough for NHQ200 errors */
/* The NHQ200 does not need multipliers or dividers but
leave them in anyway for back compatibility or future use
but force the value to 1.0 all the time */
float fDiv;
float fMult;
int iReadOnly;
prs232 controller;
} NHQ200;
typedef struct __NHQ200 *pNHQ200;
/*-----------------------------------------------------------------------*/
int NHQ200_Open(pNHQ200 *pData,char *pHost, int iPort, int iChannel, int iMode);
/***** creates an NHQ200 datastructure and opens a connection to the NHQ200
controller. Input Parameters are:
the hostname
the port number
the RS-232 channel number on the Mac.
iMode: 1 for ReadOnly, 0 for normal mode
Return values are 1 for success, a negative error code on
failure.
*/
void NHQ200_Close(pNHQ200 *pData);
/****** close a connection to an NHQ200controller and frees its
data structure. The only parameter is a pointer to the data
structure for this controller. This pointer will be invalid after
this call.
*/
int NHQ200_Config(pNHQ200 *pData, int iTmo, int iRead,
int iControl, float fDiv, float fMult);
/***** configure some aspects of a NHQ200temperature controller.
The parameter are:
- a pointer to the data structure for the controller as
returned by NHQ200_Open
- a value for the connection timeout
- the temperature sensor to use for reading the
temperature.
- the temperature sensor used by the NHQ200controller
for regulating the temperature.
- the divisor needed to calculate the real temperature
from the sensor.
The function returns 1 on success, a negative error code on
failure.
*/
int NHQ200_Send(pNHQ200 *pData, char *pCommand, char *pReply, int iLen);
/******* send a the command in pCommand to the NHQ200controller.
A possible reply is returned in the buffer pReply.
Maximum iLen characters are copied to pReply.
The first parameter is a pointer to a NHQ200data structure
as returned by NHQ200_Open.
Return values are 1 for success, a negative error code on
failure.
*/
int NHQ200_Read(pNHQ200 *pData, float *fVal);
/******* reads the current actual temperature of the sensor
configured by ConfigNHQ200for reading. The value is returned
in fVal. The first parameter is a pointer to a NHQ200
data structure as returned by NHQ200_Open.
Return values are 1 for success, a negative error code on
failure.
*/
int NHQ200_Set(pNHQ200 *pData, float fVal);
/****** sets a new preset temperature in the NHQ200temperature
controller. Parameters are:
- a pointer to a NHQ200data structure as returned by NHQ200_Open.
- the new preset value.
Return values are 1 for success, a negative error code on
failure.
*/
void NHQ200_ErrorTxt(pNHQ200 *pData, int iCode, char *pError, int iLen);
/******* translates one of the negative error NHQ200error codes
into text. Maximum iLen bytes will be copied to the
buffer pError;
*/
#endif

285
site_ansto/nhq200.c Normal file
View File

@@ -0,0 +1,285 @@
/*---------------------------------------------------------------------------
N H Q 2 0 0
This is the implementation for a NHQ200 object derived from a more general
environment controller.
Mark Koennecke, August 1997
Mark Lesha, January 2006 (based on ITC4 code)
Douglas Clowes, December 2006 (based on LAKESHORE340 code)
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 <assert.h>
#include <tcl.h>
#include <fortify.h>
#include <sics.h>
#include <splitter.h>
#include <obpar.h>
#include <devexec.h>
#include <nserver.h>
#include <interrupt.h>
#include <emon.h>
#include <evcontroller.h>
#include <evcontroller.i>
#include "nhq200.h"
/*---------------------------------------------------------------------------*/
int NHQ200SetPar(pEVControl self, char *name, float fNew, SConnection *pCon)
{
int iRet;
/* check authorisation */
if(!SCMatchRights(pCon,usUser))
{
SCWrite(pCon,"ERROR: you are not authorised to change this parameter",
eError);
return 0;
}
/* just catch those three names which we understand */
if(strcmp(name,"sensor") == 0)
{
iRet = SetSensorNHQ200(self->pDriv,(int)fNew);
if(!iRet)
{
SCWrite(pCon,"ERROR: value out of range",eError);
return 0;
}
iRet = ConfigNHQ200(self->pDriv);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: NHQ200 configuration failed! ",eError);
SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
else if(strcmp(name,"control") == 0)
{
iRet = SetControlNHQ200(self->pDriv,(int)fNew);
if(!iRet)
{
SCWrite(pCon,"ERROR: value out of range",eError);
return 0;
}
iRet = ConfigNHQ200(self->pDriv);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: NHQ200 configuration failed! ",eError);
SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
else if(strcmp(name,"timeout") == 0)
{
iRet = SetTMONHQ200(self->pDriv,(int)fNew);
if(!iRet)
{
SCWrite(pCon,"ERROR: value out of range",eError);
return 0;
}
iRet = ConfigNHQ200(self->pDriv);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: NHQ200 configuration failed! ",eError);
SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
/* Note divisors and multipliers will not be used with the NHQ200
but leave in for back compatibility */
else if(strcmp(name,"divisor") == 0)
{
iRet = SetDivisorNHQ200(self->pDriv,fNew);
if(!iRet)
{
SCWrite(pCon,"ERROR: value out of range",eError);
return 0;
}
iRet = ConfigNHQ200(self->pDriv);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: NHQ200 configuration failed! ",eError);
SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
else if(strcmp(name,"multiplicator") == 0)
{
iRet = SetMultNHQ200(self->pDriv,fNew);
if(!iRet)
{
SCWrite(pCon,"ERROR: value out of range",eError);
return 0;
}
iRet = ConfigNHQ200(self->pDriv);
if(iRet != 1)
{
SCWrite(pCon,"ERROR: NHQ200 configuration failed! ",eError);
SCWrite(pCon,"INFO: Probably comm problem, Retry!",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
else
return EVCSetPar(self,name,fNew,pCon);
}
/*--------------------------------------------------------------------------*/
int NHQ200GetPar(pEVControl self, char *name, float *fNew)
{
int iRet;
float fDiv;
/* just catch those two names which we understand */
if(strcmp(name,"sensor") == 0)
{
iRet = GetSensorNHQ200(self->pDriv);
*fNew = (float)iRet;
return 1;
}
else if(strcmp(name,"control") == 0)
{
iRet = GetControlNHQ200(self->pDriv);
*fNew = (float)iRet;
return 1;
}
else if(strcmp(name,"timeout") == 0)
{
iRet = GetTMONHQ200(self->pDriv);
*fNew = (float)iRet;
return 1;
}
else if(strcmp(name,"divisor") == 0)
{
fDiv = GetDivisorNHQ200(self->pDriv);
*fNew = fDiv;
return 1;
}
else if(strcmp(name,"multiplicator") == 0)
{
fDiv = GetMultNHQ200(self->pDriv);
*fNew = fDiv;
return 1;
}
else
return EVCGetPar(self,name,fNew);
}
/*---------------------------------------------------------------------------*/
int NHQ200List(pEVControl self, SConnection *pCon)
{
char pBueffel[132];
int iRet;
iRet = EVCList(self,pCon);
sprintf(pBueffel,"%s.sensor = %d\n",self->pName,
GetSensorNHQ200(self->pDriv));
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%s.control = %d\n",self->pName,
GetControlNHQ200(self->pDriv));
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%s.timeout = %d\n",self->pName,
GetTMONHQ200(self->pDriv));
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%s.divisor = %f\n",self->pName,
GetDivisorNHQ200(self->pDriv));
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%s.multiplicator = %f\n",self->pName,
GetMultNHQ200(self->pDriv));
SCWrite(pCon,pBueffel,eValue);
return iRet;
}
/*-------------------------------------------------------------------------*/
int NHQ200Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pEVControl self = NULL;
char pBueffel[256];
int iRet;
double fNum;
float fVal;
self = (pEVControl)pData;
assert(self);
assert(pCon);
assert(pSics);
if(argc < 2)
{
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}
strtolower(argv[1]);
if((strcmp(argv[1],"sensor") == 0) || (strcmp(argv[1],"control") == 0) ||
(strcmp(argv[1],"timeout") == 0) || (strcmp(argv[1],"divisor") == 0) ||
(strcmp(argv[1],"multiplicator") == 0) )
{
if(argc > 2) /* set case */
{
iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&fNum);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected number, got %s",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return NHQ200SetPar(self,argv[1],(float)fNum,pCon);
}
else /* get case */
{
iRet = NHQ200GetPar(self,argv[1],&fVal);
sprintf(pBueffel,"%s.%s = %f\n",self->pName,
argv[1],fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
else if(strcmp(argv[1],"list") == 0)
{
return NHQ200List(self,pCon);
}
else
{
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}
/* not reached */
return 0;
}

49
site_ansto/nhq200.h Normal file
View File

@@ -0,0 +1,49 @@
/*-------------------------------------------------------------------------
NHQ 200
Support for NHQ 200 Voltage controllers for SICS.
The meaning and working of the functions defined is as desribed for a
general environment controller.
Mark Koennecke, Juli 1997
Mark Lesha, January 2006 (based on ITC4 code)
Douglas Clowes, December 2006 (based on LAKESHORE340 code)
copyright: see implementation file.
-----------------------------------------------------------------------------*/
#ifndef SICSNHQ200
#define SICSNHQ200
/*------------------------- The Driver ------------------------------------*/
pEVDriver CreateNHQ200Driver(int argc, char *argv[]);
int ConfigNHQ200(pEVDriver self);
int SetSensorNHQ200(pEVDriver self, int iSensor);
int SetControlNHQ200(pEVDriver self, int iSensor);
int GetSensorNHQ200(pEVDriver self);
int GetControlNHQ200(pEVDriver self);
/* Divisors and multipliers should not be applicable to the NHQ200
since it uses floating point variables, but we leave the functions
in here anyway for the time being (setting will have no effect and
a value of 1.0 will always be returned. */
int SetDivisorNHQ200(pEVDriver self, float iSensor);
float GetDivisorNHQ200(pEVDriver self);
int SetMultNHQ200(pEVDriver self, float iSensor);
float GetMultNHQ200(pEVDriver self);
/* Leave in time-out functionality */
int SetTMONHQ200(pEVDriver self, int iSensor);
int GetTMONHQ200(pEVDriver self);
/*------------------------- The NHQ200 object ------------------------------*/
int NHQ200Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int NHQ200SetPar(pEVControl self, char *name, float fNew,
SConnection *pCon);
int NHQ200GetPar(pEVControl self, char *name, float *fVal);
int NHQ200List(pEVControl self, SConnection *pCon);
#endif

488
site_ansto/nhq200driv.c Normal file
View File

@@ -0,0 +1,488 @@
/*--------------------------------------------------------------------------
N H Q 2 0 0 D R I V
This file contains the implementation of a driver for the
NHQ 200 Voltage controller.
Mark Koennecke, Juli 1997
Mark Lesha, January 2006 (based on ITC4 code)
Douglas Clowes, December 2006 (based on LAKESHORE340 code)
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/nhq200util.h"
#include "hardsup/el734_def.h"
#include "hardsup/el734fix.h"
#define SHITTYVALUE -777
/*------------------------- The Driver ------------------------------------*/
pEVDriver CreateNHQ200Driver(int argc, char *argv[]);
int ConfigNHQ200(pEVDriver self);
/*-----------------------------------------------------------------------*/
typedef struct {
pNHQ200 pData;
char *pHost;
int iPort;
int iChannel;
int iControl; /* NHQ200 control */
float fDiv;
float fMult;
int iRead; /* NHQ200 sensor */
int iTmo;
int iLastError;
} NHQ200Driv, *pNHQ200Driv;
/*----------------------------------------------------------------------------*/
static int GetNHQ200Pos(pEVDriver self, float *fPos)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv)self->pPrivate;
assert(pMe);
iRet = NHQ200_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 NHQ200Run(pEVDriver self, float fVal)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
iRet = NHQ200_Set(&pMe->pData,fVal);
if(iRet != 1)
{
pMe->iLastError = iRet;
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int NHQ200Error(pEVDriver self, int *iCode, char *error, int iErrLen)
{
pNHQ200Driv pMe = NULL;
assert(self);
pMe = (pNHQ200Driv)self->pPrivate;
assert(pMe);
*iCode = pMe->iLastError;
if(pMe->iLastError == SHITTYVALUE)
{
strncpy(error,"Invalid temperature returned form NHQ200, check sensor",iErrLen);
}
else
{
NHQ200_ErrorTxt(&pMe->pData,pMe->iLastError,error,iErrLen);
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int NHQ200Send(pEVDriver self, char *pCommand, char *pReply, int iLen)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
iRet = NHQ200_Send(&pMe->pData,pCommand, pReply,iLen);
if(iRet <= 0)
{
pMe->iLastError = iRet;
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int NHQ200Init(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
pMe->pData = NULL;
iRet = NHQ200_Open(&pMe->pData, pMe->pHost, pMe->iRead, pMe->iControl,0);
if(iRet != 1)
{
if(iRet == NHQ200__NONHQ200)
{
return -1;
}
else
{
pMe->iLastError = iRet;
return 0;
}
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int NHQ200Close(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
NHQ200_Close(&pMe->pData);
return 1;
}
/*---------------------------------------------------------------------------*/
static int NHQ200Fix(pEVDriver self, int iError)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )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:
NHQ200Close(self);
iRet = NHQ200Init(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;
}
/*--------------------------------------------------------------------------*/
static int NHQ200Halt(pEVDriver *self)
{
assert(self);
return 1;
}
/*------------------------------------------------------------------------*/
void KillNHQ200(void *pData)
{
pNHQ200Driv pMe = NULL;
pMe = (pNHQ200Driv)pData;
assert(pMe);
if(pMe->pHost)
{
free(pMe->pHost);
}
free(pMe);
}
/*------------------------------------------------------------------------*/
pEVDriver CreateNHQ200Driver(int argc, char *argv[])
{
pEVDriver pNew = NULL;
pNHQ200Driv pSim = NULL;
/* check for arguments */
if(argc < 3)
{
return NULL;
}
pNew = CreateEVDriver(argc,argv);
pSim = (pNHQ200Driv)malloc(sizeof(NHQ200Driv));
memset(pSim,0,sizeof(NHQ200Driv));
if(!pNew || !pSim)
{
return NULL;
}
pNew->pPrivate = pSim;
pNew->KillPrivate = KillNHQ200;
/* initalise pNHQ200Driver */
pSim->iControl = atoi(argv[2]);
pSim->iRead = atoi(argv[1]);
pSim->iLastError = 0;
pSim->iTmo = 10;
/* The NHQ200 doesn't require divisors or multipliers
and they are always forced to 1.0 */
pSim->fDiv = 1.0;
pSim->fMult = 1.0;
pSim->pHost = strdup(argv[0]);
pSim->iPort = 0;
pSim->iChannel = 0;
/* initialise function pointers */
pNew->SetValue = NHQ200Run;
pNew->GetValue = GetNHQ200Pos;
pNew->Send = NHQ200Send;
pNew->GetError = NHQ200Error;
pNew->TryFixIt = NHQ200Fix;
pNew->Init = NHQ200Init;
pNew->Close = NHQ200Close;
return pNew;
}
/*--------------------------------------------------------------------------*/
int ConfigNHQ200(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
iRet = NHQ200_Config(&pMe->pData, pMe->iTmo, pMe->iRead,
pMe->iControl,pMe->fDiv,pMe->fMult);
if(iRet < 0)
{
pMe->iLastError = iRet;
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
int SetSensorNHQ200(pEVDriver self, int iSensor)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
/* The NHQ200 incorporates two voltage supplies so allow iSensor=1 to 2 */
if( (iSensor < 1) || (iSensor > 2) )
{
return 0;
}
pMe->iRead = iSensor;
pMe->pData->iRead = iSensor;
return 1;
}
/*-------------------------------------------------------------------------*/
int SetControlNHQ200(pEVDriver self, int iSensor)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
/* The NHQ200 incorporates two voltage supplies so allow iSensor=1 to 2 */
if( (iSensor < 1) || (iSensor > 2) )
{
return 0;
}
pMe->iControl = iSensor;
pMe->pData->iControl = iSensor;
return 1;
}
/*-------------------------------------------------------------------------*/
int SetTMONHQ200(pEVDriver self, int iSensor)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
if(iSensor < 10)
{
return 0;
}
pMe->iTmo = iSensor;
return 1;
}
/*-------------------------------------------------------------------------*/
int GetControlNHQ200(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
return pMe->iControl;
}
/*-------------------------------------------------------------------------*/
int GetSensorNHQ200(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
return pMe->iRead;
}
/*-------------------------------------------------------------------------*/
int GetTMONHQ200(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
return pMe->iTmo;
}
/*-------------------------------------------------------------------------*/
float GetDivisorNHQ200(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
return pMe->fDiv; /* but forced to 1.0 for NHQ200, not used */
}
/*--------------------------------------------------------------------------*/
int SetDivisorNHQ200(pEVDriver self, float fDiv)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
/* The NHQ200 doesn't need divisor, force to 1.0 */
pMe->fDiv = 1.0; /* fDiv */;
return 1;
}
/*-------------------------------------------------------------------------*/
float GetMultNHQ200(pEVDriver self)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
return pMe->fMult; /* but forced to 1.0 for NHQ200, not used */
}
/*--------------------------------------------------------------------------*/
int SetMultNHQ200(pEVDriver self, float fDiv)
{
pNHQ200Driv pMe = NULL;
int iRet;
assert(self);
pMe = (pNHQ200Driv )self->pPrivate;
assert(pMe);
/* The NHQ200 doesn't need multiplier, force to 1.0 */
pMe->fMult = 1.0; /* fDiv */;
return 1;
}

View File

@@ -30,6 +30,8 @@
/* Added customized HMControl object to support ANSTO OPAL NBI Histogram Server */
#include "hmcontrol.h"
#include "hmcontrol_ansto.h" // extends hmcontrol.h
/* Added code for NHQ200 HV Power Supply */
#include "nhq200.h"
/*@observer@*//*@null@*/ pCounterDriver CreateMonCounter(/*@observer@*/SConnection *pCon, /*@observer@*/char *name, char *params);
@@ -176,6 +178,18 @@ static pEVControl InstallEnvironmentController(SicsInterp *pSics,
}
}
/* Added code for new NHQ 200 driver */
if(strcmp(argv[3],"nhq200") == 0) {
pDriv = CreateNHQ200Driver(argc-4,&argv[4]);
if(pDriv){
pNew = CreateEVController(pDriv,argv[2],&status);
if(pNew != NULL){
AddCommand(pSics,argv[2],NHQ200Wrapper,DeleteEVController,
pNew);
}
}
}
return pNew;
}
/*-----------------------------------------------------------------*/