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:
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
511
site_ansto/hardsup/nhq200util.c
Normal file
511
site_ansto/hardsup/nhq200util.c
Normal 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;
|
||||
}
|
||||
}
|
||||
131
site_ansto/hardsup/nhq200util.h
Normal file
131
site_ansto/hardsup/nhq200util.h
Normal 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
285
site_ansto/nhq200.c
Normal 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
49
site_ansto/nhq200.h
Normal 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
488
site_ansto/nhq200driv.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
Reference in New Issue
Block a user