Added support for an addition Pause, Status and MsgTxt field to the EL737 scaler driver

This commit is contained in:
2017-07-24 09:45:57 +02:00
parent 9c507a05ba
commit 7263a0772f
5 changed files with 191 additions and 26 deletions

View File

@ -15,7 +15,7 @@ TEMPLATES += sinqEPICSApp/Db/dimetix.db
TEMPLATES += sinqEPICSApp/Db/slsvme.db TEMPLATES += sinqEPICSApp/Db/slsvme.db
TEMPLATES += sinqEPICSApp/Db/spsamor.db TEMPLATES += sinqEPICSApp/Db/spsamor.db
DBDS += sinq.dbd DBDS += sinqEPICSApp/src/sinq.dbd
# What we need at SINQ # What we need at SINQ
SOURCES += sinqEPICSApp/src/devScalerEL737.c SOURCES += sinqEPICSApp/src/devScalerEL737.c

View File

@ -0,0 +1,19 @@
record(bo,"$(P):Pause")
{
field(DTYP,"Soft Channel")
}
record(longin,"$(P):Status")
{
field(DTYP,"Soft Channel")
}
record(stringin,"$(P):MsgTxt")
{
field(DTYP,"Soft Channel")
}
record(scaler,"$(P)")
{
field(DESC,"$(DESC)")
field(DTYP,"asynScalerEL737")
field(OUT,"INST_IO @asyn($(PORT),0)")
}

View File

