652 lines
18 KiB
C
652 lines
18 KiB
C
/*--------------------------------------------------------------------------
|
||
N H Q 2 0 0 U T I L
|
||
|
||
A few utility functions for dealing with a NHQ200 voltage controller
|
||
within the ANSTO setup: host === TCP/IP === MOXA === 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/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 <nwatch.h>
|
||
#include <asyncqueue.h>
|
||
#include "nhq200util.h"
|
||
/*-------------------------------------------------------------------*/
|
||
|
||
static pAsyncProtocol NHQ_Protocol = NULL;
|
||
|
||
static int NHQ_Tx1(pAsyncProtocol p, void* ctx)
|
||
{
|
||
int iRet = 1;
|
||
pAsyncTxn myCmd = (pAsyncTxn) ctx;
|
||
|
||
assert(myCmd);
|
||
iRet = AsyncUnitWrite(myCmd->unit, &myCmd->out_buf[myCmd->out_idx], 1);
|
||
return iRet;
|
||
}
|
||
|
||
static int NHQ_Tx(pAsyncProtocol p, pAsyncTxn myCmd)
|
||
{
|
||
/*
|
||
* Set/reset command states for send/resend of command
|
||
*/
|
||
myCmd->txn_state = 0;
|
||
myCmd->out_idx = 0;
|
||
myCmd->inp_idx = 0;
|
||
myCmd->txn_status = ATX_ACTIVE;
|
||
return NHQ_Tx1(p, myCmd);
|
||
}
|
||
|
||
static int NHQ_Rx(pAsyncProtocol p, pAsyncTxn myCmd, int rxchar)
|
||
{
|
||
int iRet = 1;
|
||
|
||
switch (myCmd->txn_state) {
|
||
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->txn_state = 1;
|
||
/* TODO: end of line */
|
||
}
|
||
else if (myCmd->out_idx < myCmd->out_len) {
|
||
myCmd->out_idx++;
|
||
iRet = NHQ_Tx1(p, 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->txn_state = 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->txn_state = 3;
|
||
myCmd->inp_idx -= 2;
|
||
myCmd->inp_buf[myCmd->inp_idx] = '\0';
|
||
myCmd->txn_status = ATX_COMPLETE;
|
||
iRet = 0;
|
||
}
|
||
else
|
||
myCmd->txn_state = 1;
|
||
break;
|
||
}
|
||
if (iRet == 0) { /* end of command */
|
||
return AQU_POP_CMD;
|
||
}
|
||
return iRet;
|
||
}
|
||
|
||
static int NHQ_Ev(pAsyncProtocol p, pAsyncTxn myCmd, int event)
|
||
{
|
||
if (event == AQU_TIMEOUT) {
|
||
/* TODO: handle command timeout */
|
||
myCmd->txn_status = ATX_TIMEOUT;
|
||
return AQU_POP_CMD;
|
||
}
|
||
return AQU_POP_CMD;
|
||
}
|
||
|
||
static void NHQ_Notify(void* context, int event)
|
||
{
|
||
pNHQ200 self = (pNHQ200) context;
|
||
|
||
switch (event) {
|
||
case AQU_DISCONNECT:
|
||
if (self->transWait == 1) {
|
||
self->transWait = NHQ200__FAULT;
|
||
strcpy(self->pAns, "DISCONNECTED");
|
||
}
|
||
case AQU_RECONNECT:
|
||
do {
|
||
mkChannel* sock = AsyncUnitGetSocket(self->unit);
|
||
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(pAsyncTxn pTxn)
|
||
{
|
||
char cmd[20];
|
||
int cmd_len;
|
||
const char* resp = pTxn->inp_buf;
|
||
int resp_len = pTxn->inp_idx;
|
||
pNHQ200 self = (pNHQ200) pTxn->cntx;
|
||
if (pTxn->txn_status == ATX_TIMEOUT) {
|
||
self->iError = NHQ200__BADSET;
|
||
self->iState = 0;
|
||
}
|
||
else {
|
||
switch (self->iState) {
|
||
case 0: /* Initial */
|
||
cmd_len = snprintf(cmd, sizeof(cmd), "#");
|
||
AsyncUnitSendTxn(self->unit, 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);
|
||
AsyncUnitSendTxn(self->unit, 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);
|
||
AsyncUnitSendTxn(self->unit, 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);
|
||
AsyncUnitSendTxn(self->unit, 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);
|
||
AsyncUnitSendTxn(self->unit, 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);
|
||
AsyncUnitSendTxn(self->unit, 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;
|
||
AsyncUnitSendTxn(self->unit, "", 0, InitCallback, self, 80);
|
||
}
|
||
|
||
/*
|
||
* \brief GetCallback is the callback for the get position/value command.
|
||
*/
|
||
static int GetCallback(pAsyncTxn pTxn)
|
||
{
|
||
int iRet;
|
||
float fRead;
|
||
const char* resp = pTxn->inp_buf;
|
||
pNHQ200 self = (pNHQ200) pTxn->cntx;
|
||
|
||
if (pTxn->txn_status == ATX_TIMEOUT) {
|
||
self->iError = NHQ200__BADREAD;
|
||
}
|
||
else {
|
||
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(pAsyncTxn pTxn)
|
||
{
|
||
const char* resp = pTxn->inp_buf;
|
||
int resp_len = pTxn->inp_idx;
|
||
pNHQ200 self = (pNHQ200) pTxn->cntx;
|
||
|
||
if (pTxn->txn_status == ATX_TIMEOUT) {
|
||
self->transReply[0] = '\0';
|
||
self->transWait = -1;
|
||
}
|
||
else {
|
||
memcpy(self->transReply, resp, resp_len);
|
||
self->transReply[resp_len] = '\0';
|
||
self->transWait = 0;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
int transactNHQ200(pNHQ200 self, void *send, int sendLen,
|
||
void *reply, int replyLen)
|
||
{
|
||
assert(self);
|
||
self->transReply = reply;
|
||
self->transWait = 1;
|
||
AsyncUnitSendTxn(self->unit,
|
||
send, sendLen,
|
||
TransCallback, self, replyLen);
|
||
while (self->transWait == 1)
|
||
TaskYield(pServ->pTasker);
|
||
if (self->transWait < 0)
|
||
return self->transWait;
|
||
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.
|
||
*/
|
||
iRetry=0;
|
||
printf("Checking status...");
|
||
do
|
||
{
|
||
sprintf(pCommand,"S%d", self->iControl);
|
||
iRet=AsyncUnitTransact(self->unit, pCommand, strlen(pCommand), pReply, 79);
|
||
if (iRet <= 0)
|
||
{
|
||
printf("Comms error!\n");
|
||
return iRet; // Comms problem
|
||
}
|
||
sprintf(pCommand,"S%d=ON", self->iControl);
|
||
busy=(strncmp(pReply,pCommand,5) != 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;
|
||
}
|
||
|
||
/* Operations common to both Open and Config functions */
|
||
static int NHQ200_Setup(pNHQ200 self, int iControl)
|
||
{
|
||
if (!self)
|
||
return NHQ200__BADCOM;
|
||
|
||
|
||
return 1; /* Success */
|
||
}
|
||
|
||
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));
|
||
if(self == NULL)
|
||
{
|
||
return NHQ200__BADMALLOC;
|
||
}
|
||
memset(self, 0, sizeof(NHQ200));
|
||
*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;
|
||
|
||
if (AsyncUnitCreate(pName, &self->unit) == 0) {
|
||
return NHQ200__NONHQ200;
|
||
}
|
||
AsyncUnitSetNotify(self->unit, self, NHQ_Notify);
|
||
|
||
sock = AsyncUnitGetSocket(self->unit);
|
||
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)
|
||
{
|
||
pNHQ200 self;
|
||
|
||
self = *pData;
|
||
if (!self)
|
||
return; // 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;
|
||
int commandlen;
|
||
pNHQ200 self;
|
||
|
||
self = *pData;
|
||
|
||
/* Send command direct to the NHQ200 */
|
||
commandlen=strlen(pCommand);
|
||
|
||
iRet=AsyncUnitTransact(self->unit, pCommand, commandlen, pReply, iLen);
|
||
|
||
return iRet;
|
||
}
|
||
/*--------------------------------------------------------------------------*/
|
||
int NHQ200_Read(pNHQ200 *pData, float *fVal)
|
||
{
|
||
char pCommand[20];
|
||
int iRet;
|
||
pNHQ200 self;
|
||
|
||
self = *pData;
|
||
|
||
|
||
/* 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) {
|
||
AsyncUnitSendTxn(self->unit,
|
||
pCommand, 2,
|
||
GetCallback, self, 132);
|
||
self->iGetOut = 1;
|
||
self->tv_last = tv_this;
|
||
}
|
||
}
|
||
while (self->iGetOut) {
|
||
struct timeval tv_this;
|
||
gettimeofday(&tv_this, NULL);
|
||
if ((tv_this.tv_sec - self->tv_last.tv_sec) > 1)
|
||
break;
|
||
TaskYield(pServ->pTasker);
|
||
}
|
||
*fVal = self->fValue;
|
||
iRet = 1;
|
||
|
||
return iRet;
|
||
}
|
||
/*-------------------------------------------------------------------------*/
|
||
int NHQ200_Set(pNHQ200 *pData, float fVal)
|
||
{
|
||
char pCommand[20], pCommandRead[20], pReply[132], pCommandGo[20];
|
||
int iRet;
|
||
const float fPrecision = 0.1;
|
||
float fDelta, fRead;
|
||
pNHQ200 self;
|
||
|
||
self = *pData;
|
||
|
||
if(self->iReadOnly)
|
||
{
|
||
return NHQ200__READONLY;
|
||
}
|
||
|
||
/* 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);
|
||
|
||
/* send Dn=nnn command, we get a blank line response */
|
||
iRet = AsyncUnitTransact(self->unit,pCommand,strlen(pCommand),pReply,131);
|
||
if (iRet <= 0)
|
||
return iRet;
|
||
/* read the set value again using the Dn command */
|
||
iRet = AsyncUnitTransact(self->unit,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 = AsyncUnitTransact(self->unit,pCommandGo,strlen(pCommandGo),pReply,131);
|
||
if (iRet <= 0)
|
||
return iRet;
|
||
printf("G%d: Response %d chars: '%s'\n",self->iControl, iRet, pReply);
|
||
printf("SET OK, checking status and returning.\n");
|
||
return 1;
|
||
}
|
||
printf("SET 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 to write new set value to NHQ200",iLen);
|
||
break;
|
||
case NHQ200__FAULT: // Covers various NHQ200 self-diagnosed fault conditions
|
||
sprintf(pBueffel,"NHQ200: Internal fault: %s",self->pAns);
|
||
strncpy(pError,pBueffel,iLen);
|
||
break;
|
||
case NHQ200__NONHQ200:
|
||
sprintf(pBueffel,"NHQ200: Unit not found: %s",self->pAns);
|
||
strncpy(pError,pBueffel,iLen);
|
||
break;
|
||
default:
|
||
snprintf(pError, iLen, "NHQ200: Unknown Error: %d", iCode);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void NHQ200InitProtocol(SicsInterp *pSics) {
|
||
if (NHQ_Protocol == NULL) {
|
||
NHQ_Protocol = AsyncProtocolCreate(pSics, "NHQ200", NULL, NULL);
|
||
NHQ_Protocol->sendCommand = NHQ_Tx;
|
||
NHQ_Protocol->handleInput = NHQ_Rx;
|
||
NHQ_Protocol->handleEvent = NHQ_Ev;
|
||
NHQ_Protocol->prepareTxn = NULL;
|
||
NHQ_Protocol->killPrivate = NULL;
|
||
}
|
||
}
|