Huge changes, remove non-multichan code

r1511 | dcl | 2007-02-19 12:33:58 +1100 (Mon, 19 Feb 2007) | 2 lines
This commit is contained in:
Douglas Clowes
2007-02-19 12:33:58 +11:00
parent 6de7c8773f
commit 696227ffc8
2 changed files with 538 additions and 309 deletions

View File

@@ -2,7 +2,7 @@
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.
within the ANSTO setup: host === TCP/IP === MOXA === RS-232.
Mark Koennecke, Juli 1997
Mark Lesha, January 2006 (based on ITC4 code)
@@ -41,149 +41,385 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <fortify.h>
#include <sics.h>
#include <modriv.h>
#include <rs232controller.h>
#include <nwatch.h>
#include <multichan.h>
#include "nhq200util.h"
/* -------------------------------------------------------------------------*/
/* -------------------------------------------------------------------*/
static int writeNHQ200(prs232 rs232, void *data, int dataLen)
typedef struct __command Command, *pCommand;
typedef int (*CommandCallback)(void* ctx, const char* resp, int resp_len);
struct __command {
pMultiChan unit;
int cstate;
int lstate;
char* out_buf;
int out_len;
int out_idx;
char* inp_buf;
int inp_len;
int inp_idx;
CommandCallback func;
void* cntx;
};
static int NHQ_Tx1(void* ctx)
{
int i, iRet;
char reply[1];
int replyLen;
char* request = (char *) data;
char crlf[3] = {0x0D, 0x0A, 0x00};
int iRet = 1;
pCommand myCmd = (pCommand) ctx;
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;
assert(myCmd);
iRet = MultiChanWrite(myCmd->unit, &myCmd->out_buf[myCmd->out_idx], 1);
return iRet;
}
static int NHQ_Tx(void* ctx)
{
pCommand myCmd = (pCommand) ctx;
/*
* Set/reset command states for send/resend of command
*/
myCmd->cstate = 0;
myCmd->lstate = 0;
myCmd->out_idx = 0;
myCmd->inp_idx = 0;
return NHQ_Tx1(myCmd);
}
static int NHQ_Rx(void* ctx, int rxchar)
{
int iRet = 1;
pCommand myCmd = (pCommand) ctx;
switch (myCmd->cstate) {
case 0: /* send with echo */
if (rxchar != myCmd->out_buf[myCmd->out_idx]) {
/* TODO: bad echo */
}
else if (rxchar == 0x0A &&
myCmd->out_idx > 0 &&
myCmd->out_buf[myCmd->out_idx - 1] == 0x0D) {
myCmd->inp_idx = 0;
myCmd->cstate = 1;
/* TODO: end of line */
}
else if (myCmd->out_idx < myCmd->out_len) {
myCmd->out_idx++;
iRet = NHQ_Tx1(myCmd);
}
else {
/* TODO: out of data */
}
break;
case 1: /* receiving reply */
if (myCmd->inp_idx < myCmd->inp_len)
myCmd->inp_buf[myCmd->inp_idx++] = rxchar;
if (rxchar == 0x0D)
myCmd->cstate = 2;
break;
case 2: /* received CR and looking for LF */
if (myCmd->inp_idx < myCmd->inp_len)
myCmd->inp_buf[myCmd->inp_idx++] = rxchar;
if (rxchar == 0x0A) {
/* end of line */
myCmd->cstate = 3;
myCmd->inp_idx -= 2;
myCmd->inp_buf[myCmd->inp_idx] = '\0';
if (myCmd->func)
iRet = myCmd->func(myCmd->cntx, myCmd->inp_buf, myCmd->inp_idx);
else
iRet = 0;
}
else
myCmd->cstate = 1;
break;
}
if (iRet == 0) { /* end of command */
free(myCmd->out_buf);
free(myCmd->inp_buf);
free(myCmd);
}
return iRet;
}
int NHQ_SendCmd(pMultiChan unit,
char* command, int cmd_len,
CommandCallback callback, void* context, int rsp_len)
{
pCommand myCmd = NULL;
assert(unit);
myCmd = (pCommand) malloc(sizeof(Command));
assert(myCmd);
memset(myCmd, 0, sizeof(Command));
myCmd->out_buf = (char*) malloc(cmd_len + 5);
memcpy(myCmd->out_buf, command, cmd_len);
myCmd->out_len = cmd_len;
if (myCmd->out_len < 2 ||
myCmd->out_buf[myCmd->out_len - 1] != 0x0A ||
myCmd->out_buf[myCmd->out_len - 2] != 0x0D) {
myCmd->out_buf[myCmd->out_len++] = 0x0D;
myCmd->out_buf[myCmd->out_len++] = 0x0A;
}
myCmd->out_buf[myCmd->out_len] = '\0';
myCmd->func = callback;
myCmd->cntx = context;
if (rsp_len == 0)
myCmd->inp_buf = NULL;
else {
myCmd->inp_buf = malloc(rsp_len + 1);
memset(myCmd->inp_buf, 0, rsp_len + 1);
}
myCmd->inp_len = rsp_len;
myCmd->unit = unit;
return MultiChanEnque(unit, myCmd, NHQ_Tx, NHQ_Rx);
}
static void NHQ_Notify(void* context, int event)
{
pNHQ200 self = (pNHQ200) context;
switch (event) {
case MCC_RECONNECT:
do {
mkChannel* sock = MultiChanGetSocket(self->mcc);
int flag = 1;
setsockopt(sock->sockid, /* 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 */
return;
} while (0);
}
return;
}
static void parse_hash(pNHQ200 self, const char* resp, int resp_len)
{
int iSrc;
int iDst;
iSrc = 0;
iDst = 0;
while (iSrc < resp_len && resp[iSrc]) {
if (resp[iSrc] == ';') {
++iSrc;
break;
}
self->serial_number[iDst++] = resp[iSrc++];
}
self->serial_number[iDst] = '\0';
iDst = 0;
while (iSrc < resp_len && resp[iSrc]) {
if (resp[iSrc] == ';') {
++iSrc;
break;
}
self->software_version[iDst++] = resp[iSrc++];
}
self->software_version[iDst] = '\0';
iDst = 0;
while (iSrc < resp_len && resp[iSrc]) {
if (resp[iSrc] == ';') {
++iSrc;
break;
}
self->voltage_max[iDst++] = resp[iSrc++];
}
self->voltage_max[iDst] = '\0';
iDst = 0;
while (iSrc < resp_len && resp[iSrc]) {
if (resp[iSrc] == ';') {
++iSrc;
break;
}
self->current_max[iDst++] = resp[iSrc++];
}
self->current_max[iDst] = '\0';
/* TODO: convert voltage and current */
}
static void parse_Sx(pNHQ200 self, const char* resp, int resp_len)
{
memcpy(self->status_s, resp, resp_len);
if (resp_len > 0 && self->status_s[resp_len - 1] == ' ')
--resp_len;
self->status_s[resp_len] = '\0';
}
static void parse_Tx(pNHQ200 self, const char* resp, int resp_len)
{
memcpy(self->status_t, resp, resp_len);
self->status_t[resp_len] = '\0';
self->module_status = strtol(self->status_t, NULL, 10);
}
static void parse_Mx(pNHQ200 self, const char* resp, int resp_len)
{
self->vmax_percent = strtol(resp, NULL, 10);
}
static void parse_Nx(pNHQ200 self, const char* resp, int resp_len)
{
self->imax_percent = strtol(resp, NULL, 10);
}
static void parse_Vx(pNHQ200 self, const char* resp, int resp_len)
{
self->ramp_input = strtol(resp, NULL, 10);
}
#define STATE_HASH 1
#define STATE_SX 2
#define STATE_TX 3
#define STATE_MX 4
#define STATE_NX 5
#define STATE_VX 6
#define STATE_END 9
static int InitCallback(void* ctx, const char* resp, int resp_len)
{
char cmd[20];
int cmd_len;
/* TODO: FIXME finish initialisation */
pNHQ200 self = (pNHQ200) ctx;
switch (self->iState) {
case 0: /* Initial */
cmd_len = snprintf(cmd, sizeof(cmd), "#");
NHQ_SendCmd(self->mcc, cmd, cmd_len, InitCallback, self, 80);
self->iState = STATE_HASH;
break;
case STATE_HASH: /* # */
parse_hash(self, resp, resp_len);
cmd_len = snprintf(cmd, sizeof(cmd), "S%d", self->iControl);
NHQ_SendCmd(self->mcc, cmd, cmd_len, InitCallback, self, 80);
self->iState = STATE_SX;
break;
case STATE_SX: /* Sx */
parse_Sx(self, resp, resp_len);
cmd_len = snprintf(cmd, sizeof(cmd), "T%d", self->iControl);
NHQ_SendCmd(self->mcc, cmd, cmd_len, InitCallback, self, 80);
self->iState = STATE_TX;
break;
case STATE_TX: /* Tx */
parse_Tx(self, resp, resp_len);
cmd_len = snprintf(cmd, sizeof(cmd), "M%d", self->iControl);
NHQ_SendCmd(self->mcc, cmd, cmd_len, InitCallback, self, 80);
self->iState = STATE_MX;
break;
case STATE_MX: /* Mx */
parse_Mx(self, resp, resp_len);
cmd_len = snprintf(cmd, sizeof(cmd), "N%d", self->iControl);
NHQ_SendCmd(self->mcc, cmd, cmd_len, InitCallback, self, 80);
self->iState = STATE_NX;
break;
case STATE_NX: /* Nx */
parse_Nx(self, resp, resp_len);
cmd_len = snprintf(cmd, sizeof(cmd), "V%d", self->iControl);
NHQ_SendCmd(self->mcc, cmd, cmd_len, InitCallback, self, 80);
self->iState = STATE_VX;
break;
case STATE_VX: /* Vx */
parse_Vx(self, resp, resp_len);
self->iState = STATE_END;
break;
case STATE_END:
break;
}
return 0;
}
static void NHQ_Init(pNHQ200 self)
{
self->iState = 0;
NHQ_SendCmd(self->mcc, "", 0, InitCallback, self, 80);
}
/*
* \brief GetCallback is the callback for the get position/value command.
*/
static int GetCallback(void* ctx, const char* resp, int resp_len)
{
int iRet;
float fRead;
pNHQ200 self = (pNHQ200) ctx;
iRet = sscanf(resp,"%g",&fRead);
if(iRet != 1) { // Not a number, probably an error response
self->iError = NHQ200__BADREAD;
}
else {
if (fRead < 0)
fRead = -fRead;
self->fValue = fRead;
}
self->iGetOut = 0;
return 0;
}
/*
* \brief TransCallback is the callback for the general command transaction.
*/
static int TransCallback(void* ctx, const char* resp, int resp_len)
{
pNHQ200 self = (pNHQ200) ctx;
memcpy(self->transReply, resp, resp_len);
self->transReply[resp_len] = '\0';
self->transWait = 0;
return 0;
}
/*------------------------------------------------------------------------*/
int transactNHQ200(prs232 self, void *send, int sendLen,
int transactNHQ200(pNHQ200 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;
}
self->transReply = reply;
self->transWait = 1;
NHQ_SendCmd(self->mcc,
send, sendLen,
TransCallback, self, replyLen);
while (self->transWait)
TaskYield(pServ->pTasker);
return 1;
}
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
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. */
/* 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)
sprintf(pCommand,"S%d", self->iControl);
if ((iRet=transactNHQ200(self,pCommand,strlen(pCommand),pReply,79))<=0)
{
printf("Comms error!\n");
return iRet; // Comms problem
}
busy=(strncmp(pReply,"S1=ON",15)!=0);
sprintf(pCommand,"S%d=ON", self->iControl);
busy=(strncmp(pReply,pCommand,5) != 0);
notbusy=!busy;
if (notbusy)
{
@@ -198,99 +434,24 @@ int NHQ200_Check_Status(pNHQ200 self)
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 */
/* Operations common to both Open and Config functions */
static int NHQ200_Setup(pNHQ200 self, int iControl)
{
int iRet;
char pCommand[20];
char pReply[132];
if (!self || !self->controller || !self->controller->pSock)
if (!self)
return NHQ200__BADCOM;
/* 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)
int NHQ200_Open(pNHQ200 *pData, char *pName, int iSensor, int iCTRL, int iMode)
{
int iRet = 1;
mkChannel* sock = NULL;
pNHQ200 self = NULL;
self = (pNHQ200)malloc(sizeof(NHQ200));
@@ -298,6 +459,7 @@ int NHQ200_Open(pNHQ200 *pData, char *pRS232, int iSensor, int iCTRL, int iMode)
{
return NHQ200__BADMALLOC;
}
memset(self, 0, sizeof(NHQ200));
*pData = self;
self->iControl = iCTRL;
self->iRead = iSensor;
@@ -308,18 +470,28 @@ int NHQ200_Open(pNHQ200 *pData, char *pRS232, int iSensor, int iCTRL, int iMode)
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 (MultiChanCreate(pName, &self->mcc) == 0) {
return NHQ200__NONHQ200;
}
MultiChanSetNotify(self->mcc, self, NHQ_Notify);
if(!self->iReadOnly)
return NHQ200_Setup(self, self->iControl);
}
sock = MultiChanGetSocket(self->mcc);
if (sock) {
int flag = 1;
iRet = setsockopt(sock->sockid, /* 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 (iRet < 0)
return NHQ200__BADCOM;
}
else
return NHQ200__BADCOM;
NHQ_Init(self);
return iRet;
}
/*--------------------------------------------------------------------------*/
void NHQ200_Close(pNHQ200 *pData)
{
@@ -329,18 +501,10 @@ void NHQ200_Close(pNHQ200 *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,
int NHQ200_Config(pNHQ200 *pData, int iTmo, int iRead, int iControl,
float fDiv,float fMult)
{
pNHQ200 self;
@@ -348,11 +512,12 @@ int NHQ200_Config(pNHQ200 *pData, int iTmo, int iRead, int iControl,
self = *pData;
return NHQ200_Setup(self, iControl);
}
}
/* --------------------------------------------------------------------------*/
int NHQ200_Send(pNHQ200 *pData, char *pCommand, char *pReply, int iLen)
{
int iRet,i,commandlen,isquery;
int iRet;
int commandlen;
pNHQ200 self;
self = *pData;
@@ -360,50 +525,36 @@ int NHQ200_Send(pNHQ200 *pData, char *pCommand, char *pReply, int iLen)
/* Send command direct to the NHQ200 */
commandlen=strlen(pCommand);
usleep(50000); // Required to meet Lakeshore340 spec.
iRet=transactNHQ200(self->controller,pCommand,commandlen,pReply,iLen);
iRet=transactNHQ200(self,pCommand,commandlen,pReply,iLen);
return iRet;
}
/*--------------------------------------------------------------------------*/
int NHQ200_Read(pNHQ200 *pData, float *fVal)
{
char pCommand[20], pReply[132];
char pCommand[20];
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
/* for the NHQ200 there are two units available */
sprintf(pCommand,"U%d", self->iControl);
if (self->iGetOut == 0) {
struct timeval tv_this;
gettimeofday(&tv_this, NULL);
if ((tv_this.tv_sec - self->tv_last.tv_sec) > 0) {
NHQ_SendCmd(self->mcc,
pCommand, 2,
GetCallback, self, 132);
self->iGetOut = 1;
self->tv_last = tv_this;
}
}
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;
*fVal = self->fValue;
iRet = 1;
return iRet;
}
@@ -423,52 +574,41 @@ int NHQ200_Set(pNHQ200 *pData, float fVal)
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
/* command to set the voltage */
sprintf(pCommand,"D%d=%d", self->iControl, (int) (fVal + 0.5));
/* command to read back and check the set value */
sprintf(pCommandRead,"D%d", self->iControl);
/* 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)
/* send Dn=nnn command, we get a blank line response */
iRet = transactNHQ200(self,pCommand,strlen(pCommand),pReply,131);
if (iRet <= 0)
return iRet;
/* read the set value again using the Dn command */
iRet = transactNHQ200(self,pCommandRead,strlen(pCommandRead),pReply,131);
if (iRet <= 0)
return iRet;
printf("D%d: Response %d chars: '%s'\n",self->iControl, iRet, pReply);
/* Convert the value read back. */
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)
{
sprintf(pCommandGo, "G%d", self->iControl);
iRet = transactNHQ200(self,pCommandGo,strlen(pCommandGo),pReply,131);
if (iRet <= 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("G%d: Response %d chars: '%s'\n",self->iControl, iRet, pReply);
printf("SET OK, checking status and returning.\n");
return 1;
}
printf("SETP failed!\n");
printf("SET failed!\n");
return NHQ200__BADSET;
}
/* -------------------------------------------------------------------------*/
@@ -496,18 +636,89 @@ void NHQ200_ErrorTxt(pNHQ200 *pData,int iCode, char *pError, int iLen)
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);
strncpy(pError,"NHQ200: Failed 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);
sprintf(pBueffel,"NHQ200: Internal fault: %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);
sprintf(pBueffel,"NHQ200: Unit not found: %s",self->pAns);
strncpy(pError,pBueffel,iLen);
break;
default:
SerialError(iCode, pError,iLen);
break;
snprintf(pError, iLen, "NHQ200: Unknown Error: %d", iCode);
break;
}
}
static int GALIL_Tx(void* ctx)
{
int iRet = 1;
pCommand myCmd = (pCommand) ctx;
if (myCmd) {
iRet = MultiChanWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len);
/* TODO handle errors */
if (iRet < 0) { /* TODO: EOF */
iRet = MultiChanReconnect(myCmd->unit);
if (iRet == 0)
return 0;
}
}
return 1;
}
static int GALIL_Rx(void* ctx, int rxchar)
{
int iRet = 1;
pCommand myCmd = (pCommand) ctx;
switch (myCmd->cstate) {
case 0: /* first character */
if (rxchar == ':') {
/* normal prompt */
myCmd->cstate = 99;
}
else if (rxchar == '?') {
/* TODO: error prompt, send TC1 */
myCmd->cstate = 99;
}
else {
/* normal data */
myCmd->cstate = 1;
}
/* note fallthrough */
case 1: /* receiving reply */
if (myCmd->inp_idx < myCmd->inp_len)
myCmd->inp_buf[myCmd->inp_idx++] = rxchar;
if (rxchar == 0x0D)
myCmd->cstate = 2;
break;
case 2: /* received CR and looking for LF */
if (myCmd->inp_idx < myCmd->inp_len)
myCmd->inp_buf[myCmd->inp_idx++] = rxchar;
if (rxchar == 0x0A) {
myCmd->cstate = 99;
/* end of line */
}
else
myCmd->cstate = 1;
break;
}
if (myCmd->cstate == 99) {
myCmd->inp_buf[myCmd->inp_idx] = '\0';
if (myCmd->func)
iRet = myCmd->func(myCmd->cntx, myCmd->inp_buf, myCmd->inp_idx);
else
iRet = 0;
myCmd->cstate = 0;
myCmd->inp_idx = 0;
}
if (iRet == 0) { /* end of command */
free(myCmd->out_buf);
free(myCmd->inp_buf);
free(myCmd);
}
return iRet;
}

View File

@@ -2,7 +2,7 @@
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:
voltage controller via the ANSTO setup:
TCP/IP===MOXA===RS-232===NHQ200.
Mark Koennecke, Juli 1997
@@ -14,7 +14,7 @@
#define NHQ200_UTIL_H
/*----------------------- ERRORCODES--------------------------------------
Most functions return a negative error code on failure. Error codes
Most functions return a negative error code on failure. Error codes
defined are those defined for serialsinq plus a few additional ones:
*/
@@ -27,7 +27,9 @@
#define NHQ200__BADSET -530 /* failed three times to set voltage */
#define NHQ200__READONLY -531
/*------------------------------------------------------------------------*/
typedef struct __NHQ200 {
pMultiChan mcc;
int iRead;
int iControl;
void *pData;
@@ -37,9 +39,25 @@ typedef struct __NHQ200 {
but force the value to 1.0 all the time */
float fDiv;
float fMult;
float fValue;
int iError;
int iReadOnly;
prs232 controller;
} NHQ200;
int iState;
char serial_number[20];
char software_version[20];
char voltage_max[20];
char current_max[20];
char status_s[20];
char status_t[20];
int module_status;
int vmax_percent;
int imax_percent;
int ramp_input;
char* transReply;
int transWait;
int iGetOut;
struct timeval tv_last;
} NHQ200;
typedef struct __NHQ200 *pNHQ200;
@@ -55,29 +73,29 @@ 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
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 NHQ200_Config(pNHQ200 *pData, int iTmo, int iRead,
int iControl, float fDiv, float fMult);
/***** configure some aspects of a NHQ200 voltage controller.
The parameter are:
- a pointer to the data structure for the controller as
- a pointer to the data structure for the controller as
returned by NHQ200_Open
- a value for the connection timeout
- the voltage sensor to use for reading the
- the voltage sensor to use for reading the
voltage.
- the voltage sensor used by the NHQ200controller
- the voltage sensor used by the NHQ200controller
for regulating the voltage.
- the divisor needed to calculate the real voltage
from the sensor.
The function returns 1 on success, a negative error code on
from the sensor.
The function returns 1 on success, a negative error code on
failure.
*/
@@ -116,7 +134,7 @@ 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 /* NHQ200_UTIL_H */