@ -19,7 +19,7 @@
* - Thresholding * - Thresholding
* - two count modes * - two count modes
* A better solution would be to extend the scalar record to have a proper status and count * A better solution would be to extend the scalar record to have a proper status and count
* mode field. And threshold control fileds too. But this is much more work, breaks * mode field. And threshold control fields too. But this is much more work, breaks
* compatability with the scalar record completely and thus was not done for now. * compatability with the scalar record completely and thus was not done for now.
* *
* The driver will run a separate thread which does all the * The driver will run a separate thread which does all the
@ -27,6 +27,10 @@
* *
* Mark Koennecke, February 2013 * Mark Koennecke, February 2013
* *
* Enhanced by adding an addtional external pause and status flag in the databse and code in here
* to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message.
*
* Mark Koennecke, July 2017
*/ */
#include <string.h> #include <string.h>
@ -40,6 +44,10 @@
#include <recSup.h> #include <recSup.h>
#include <devSup.h> #include <devSup.h>
#include <cantProceed.h> #include <cantProceed.h>
#include <dbDefs.h>
#include <dbFldTypes.h>
#include <dbAccess.h>
#include <errlog.h>
#include <scalerRecord.h> #include <scalerRecord.h>
#include <devScaler.h> #include <devScaler.h>
@ -89,12 +97,54 @@ typedef struct {
epicsEventId wakeUp; epicsEventId wakeUp;
asynUser *asynContext; asynUser *asynContext;
CALLBACK *pcallback; CALLBACK *pcallback;
DBADDR pause;
DBADDR status;
DBADDR msgTxt;
unsigned int dbInit;
}EL737priv; }EL737priv;
static void dummyAsynCallback(asynUser *pasynUser) static void dummyAsynCallback(asynUser *pasynUser)
{ {
} }
static void connectSlaveRecords(EL737priv *priv)
{
char slaveName[PVNAME_SZ], errName[256];
long status;
snprintf(slaveName,sizeof(slaveName),"%s:Pause", priv->psr->name);
errlogPrintf("Name of pause variable: %s\n", slaveName);
status = dbNameToAddr(slaveName,&priv->pause);
if(status!= 0){
errSymLookup(status,errName,sizeof(errName));
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
} else {
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->pause.precord->name);
}
snprintf(slaveName,sizeof(slaveName),"%s:MsgTxt", priv->psr->name);
errlogPrintf("Name of MsgTxt variable: %s\n", slaveName);
status = dbNameToAddr(slaveName,&priv->msgTxt);
if(status!= 0){
errSymLookup(status,errName,sizeof(errName));
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
} else {
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->msgTxt.precord->name);
}
snprintf(slaveName,sizeof(slaveName),"%s:Status", priv->psr->name);
errlogPrintf("Name of status variable: %s\n", slaveName);
status = dbNameToAddr(slaveName,&priv->status);
if(status!= 0){
errSymLookup(status,errName,sizeof(errName));
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
} else {
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->status.precord->name);
}
priv->dbInit = 1;
}
static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback) static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
{ {
EL737priv *priv = NULL; EL737priv *priv = NULL;
@ -122,8 +172,10 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
priv->psr = psr; priv->psr = psr;
priv->wakeUp = epicsEventCreate(epicsEventEmpty); priv->wakeUp = epicsEventCreate(epicsEventEmpty);
priv->pcallback = pcallback; priv->pcallback = pcallback;
priv->dbInit = 0;
psr->dpvt = priv; psr->dpvt = priv;
/* /*
* Hook up with device * Hook up with device
*/ */
@ -148,6 +200,8 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r")); pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r"));
priv->asynContext->timeout = 1.0; priv->asynContext->timeout = 1.0;
strcpy(command,"RMT 1"); strcpy(command,"RMT 1");
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,sizeof(reply), 1.,&out,&in,&reason);
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command), pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,sizeof(reply), 1.,&out,&in,&reason); reply,sizeof(reply), 1.,&out,&in,&reason);
strcpy(command,"ECHO 2"); strcpy(command,"ECHO 2");
@ -155,6 +209,7 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
reply,sizeof(reply), 1.,&out,&in,&reason); reply,sizeof(reply), 1.,&out,&in,&reason);
pasynManager->freeAsynUser(dummyUser); pasynManager->freeAsynUser(dummyUser);
connectSlaveRecords(priv);
/* /*
start the thread which actually runs the device start the thread which actually runs the device
@ -245,27 +300,57 @@ static long el737_done(scalerRecord *psr)
} }
} }
static asynStatus el737_transactCommand(asynUser *asynContext, char command[COMLEN],char reply[COMLEN]) static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],char reply[COMLEN])
{ {
asynStatus status; asynStatus status;
size_t in, out; size_t in, out;
int reason; int reason, dbStatus;
char myCommand[COMLEN]; char myCommand[COMLEN], message[40];
pasynOctetSyncIO->flush(asynContext); pasynOctetSyncIO->flush(priv->asynContext);
status = pasynOctetSyncIO->writeRead(asynContext, command, strlen(command), strcpy(message,"OK");
status = pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason); reply,COMLEN, 1.,&out,&in,&reason);
if(status == asynSuccess){ if(status == asynSuccess){
if(strstr(reply,"?OF") != NULL){ if(strstr(reply,"?OF") != NULL){
strcpy(myCommand,"RMT 1"); strcpy(myCommand,"RMT 1");
status = pasynOctetSyncIO->writeRead(asynContext, myCommand, strlen(myCommand), status = pasynOctetSyncIO->writeRead(priv->asynContext, myCommand, strlen(myCommand),
reply,COMLEN, 1.,&out,&in,&reason); reply,COMLEN, 1.,&out,&in,&reason);
strcpy(myCommand,"ECHO 2"); strcpy(myCommand,"ECHO 2");
status = pasynOctetSyncIO->writeRead(asynContext, myCommand, strlen(myCommand), status = pasynOctetSyncIO->writeRead(priv->asynContext, myCommand, strlen(myCommand),
reply,COMLEN, 1.,&out,&in,&reason); reply,COMLEN, 1.,&out,&in,&reason);
return pasynOctetSyncIO->writeRead(asynContext, command, strlen(command), return pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason); reply,COMLEN, 1.,&out,&in,&reason);
} else {
if(strstr(reply,"?OV") != NULL){
strncpy(message,"Overflow",sizeof(message));
} else if(strstr(reply,"?1") != NULL) {
strncpy(message,"Par out of range",sizeof(message));
} else if(strstr(reply,"?2") != NULL){
strncpy(message,"Bad command",sizeof(message));
} else if(strstr(reply,"?3") != NULL){
strncpy(message,"Bad parameter",sizeof(message));
} else if(strstr(reply,"?4") != NULL){
strncpy(message,"Bad counter",sizeof(message));
} else if(strstr(reply,"?5") != NULL){
strncpy(message,"Parameter missing",sizeof(message));
} else if(strstr(reply,"?6") != NULL){
strncpy(message,"to many counts",sizeof(message));
} else {
if(strstr(reply,"?") != NULL) {
snprintf(message,sizeof(message),"HW error: %s", reply);
}
}
}
} else {
strncpy(message,"Lost communication",sizeof(message));
}
if(priv->dbInit){
dbStatus = dbPutField(&priv->msgTxt, DBR_STRING,message, 1);
if(dbStatus!= 0){
errSymLookup(dbStatus,message,sizeof(message));
errlogPrintf("Setting external count message failed with %s\n", message);
} }
} }
return status; return status;
@ -276,7 +361,7 @@ static asynStatus sendStop(EL737priv *priv)
char command[COMLEN], reply[COMLEN]; char command[COMLEN], reply[COMLEN];
//errlogPrintf("Sending stop\n"); //errlogPrintf("Sending stop\n");
strcpy(command,"S"); strcpy(command,"S");
return el737_transactCommand(priv->asynContext,command,reply); return el737_transactCommand(priv,command,reply);
} }
static void runEvents(EL737priv *priv) static void runEvents(EL737priv *priv)
@ -288,9 +373,9 @@ static void runEvents(EL737priv *priv)
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON], sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
(int)priv->presets[THRESHVAL]); (int)priv->presets[THRESHVAL]);
//errlogPrintf("Sending threshold command %s\n", command); //errlogPrintf("Sending threshold command %s\n", command);
status = el737_transactCommand(priv->asynContext,command,reply); status = el737_transactCommand(priv,command,reply);
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]); sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
status = el737_transactCommand(priv->asynContext,command,reply); status = el737_transactCommand(priv, command,reply);
if(status == asynSuccess){ if(status == asynSuccess){
priv->sendThreshold = 0; priv->sendThreshold = 0;
} }
@ -307,7 +392,7 @@ static void runEvents(EL737priv *priv)
sprintf(command,"TP %f", priv->presets[TIMER]/1000.); sprintf(command,"TP %f", priv->presets[TIMER]/1000.);
//errlogPrintf("Starting preset timer\n"); //errlogPrintf("Starting preset timer\n");
} }
status = el737_transactCommand(priv->asynContext,command,reply); status = el737_transactCommand(priv,command,reply);
if(status == asynSuccess){ if(status == asynSuccess){
priv->counting = 1; priv->counting = 1;
} }
@ -335,7 +420,7 @@ static void updateValues(EL737priv *priv)
long m1, m2 ,m3, m4, m5, m6 ,m7, m8; long m1, m2 ,m3, m4, m5, m6 ,m7, m8;
strcpy(command,"RA"); strcpy(command,"RA");
status = el737_transactCommand(priv->asynContext,command,reply); status = el737_transactCommand(priv,command,reply);
if(status != asynSuccess){ if(status != asynSuccess){
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n", errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
priv->asynContext->errorMessage); priv->asynContext->errorMessage);
@ -371,9 +456,10 @@ static void el737Thread(void *param)
EL737priv *priv = (EL737priv *)param; EL737priv *priv = (EL737priv *)param;
epicsEventWaitStatus evStatus; epicsEventWaitStatus evStatus;
double timeout = 60.; double timeout = 60.;
char command[COMLEN], reply[COMLEN]; char command[COMLEN], reply[COMLEN], errName[256];
asynStatus status; asynStatus status;
int rs; int rs, ctStatus;
long dbStatus, options, nElements = 1, pauseFlag = 0;
//errlogPrintf("Within EL737 thread \n"); //errlogPrintf("Within EL737 thread \n");
@ -381,6 +467,7 @@ static void el737Thread(void *param)
evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout); evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout);
//errlogPrintf("EL737 thread woke up with %d\n", evStatus); //errlogPrintf("EL737 thread woke up with %d\n", evStatus);
if(evStatus == epicsEventWaitOK) { if(evStatus == epicsEventWaitOK) {
/* /*
FEAR: we received a command!!!! FEAR: we received a command!!!!
@ -402,7 +489,7 @@ static void el737Thread(void *param)
if(priv->counting) { if(priv->counting) {
strcpy(command,"RS"); strcpy(command,"RS");
status = el737_transactCommand(priv->asynContext,command,reply); status = el737_transactCommand(priv, command,reply);
if(status != asynSuccess){ if(status != asynSuccess){
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n", errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
priv->asynContext->errorMessage); priv->asynContext->errorMessage);
@ -414,15 +501,57 @@ static void el737Thread(void *param)
priv->counting = 0; priv->counting = 0;
timeout = 60.; timeout = 60.;
priv->values[9] = 0; priv->values[9] = 0;
ctStatus = 0;
} else if(rs == 1 || rs == 2){ } else if(rs == 1 || rs == 2){
/* counting */ /* counting */
priv->values[9] = 1; priv->values[9] = 1;
ctStatus = 1;
} else if(rs == 5 || rs == 6){ } else if(rs == 5 || rs == 6){
/* low rate */ /* low rate */
priv->values[9] = 2; priv->values[9] = 2;
ctStatus = 2;
} else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){ } else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){
/* low rate */ /* paused states */
priv->values[9] = 2; priv->values[9] = 3;
ctStatus = 3;
}
}
if(priv->dbInit){
/*
update the external status field
*/
dbStatus = dbPutField(&priv->status, DBR_LONG,&ctStatus, 1);
if(dbStatus!= 0){
errSymLookup(dbStatus,errName,sizeof(errName));
errlogPrintf("Setting external count status failed with %s\n", errName);
}
/*
check and handle pause flag
*/
dbStatus = dbGetField(&priv->pause, DBR_LONG,&pauseFlag,&options, &nElements, NULL);
if(dbStatus!= 0){
errSymLookup(dbStatus,errName,sizeof(errName));
errlogPrintf("Reading pauseFlag failed with %s\n", errName);
}
/* errlogPrintf("Successfully read %ld pause flags as %d\n",nElements, pauseFlag); */
if(pauseFlag == 1 && ctStatus == 1){
strcpy(command,"PS");
status = el737_transactCommand(priv, command,reply);
if(status != asynSuccess){
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
priv->asynContext->errorMessage);
break;
}
} else if(pauseFlag == 0 && ctStatus == 3){
strcpy(command,"CO");
status = el737_transactCommand(priv,command,reply);
if(status != asynSuccess){
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
priv->asynContext->errorMessage);
break;
}
} }
} }

View File

@ -1,9 +1,19 @@
record(scaler,"") record(bo,"$(P):Pause")
{ {
field(NAME,"NZ:counter") field(DTYP,"Soft Channel")
field(DESC,"NARZIS EL737 counter") }
field(DTYP,"asynScalerEL737") record(longin,"$(P):Status")
field(OUT,"INST_IO @asyn(cter1,0)") {
field(DTYP,"Soft Channel")
}
record(stringin,"$(P):MsgTxt")
{
field(DTYP,"Soft Channel")
}
record(scaler,"$(P)")
{
field(DESC,"$(DESC)")
field(DTYP,"asynScalerEL737")
field(OUT,"INST_IO @asyn($(PORT),0)")
} }

7
testcter/startcter.cmd Normal file
View File

@ -0,0 +1,7 @@
require sinq,koennecke
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp")
drvAsynIPPortConfigure("cter1","localhost:62000",0,0,0)
dbLoadRecords("asynRecord.db","P=KM36:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("${TOP}/sinqEPICSApp/Db/el737Record.db","P=KM36:counter,PORT=cter1,DESC=KM36Counter")