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:
Ferdi Franceschini
2008-09-18 14:50:09 +10:00
committed by Douglas Clowes
parent 70f194fe85
commit 7919c7cd6a
2 changed files with 241 additions and 48 deletions

View File

@@ -793,7 +793,7 @@ int AsyncQueueAction(SConnection *pCon, SicsInterp *pSics,
return OKOK; return OKOK;
} }
else if (value == 1) { else if (value == 1) {
self->timeout = true; self->translate = true;
return OKOK; return OKOK;
} }
snprintf(line, 132, "Invalid argument: %s", argv[2]); snprintf(line, 132, "Invalid argument: %s", argv[2]);
@@ -802,7 +802,7 @@ int AsyncQueueAction(SConnection *pCon, SicsInterp *pSics,
} }
} }
else { else {
snprintf(line, 132, "%s.timeout = %d", argv[0], self->timeout); snprintf(line, 132, "%s.translate = %d", argv[0], self->translate);
SCWrite(pCon, line, eStatus); SCWrite(pCon, line, eStatus);
return OKOK; return OKOK;
} }

View File

@@ -107,7 +107,29 @@ static int ORHV_SendReceive(pORHVPSDriv priv,
int *rep_len) { int *rep_len) {
int status; 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) { if (status != 1) {
return FAILURE; return FAILURE;
@@ -680,7 +702,7 @@ static int ORHVPSSend(pEVDriver self, char *pCommand, char *pReply, int iLen) {
cmd[idx] = '\0'; cmd[idx] = '\0';
cmd_len = idx; cmd_len = idx;
rsp_len = CMDLEN; 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; idx = 0;
for (i = 0; i < rsp_len && idx < iLen - 1; ++i) { for (i = 0; i < rsp_len && idx < iLen - 1; ++i) {
if (rsp[i] < 32 || rsp[i] > 126) { 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.state_name = state_name;
priv->fsm.event_name = event_name; priv->fsm.event_name = event_name;
priv->name = strdup(argv[0]); 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->fRate = 10.0;
priv->fLower = 0.0; priv->fLower = 0.0; // fLower is 'low' safe voltage for driving - nominally 800V - but leave default at 0V for safety
priv->fUpper = 1800.0; priv->fUpper = 2350.0;
priv->iPeriod = get_period(priv->fMax, priv->fRate); priv->iPeriod = get_period(priv->fMax, priv->fRate);
priv->bRunFlag = false; priv->bRunFlag = false;
@@ -986,7 +1015,11 @@ int ORHVPSWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
{ {
return EVControlWrapper(pCon,pSics,pData,argc,argv); 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]; char cmd[CMDLEN];
int cmd_len; int cmd_len;
char rsp[CMDLEN]; char rsp[CMDLEN];
@@ -996,51 +1029,211 @@ int ORHVPSWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
/* Managers only */ /* Managers only */
if (!SCMatchRights(pCon, usMugger)) if (!SCMatchRights(pCon, usMugger))
return 0; return 0;
cmd[idx] = '\0';
for (i = 2; i < argc; ++i) { if (argc<3)
int j, k; {
if (i > 2 && idx < CMDLEN) SCWrite(pCon, "ERROR: Not enough arguments supplied", eError);
cmd[idx++] = ' '; return 0;
for (j = 0; argv[i][j]; ++j) { }
if (argv[i][j] == '\\') {
k = 0; char *pcmdrspfmt=argv[2];
if (isxdigit(argv[i][j+1]) && isxdigit(argv[i][j+2])) { if (is_cmd) // "cmd"
if (argv[i][j+1] >= '0' && argv[i][j+1] <= '9') {
k = (argv[i][j+1] - '0') << 4; // In command mode, the third argument is normally a single letter command
else if (argv[i][j+1] >= 'a' && argv[i][j+1] <= 'f') // and the remaining arguments are command parameters. For future expansion,
k = (argv[i][j+1] - 'a' + 10) << 4; // we also allow the third argument to be an explicit command/response format.
else if (argv[i][j+1] >= 'A' && argv[i][j+1] <= 'F') // This is in format "<cmd>-<resp>" where the command and response fields
k = (argv[i][j+1] - 'A' + 10) << 4; // are format specifiers containing the required/expected ASCII letters
if (argv[i][j+2] >= '0' && argv[i][j+2] <= '9') // in the command, and the format specifiers '%s' (string),
k += (argv[i][j+2] - '0'); // '%d' (integer 0-255), , '%B' (a board name e.g. x0-y15),
else if (argv[i][j+2] >= 'a' && argv[i][j+2] <= 'f') // '%P' (a pot name e.g. x0-y191), or '%A' (ack code as 'ACK'/'NAK').
k += (argv[i][j+2] - 'a' + 10); // Formats '%c' (a character) and '%x' (char as 2 hex digits) could be
else if (argv[i][j+2] >= 'A' && argv[i][j+2] <= 'F') // added to the code if needed.
k += (argv[i][j+2] - 'A' + 10); // Note '%P' translates to/from a two-byte board number plus pot number.
j += 2; // 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;
} }
} if (*pcmdrspfmt=='%') // format specifier
else {
k = argv[i][j]; pcmdrspfmt++;
if (idx < CMDLEN) if (++nfmtspec>argc-3)
cmd[idx++] = k; {
} SCWrite(pCon, "ERROR: Not enough arguments supplied for cmd", eError);
if (idx < CMDLEN) return 0;
cmd[idx] = '\0'; }
cmd_len = idx;
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; rsp_len = CMDLEN;
ORHV_SendReceive(priv, cmd, cmd_len, rsp, &rsp_len); int orhvsr_status=ORHV_SendReceive(priv, cmd, cmd_len, rsp, &rsp_len);
idx = 0;
for (i = 0; i < rsp_len && idx < CMDLEN - 1; ++i) { int error_in_cmd_rsp_parse=0;
if (rsp[i] < 32 || rsp[i] > 126) { if (is_cmd) // "cmd" response
idx+=sprintf(&cmd[idx], "%02Xh", rsp[i]); {
// 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) if (!is_cmd||error_in_cmd_rsp_parse) // "send" response, or a "cmd" response that didn't match expected format
cmd[idx++] = '\0'; {
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); SCWrite(pCon, cmd, eValue);
return 1; return 1;
} }