Files
sics/site_ansto/hardsup/sct_rfamp.c
Ferdi Franceschini 3d5d94c1dd sct_rfamp.c
SICS-405 Protocol handler always reports "SET" failed. Implemented workaround so that it always succeeds until we have a proper fix.

server_config.tcl
Set opal_simulation=true until we implement the new LSS feedback

r2940 | ffr | 2010-05-28 11:36:25 +1000 (Fri, 28 May 2010) | 6 lines
2012-11-15 17:03:35 +11:00

342 lines
10 KiB
C

/**
* @brief Protocol handler for Mirrotron RF power supplies
Author: Ferdi Franceschini
TODO: Provide acknowledgement when setting a parameter
"OK", when successful
"ANSRFAMP: Set failed", on error
Current should be ramped up in steps of 0.5A but it doesn't
have to be ramped down.
Provides two commands (L)ist and (S)et
eg,
The following command lists status info from the RF Amp at address 3.
sct_rfamp send L:3
The reply string has the following form
address=1|type=L|curr=00|freq=170|voltage=50|K3=1|K2=1|K1=1|O=1|CC=1|CV=0|H=1
The following command sets the current(I), frequency, switches(K1,K2,K3) and output(O).
sct_rfamp send S:3:I=5:F=170:K3=0:K2=1:k1=0:O=1
NOTE: The current is an integer which equals the desired current x10, ie 71 -> 7.1A
*/
#include <errno.h>
#include <ctype.h>
#include <ascon.h>
#include <ascon.i>
#include <string.h>
#include <dynstring.h>
#define ERRLEN 128
#define LASTBYTENUM 12
#define NOTBOOLEAN(b) (b==1 || b==0 ? 0 : 1)
#define MINCURRSPEC 0
#define MAXCURRSPEC 71
#define MINFREQ 170
#define MAXFREQ 500
#define LCMDLEN 4
#define SCMDLEN 10
#define REPLYLEN 13
struct RFAmpData {
int transactInProg;
int targetCurrent;
char rfCmd[16];
char statusCmd[5];
int currTol;
};
void RFAmpKill(void *private)
{
struct RFAmpData *data = private;
free(data);
}
enum transactionState {txNormalRead, txPreSet, txPostSet, txCheckReply};
/**
* @brief Translates ASCII command string into a properly formatted command for the RF amplifier
*/
int RFAmpWriteStart (Ascon *a)
{
char *dynStrBuffer, errMsg[ERRLEN];
char ctype='X', address='0';
unsigned char switches=0;
int curr, freq, outOn, K1, K2, K3;
int i, ret;
struct RFAmpData *data = a->private;
curr=freq=outOn=K1=K2=K3=0;
dynStrBuffer = GetCharArray(a->wrBuffer);
for (i=0; dynStrBuffer[i]; i++)
dynStrBuffer[i]=toupper(dynStrBuffer[i]);
ret = sscanf(dynStrBuffer, " %c:%c:I=%d:F=%d:K3=%d:K2=%d:K1=%d:O=%d ", &ctype, &address, &curr, &freq, &K3, &K2, &K1, &outOn);
if (ret==0) {
snprintf(errMsg, ERRLEN, "ANSRFAMP:Invalid command string %s", dynStrBuffer);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
}
switch (ctype) {
case 'L':
sprintf(data->rfCmd,"%c%c%c%c", 2, address, ctype, 3);
DynStringReplaceWithLen(a->wrBuffer, data->rfCmd,0, LCMDLEN);
a->state = AsconWriting;
a->noResponse = 0;
a->wrPos = 0;
return 1;
break;
case 'S':
if (ret < 8) {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Invalid command string %s", dynStrBuffer);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
}
if (address < '1' || address > '9') {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Invalid address %c, it should be between 1 and 9", address);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
}
if (curr < MINCURRSPEC || curr > MAXCURRSPEC) {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Invalid current specifier %d, it should be between %d and %d. NOTE:divide by 10 to convert to Amps", \
curr, MINCURRSPEC, MAXCURRSPEC);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
}
if (freq < MINFREQ || freq > MAXFREQ) {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Invalid frequency %d, it should be between %d and %d", freq, MINFREQ, MAXFREQ);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
}
if (NOTBOOLEAN(K1) || NOTBOOLEAN(K2) || NOTBOOLEAN(K3) || NOTBOOLEAN(outOn)) {
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, "ANSRFAMP: K1, K2, K3 and O must be boolean values (ie 1 or 0)", 0);
return 1;
}
switches = (K3 << 3) | (K2 << 2) | (K1 << 1) | outOn;
sprintf(data->rfCmd,"%c%c%c%02d%03d%c%c", 2, address, ctype, curr, freq, switches, 3);
if (data->rfCmd[0] != 2 || data->rfCmd[9] != 3) {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Failed to construct a valid packet for %s", dynStrBuffer);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
}
sprintf(data->statusCmd,"%c%c%c%c", 2, address, 'L', 3);
DynStringReplaceWithLen(a->wrBuffer, data->statusCmd, 0, LCMDLEN);
data->transactInProg = txPreSet;
data->targetCurrent = curr;
a->state = AsconWriting;
a->noResponse = 0;
a->wrPos = 0;
return 1;
break;
default:
snprintf(errMsg, ERRLEN, "ANSRFAMP: Unknown command type %c, allowed types are 'L' or 'S'", ctype);
a->state = AsconWriteDone;
a->noResponse = 1;
AsconError(a, errMsg, 0);
return 1;
break;
}
}
int RFAmpReading (Ascon *a)
{
int rdChRet, GetReplyFailed=0, errNum=0;
char chr, address, ctype, curr[3], freq[4], voltage[3], replyStr[128];
unsigned char switches, opstate;
unsigned char K3, K2, K1, outOn, CC, CV, heat;
char errMsg[ERRLEN];
struct RFAmpData *data = a->private;
switches=opstate=K3=K2=K1=outOn=CC=CV=heat=0;
if(data->transactInProg == txPostSet){
data->transactInProg = txCheckReply;
DynStringReplaceWithLen(a->wrBuffer, data->statusCmd, 0, LCMDLEN);
a->state = AsconWriting;
a->noResponse = 0;
a->wrPos = 0;
}else{
// Start reading when byte = 2 and stop when 3
while ( ( rdChRet = AsconReadChar(a->fd, &chr) ) > 0) {
a->start = DoubleTime();
if (a->readState) {
if (a->readState >= LASTBYTENUM) {
a->readState = 0;
if (a->readState > LASTBYTENUM) {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Packet larger than expected, size exceeds %d", LASTBYTENUM);
GetReplyFailed = 1;
break;
}
if (chr != 3) {
snprintf(errMsg, ERRLEN, "ANSRFAMP: Unexpected value %X for packet end signal", chr);
GetReplyFailed = 1;
break;
}
if (0 == DynStringConcatChar(a->rdBuffer, '\0')) {
strcpy(errMsg, "ANSRFAMP: DynStringConcatChar failed:");
errNum = ENOMEM;
GetReplyFailed = 1;
break;
}
address = GetCharArray(a->rdBuffer)[0];
ctype = GetCharArray(a->rdBuffer)[1];
strncpy(curr, &GetCharArray(a->rdBuffer)[2], 2);
strncpy(freq, &GetCharArray(a->rdBuffer)[4], 3);
strncpy(voltage, &GetCharArray(a->rdBuffer)[7], 2);
switches = (unsigned char)GetCharArray(a->rdBuffer)[9];
opstate = GetCharArray(a->rdBuffer)[10];
if (data->transactInProg == txPreSet) {
data->transactInProg = txPostSet;
if (abs(data->targetCurrent - atoi(curr)) <= (5 + data->currTol)) {
DynStringReplaceWithLen(a->wrBuffer, data->rfCmd,0, SCMDLEN);
a->state = AsconWriting;
a->noResponse = 0;
a->wrPos = 0;
} else {
strcpy(errMsg, "ANSRFAMP: Step size should be <= 5 for current");
GetReplyFailed = 1;
break;
}
} else if (data->transactInProg == txCheckReply) {
// TODO Compare rdBuffer to rfCmd if they match then set replyStr="OK" else set error message
char tmpCurr[3], tmpFreq[4];
unsigned char tmpSwitchs;
strncpy(tmpCurr, &data->rfCmd[3], 2);
strncpy(tmpFreq, &data->rfCmd[5], 3);
tmpSwitchs = (unsigned char)data->rfCmd[8];
/* TODO SICS-405 ffr Removed check because the read values don't immediately match the set values
if( (abs(atoi(curr) - atoi(tmpCurr)) > data->currTol) ||
(atoi(freq) != atoi(tmpFreq)) ||
((switches & 0x0F) != (tmpSwitchs & 0x0F)) ) {
strcpy(errMsg, "ANSRFAMP: the (S)ET command failed");
GetReplyFailed = 1;
break;
} else {
DynStringReplace(a->rdBuffer, "OK", 0);
}
*/
/* ffr Just report OK until we have a proper fix */
DynStringReplace(a->rdBuffer, "OK", 0);
a->state = AsconReadDone;
data->transactInProg = txNormalRead;
} else if (data->transactInProg == txNormalRead) {
K3 = (switches & 0x08) >> 3;
K2 = (switches & 0x04) >> 2;
K1 = (switches & 0x02) >> 1;
outOn = switches & 0x01;
CC = (opstate & 0x04) >> 2;
CV = (opstate & 0x02) >> 1;
heat = opstate & 0x01;
snprintf(replyStr, 128, "address=%c|type=%c|curr=%s|freq=%s|voltage=%s|K3=%d|K2=%d|K1=%d|O=%d|CC=%d|CV=%d|H=%d", \
address, ctype, curr, freq, voltage, K3, K2, K1, outOn, CC, CV, heat);
if (0 == DynStringReplaceWithLen(a->rdBuffer, replyStr, 0, 128)) {
strcpy(errMsg, "ANSRFAMP: DynStringReplace failed:");
errNum = ENOMEM;
GetReplyFailed = 1;
break;
}
a->state = AsconReadDone;
}
return 1;
}
if (0 == DynStringConcatChar(a->rdBuffer, chr)) {
strcpy(errMsg, "ANSRFAMP: DynStringConcatChar failed:");
errNum = ENOMEM;
GetReplyFailed = 1;
break;
}
a->readState++;
} else if (chr == 2) {
a->readState = 1;
}
}
}
if (rdChRet < 0) {
AsconError(a, "ANSRFAMP: AsconReadChar failed:", errno);
return 1;
}
if (GetReplyFailed) {
a->state = AsconReadDone;
a->noResponse = 1;
a->readState = 0;
data->transactInProg = txNormalRead;
AsconError(a, errMsg, errNum);
return 1;
}
if (a->timeout > 0) {
if (DoubleTime() - a->start > a->timeout) {
a->state = AsconTimeout;
AsconError(a, "ANSRFAMP: read timeout", 0);
}
}
return 1;
}
int RFAmpProtHandler (Ascon *a)
{
int ret;
switch (a->state) {
case AsconWriteStart:
ret = RFAmpWriteStart(a);
return ret;
break;
case AsconReading:
ret = RFAmpReading(a);
return ret;
break;
default:
return AsconStdHandler(a);
}
}
int RFAmpInit(Ascon *a, SConnection *con, int argc, char *argv[])
{
struct RFAmpData *data;
a->readState=0;
a->private = data = (struct RFAmpData *) malloc(sizeof(struct RFAmpData));
data->transactInProg = txNormalRead;
data->targetCurrent = 0;
data->rfCmd[0] = '\0';
data->statusCmd[0] = '\0';
data->currTol = 1; /* TODO This should be a configuration parameter */
a->killPrivate = RFAmpKill;
return AsconStdInit(a, con, argc, argv);
}
void AddRFAmpProtocol()
{
AsconProtocol *prot = NULL;
prot = calloc(sizeof(AsconProtocol), 1);
prot->name = strdup("rfamp");
prot->init = RFAmpInit;
prot->handler = RFAmpProtHandler;
AsconInsertProtocol(prot);
}