Mark Lesha's fixes to the asyncqueue and voltage controller
r2696 | ffr | 2008-09-18 14:50:09 +1000 (Thu, 18 Sep 2008) | 2 lines
This commit is contained in:
committed by
Douglas Clowes
parent
70f194fe85
commit
7919c7cd6a
@@ -107,7 +107,29 @@ static int ORHV_SendReceive(pORHVPSDriv priv,
|
||||
int *rep_len) {
|
||||
int status;
|
||||
|
||||
status = AsyncUnitTransact(priv->asyncUnit, cmd, cmd_len, reply, rep_len);
|
||||
if (!*cmd)
|
||||
{
|
||||
*reply='\0';
|
||||
*rep_len=0;
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Ordela 21000 firmware appears to send NAK (15h) code at regular intervals
|
||||
// when there is no comms (time out)? To prevent this from interfering with
|
||||
// the transaction, perform a dummy transaction first.
|
||||
// Reading the jumper settings should be harmless (but in case of true
|
||||
// disconnect we are going to get N * timeout - should not normally occur)
|
||||
|
||||
int max_rep_len=*rep_len; // Value of arguemnt on entry is the max receive buffer len
|
||||
AsyncUnitTransact(priv->asyncUnit, "Jz", 2, reply, rep_len);
|
||||
*rep_len=max_rep_len;
|
||||
// Now do the real transaction. */
|
||||
int max_retries=1; // Retries should be built into the async queue object, so set to 1. In practice this works just fine.
|
||||
do
|
||||
{
|
||||
*rep_len=max_rep_len;
|
||||
status = AsyncUnitTransact(priv->asyncUnit, cmd, cmd_len, reply, rep_len);
|
||||
} while(--max_retries&&status!=1);
|
||||
|
||||
if (status != 1) {
|
||||
return FAILURE;
|
||||
@@ -680,7 +702,7 @@ static int ORHVPSSend(pEVDriver self, char *pCommand, char *pReply, int iLen) {
|
||||
cmd[idx] = '\0';
|
||||
cmd_len = idx;
|
||||
rsp_len = CMDLEN;
|
||||
ORHV_SendReceive(self->pPrivate, cmd, cmd_len, rsp, &rsp_len);
|
||||
int orhvsr_status=ORHV_SendReceive(self->pPrivate, cmd, cmd_len, rsp, &rsp_len);
|
||||
idx = 0;
|
||||
for (i = 0; i < rsp_len && idx < iLen - 1; ++i) {
|
||||
if (rsp[i] < 32 || rsp[i] > 126) {
|
||||
@@ -934,10 +956,17 @@ pEVDriver CreateORHVPSDriver(int argc, char *argv[])
|
||||
priv->fsm.state_name = state_name;
|
||||
priv->fsm.event_name = event_name;
|
||||
priv->name = strdup(argv[0]);
|
||||
priv->fMax = 2400.0;
|
||||
// MJL 9/08 Modified the defaults to cater for the current Ordela 21000N detector on SANS
|
||||
// (max HV setting 2600V adjusted via pot). For the spare Ordela detector, the max voltage
|
||||
// is pot-adjusted to 2400V as we have been advised that this is the max safe operating voltage.
|
||||
// Since this driver uses the fUpper for scaling, in order to prevent any potential damage to the
|
||||
// detectors we set the default to the highest of the two. (i.e. if .upper is not initialized
|
||||
// in the SICS configuration, it is higher than or equal to the actual detector voltage maximum
|
||||
// and this results in the set voltage being equal to or lower than expected - not higher).
|
||||
priv->fMax = 2600.0;
|
||||
priv->fRate = 10.0;
|
||||
priv->fLower = 0.0;
|
||||
priv->fUpper = 1800.0;
|
||||
priv->fLower = 0.0; // fLower is 'low' safe voltage for driving - nominally 800V - but leave default at 0V for safety
|
||||
priv->fUpper = 2350.0;
|
||||
priv->iPeriod = get_period(priv->fMax, priv->fRate);
|
||||
priv->bRunFlag = false;
|
||||
|
||||
@@ -986,7 +1015,11 @@ int ORHVPSWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
{
|
||||
return EVControlWrapper(pCon,pSics,pData,argc,argv);
|
||||
}
|
||||
if (strcasecmp("send", argv[1]) == 0) {
|
||||
// MJL 17/9/08 implement a special command mode to make life easier
|
||||
// (otherwise there is a lot of tedious translation between hex/decimal and ASCII codes
|
||||
// due to the inability of the code to distinguish between ASCII and returned setting values)
|
||||
int is_cmd=(strcasecmp("cmd", argv[1]) == 0);
|
||||
if (is_cmd || strcasecmp("send", argv[1]) == 0) {
|
||||
char cmd[CMDLEN];
|
||||
int cmd_len;
|
||||
char rsp[CMDLEN];
|
||||
@@ -996,51 +1029,211 @@ int ORHVPSWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
/* Managers only */
|
||||
if (!SCMatchRights(pCon, usMugger))
|
||||
return 0;
|
||||
cmd[idx] = '\0';
|
||||
for (i = 2; i < argc; ++i) {
|
||||
int j, k;
|
||||
if (i > 2 && idx < CMDLEN)
|
||||
cmd[idx++] = ' ';
|
||||
for (j = 0; argv[i][j]; ++j) {
|
||||
if (argv[i][j] == '\\') {
|
||||
k = 0;
|
||||
if (isxdigit(argv[i][j+1]) && isxdigit(argv[i][j+2])) {
|
||||
if (argv[i][j+1] >= '0' && argv[i][j+1] <= '9')
|
||||
k = (argv[i][j+1] - '0') << 4;
|
||||
else if (argv[i][j+1] >= 'a' && argv[i][j+1] <= 'f')
|
||||
k = (argv[i][j+1] - 'a' + 10) << 4;
|
||||
else if (argv[i][j+1] >= 'A' && argv[i][j+1] <= 'F')
|
||||
k = (argv[i][j+1] - 'A' + 10) << 4;
|
||||
if (argv[i][j+2] >= '0' && argv[i][j+2] <= '9')
|
||||
k += (argv[i][j+2] - '0');
|
||||
else if (argv[i][j+2] >= 'a' && argv[i][j+2] <= 'f')
|
||||
k += (argv[i][j+2] - 'a' + 10);
|
||||
else if (argv[i][j+2] >= 'A' && argv[i][j+2] <= 'F')
|
||||
k += (argv[i][j+2] - 'A' + 10);
|
||||
j += 2;
|
||||
|
||||
if (argc<3)
|
||||
{
|
||||
SCWrite(pCon, "ERROR: Not enough arguments supplied", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *pcmdrspfmt=argv[2];
|
||||
if (is_cmd) // "cmd"
|
||||
{
|
||||
// In command mode, the third argument is normally a single letter command
|
||||
// and the remaining arguments are command parameters. For future expansion,
|
||||
// we also allow the third argument to be an explicit command/response format.
|
||||
// This is in format "<cmd>-<resp>" where the command and response fields
|
||||
// are format specifiers containing the required/expected ASCII letters
|
||||
// in the command, and the format specifiers '%s' (string),
|
||||
// '%d' (integer 0-255), , '%B' (a board name e.g. x0-y15),
|
||||
// '%P' (a pot name e.g. x0-y191), or '%A' (ack code as 'ACK'/'NAK').
|
||||
// Formats '%c' (a character) and '%x' (char as 2 hex digits) could be
|
||||
// added to the code if needed.
|
||||
// Note '%P' translates to/from a two-byte board number plus pot number.
|
||||
// Code '%A' only useable in response format.
|
||||
if (strlen(argv[2])==1)
|
||||
switch(*argv[2])
|
||||
{
|
||||
// All the known commands for the Ordela 21000N, at 9/08.
|
||||
// If more become available, add them here, or alternately
|
||||
// supply an appropriate command format string explicitly.
|
||||
case 'v': pcmdrspfmt="vz-%sz"; break; // Get firmware version
|
||||
case 'p': pcmdrspfmt="p%P%dz-%A"; break; // Set a pot value
|
||||
case 'P': pcmdrspfmt="P%Pz-P%P%dz"; break; // Get a pot value
|
||||
case 'h': pcmdrspfmt="h%dz-%A"; break; // Set HV voltage (also settable directly via the orhvps object)
|
||||
case 'H': pcmdrspfmt="Hz-H%dz"; break; // Get HV setting
|
||||
case 'd': pcmdrspfmt="dz-%A"; break; // Enter diagnostic mode (disables coincidence detection etc.)
|
||||
case 'D': pcmdrspfmt="Dz-D%dz"; break; // Check if in diagnostic mode
|
||||
case 'n': pcmdrspfmt="nz-%A"; break; // Exit diagnostic mode
|
||||
case 'b': pcmdrspfmt="b%Bz-%A"; break; // Disable a board
|
||||
case 'B': pcmdrspfmt="B%Bz-B%B%dz"; break; // Query if board disabled
|
||||
case 'l': pcmdrspfmt="l%Bz-%A"; break; // Re-enable a board
|
||||
case 'J': pcmdrspfmt="Jz-J%dz"; break; // Check jumper settings
|
||||
}
|
||||
// Prepare the command string
|
||||
char *pcmd=cmd;
|
||||
int nfmtspec=0;
|
||||
while(*pcmdrspfmt!='-')
|
||||
{
|
||||
if (*pcmdrspfmt=='\0')
|
||||
{
|
||||
SCWrite(pCon, "ERROR: Missing '-' separator in format string", eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
k = argv[i][j];
|
||||
if (idx < CMDLEN)
|
||||
cmd[idx++] = k;
|
||||
}
|
||||
if (idx < CMDLEN)
|
||||
cmd[idx] = '\0';
|
||||
cmd_len = idx;
|
||||
if (*pcmdrspfmt=='%') // format specifier
|
||||
{
|
||||
pcmdrspfmt++;
|
||||
if (++nfmtspec>argc-3)
|
||||
{
|
||||
SCWrite(pCon, "ERROR: Not enough arguments supplied for cmd", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v1,v2;
|
||||
switch(*pcmdrspfmt++)
|
||||
{
|
||||
case 's': // probably never used
|
||||
pcmd+=sprintf(pcmd,"%s",argv[nfmtspec+2]);
|
||||
break;
|
||||
case 'd':
|
||||
sscanf(argv[nfmtspec+2],"%d",&v1);
|
||||
pcmd+=sprintf(pcmd,"%c",(char)v1);
|
||||
break;
|
||||
case 'B':
|
||||
sscanf(argv[nfmtspec+2]+1,"%d",&v1);
|
||||
v1+=(v1>=8)*8; // 0-15-> 0-7 and 16-23
|
||||
v1+=(*argv[nfmtspec+2]=='y')*8; // y at 8-15 and 24-31
|
||||
pcmd+=sprintf(pcmd,"%c",v1);
|
||||
break;
|
||||
case 'P':
|
||||
sscanf(argv[nfmtspec+2]+1,"%d",&v1);
|
||||
v2=v1&0xF;
|
||||
v1>>=4;
|
||||
v1+=(v1>=8)*8;
|
||||
v1+=(*argv[nfmtspec+2]=='y')*8;
|
||||
pcmd+=sprintf(pcmd,"%c%c",v1,v2);
|
||||
break;
|
||||
// case 'A': is NOT supported - responses only!
|
||||
default: SCWrite(pCon, "ERROR: Unknown % specification in command format", eError); return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
*pcmd++=*pcmdrspfmt++; // Simple ASCII character that is part of command
|
||||
}
|
||||
pcmdrspfmt++; // skip over the '-' separator into the response format
|
||||
cmd_len=pcmd-cmd;
|
||||
}
|
||||
else // "send"
|
||||
{
|
||||
cmd[idx] = '\0';
|
||||
for (i = 2; i < argc; ++i) {
|
||||
int j, k;
|
||||
if (i > 2 && idx < CMDLEN)
|
||||
cmd[idx++] = ' ';
|
||||
for (j = 0; argv[i][j]; ++j) {
|
||||
if (argv[i][j] == '\\') {
|
||||
k = 0;
|
||||
if (isxdigit(argv[i][j+1]) && isxdigit(argv[i][j+2])) {
|
||||
if (argv[i][j+1] >= '0' && argv[i][j+1] <= '9')
|
||||
k = (argv[i][j+1] - '0') << 4;
|
||||
else if (argv[i][j+1] >= 'a' && argv[i][j+1] <= 'f')
|
||||
k = (argv[i][j+1] - 'a' + 10) << 4;
|
||||
else if (argv[i][j+1] >= 'A' && argv[i][j+1] <= 'F')
|
||||
k = (argv[i][j+1] - 'A' + 10) << 4;
|
||||
if (argv[i][j+2] >= '0' && argv[i][j+2] <= '9')
|
||||
k += (argv[i][j+2] - '0');
|
||||
else if (argv[i][j+2] >= 'a' && argv[i][j+2] <= 'f')
|
||||
k += (argv[i][j+2] - 'a' + 10);
|
||||
else if (argv[i][j+2] >= 'A' && argv[i][j+2] <= 'F')
|
||||
k += (argv[i][j+2] - 'A' + 10);
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
k = argv[i][j];
|
||||
if (idx < CMDLEN)
|
||||
cmd[idx++] = k;
|
||||
}
|
||||
if (idx < CMDLEN)
|
||||
cmd[idx] = '\0';
|
||||
cmd_len = idx;
|
||||
}
|
||||
}
|
||||
|
||||
rsp_len = CMDLEN;
|
||||
ORHV_SendReceive(priv, cmd, cmd_len, rsp, &rsp_len);
|
||||
idx = 0;
|
||||
for (i = 0; i < rsp_len && idx < CMDLEN - 1; ++i) {
|
||||
if (rsp[i] < 32 || rsp[i] > 126) {
|
||||
idx+=sprintf(&cmd[idx], "%02Xh", rsp[i]);
|
||||
int orhvsr_status=ORHV_SendReceive(priv, cmd, cmd_len, rsp, &rsp_len);
|
||||
|
||||
int error_in_cmd_rsp_parse=0;
|
||||
if (is_cmd) // "cmd" response
|
||||
{
|
||||
// Start parsing the response according to the format string.
|
||||
// If we don't get what we expect, set error_in_cmd_rsp_parse
|
||||
// so that the response is output in 'send' format.
|
||||
// Only output the parameters in the response format, not ASCII's
|
||||
char *pcmd=cmd; // reformat rsp string into cmd string
|
||||
char *prsp=rsp;
|
||||
int got_fmt_rsp=0;
|
||||
while (*pcmdrspfmt&&!error_in_cmd_rsp_parse)
|
||||
{
|
||||
if (prsp-rsp>=rsp_len)
|
||||
error_in_cmd_rsp_parse=1; // response is too short - no bytes left to parse
|
||||
else if (*pcmdrspfmt=='%') // Parse byte(s)
|
||||
{
|
||||
pcmdrspfmt++;
|
||||
if (got_fmt_rsp)
|
||||
*pcmd++=' '; // separate response fields with spaces (Tcl list can separate these)
|
||||
int slen;
|
||||
switch(*pcmdrspfmt++)
|
||||
{
|
||||
case 's':
|
||||
pcmd+=(slen=sprintf(pcmd,"%s",prsp));
|
||||
*--pcmd='\0'; // string should have been terminated (with a 'z') but that gets checked later
|
||||
prsp+=slen-1;
|
||||
break;
|
||||
case 'd':
|
||||
pcmd+=sprintf(pcmd,"%d",*prsp++);
|
||||
break;
|
||||
case 'B':
|
||||
pcmd+=sprintf(pcmd,"%c%d",(prsp[0]&0x8)?'y':'x',(prsp[0]&0x7)+((prsp[0]&0x10)>>1));
|
||||
prsp++;
|
||||
break;
|
||||
case 'P':
|
||||
if (rsp_len-(prsp-rsp)<2)
|
||||
error_in_cmd_rsp_parse=1;
|
||||
else
|
||||
{
|
||||
pcmd+=sprintf(pcmd,"%c%d",(prsp[0]&0x8)?'y':'x',(prsp[0]&0x7)*0x10+(prsp[0]&0x10)*0x8+prsp[1]);
|
||||
prsp+=2;
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
error_in_cmd_rsp_parse|=(prsp[0]!=0x06&&prsp[0]!=0x15);
|
||||
pcmd+=sprintf(pcmd,"%s",(prsp[0]==0x06)?"ACK":"NAK");
|
||||
prsp++;
|
||||
break;
|
||||
default: SCWrite(pCon, "ERROR: Unknown % specification in response format", eError); return 0;
|
||||
}
|
||||
got_fmt_rsp=1;
|
||||
}
|
||||
else // expected ASCII characters in response have to match response format
|
||||
error_in_cmd_rsp_parse|=(*prsp++!=*pcmdrspfmt++);
|
||||
}
|
||||
else
|
||||
cmd[idx++] = rsp[i];
|
||||
}
|
||||
if (idx < CMDLEN)
|
||||
cmd[idx++] = '\0';
|
||||
if (!is_cmd||error_in_cmd_rsp_parse) // "send" response, or a "cmd" response that didn't match expected format
|
||||
{
|
||||
idx = 0;
|
||||
if (error_in_cmd_rsp_parse)
|
||||
idx=sprintf(cmd,"ERROR: Bad response format: ");
|
||||
for (i = 0; i < rsp_len && idx < CMDLEN - 1; ++i) {
|
||||
if (rsp[i] < 32 || rsp[i] > 126) {
|
||||
idx+=sprintf(&cmd[idx], "%02Xh", rsp[i]);
|
||||
}
|
||||
else
|
||||
cmd[idx++] = rsp[i];
|
||||
}
|
||||
if (idx < CMDLEN)
|
||||
cmd[idx++] = '\0';
|
||||
}
|
||||
SCWrite(pCon, cmd, eValue);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user