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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user