From 7263a0772f8a8a902fb12c6d55eddc9319987185 Mon Sep 17 00:00:00 2001 From: koennecke Date: Mon, 24 Jul 2017 09:45:57 +0200 Subject: [PATCH] Added support for an addition Pause, Status and MsgTxt field to the EL737 scaler driver --- Makefile.RHEL7 | 2 +- sinqEPICSApp/Db/el737Record.db | 19 ++++ sinqEPICSApp/src/devScalerEL737.c | 167 ++++++++++++++++++++++++++---- sinqEPICSApp/src/el737Record.db | 22 ++-- testcter/startcter.cmd | 7 ++ 5 files changed, 191 insertions(+), 26 deletions(-) create mode 100644 sinqEPICSApp/Db/el737Record.db create mode 100644 testcter/startcter.cmd diff --git a/Makefile.RHEL7 b/Makefile.RHEL7 index 2228343..2c2374c 100644 --- a/Makefile.RHEL7 +++ b/Makefile.RHEL7 @@ -15,7 +15,7 @@ TEMPLATES += sinqEPICSApp/Db/dimetix.db TEMPLATES += sinqEPICSApp/Db/slsvme.db TEMPLATES += sinqEPICSApp/Db/spsamor.db -DBDS += sinq.dbd +DBDS += sinqEPICSApp/src/sinq.dbd # What we need at SINQ SOURCES += sinqEPICSApp/src/devScalerEL737.c diff --git a/sinqEPICSApp/Db/el737Record.db b/sinqEPICSApp/Db/el737Record.db new file mode 100644 index 0000000..d11f8ea --- /dev/null +++ b/sinqEPICSApp/Db/el737Record.db @@ -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)") +} diff --git a/sinqEPICSApp/src/devScalerEL737.c b/sinqEPICSApp/src/devScalerEL737.c index 00a4ffc..3fdd123 100644 --- a/sinqEPICSApp/src/devScalerEL737.c +++ b/sinqEPICSApp/src/devScalerEL737.c @@ -19,7 +19,7 @@ * - Thresholding * - two count modes * 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. * * The driver will run a separate thread which does all the @@ -27,6 +27,10 @@ * * 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 @@ -40,6 +44,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -89,12 +97,54 @@ typedef struct { epicsEventId wakeUp; asynUser *asynContext; CALLBACK *pcallback; + DBADDR pause; + DBADDR status; + DBADDR msgTxt; + unsigned int dbInit; }EL737priv; 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) { EL737priv *priv = NULL; @@ -122,7 +172,9 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback) priv->psr = psr; priv->wakeUp = epicsEventCreate(epicsEventEmpty); priv->pcallback = pcallback; + priv->dbInit = 0; psr->dpvt = priv; + /* * Hook up with device @@ -148,6 +200,8 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback) pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r")); priv->asynContext->timeout = 1.0; 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), reply,sizeof(reply), 1.,&out,&in,&reason); strcpy(command,"ECHO 2"); @@ -155,6 +209,7 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback) reply,sizeof(reply), 1.,&out,&in,&reason); pasynManager->freeAsynUser(dummyUser); + connectSlaveRecords(priv); /* 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; size_t in, out; - int reason; - char myCommand[COMLEN]; + int reason, dbStatus; + 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); if(status == asynSuccess){ if(strstr(reply,"?OF") != NULL){ 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); 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); - return pasynOctetSyncIO->writeRead(asynContext, command, strlen(command), + return pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command), 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; @@ -276,7 +361,7 @@ static asynStatus sendStop(EL737priv *priv) char command[COMLEN], reply[COMLEN]; //errlogPrintf("Sending stop\n"); strcpy(command,"S"); - return el737_transactCommand(priv->asynContext,command,reply); + return el737_transactCommand(priv,command,reply); } static void runEvents(EL737priv *priv) @@ -288,9 +373,9 @@ static void runEvents(EL737priv *priv) sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON], (int)priv->presets[THRESHVAL]); //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]); - status = el737_transactCommand(priv->asynContext,command,reply); + status = el737_transactCommand(priv, command,reply); if(status == asynSuccess){ priv->sendThreshold = 0; } @@ -307,7 +392,7 @@ static void runEvents(EL737priv *priv) sprintf(command,"TP %f", priv->presets[TIMER]/1000.); //errlogPrintf("Starting preset timer\n"); } - status = el737_transactCommand(priv->asynContext,command,reply); + status = el737_transactCommand(priv,command,reply); if(status == asynSuccess){ priv->counting = 1; } @@ -335,7 +420,7 @@ static void updateValues(EL737priv *priv) long m1, m2 ,m3, m4, m5, m6 ,m7, m8; strcpy(command,"RA"); - status = el737_transactCommand(priv->asynContext,command,reply); + status = el737_transactCommand(priv,command,reply); if(status != asynSuccess){ errlogPrintf("devScalerEL737::el737Thread communication problem %s\n", priv->asynContext->errorMessage); @@ -371,9 +456,10 @@ static void el737Thread(void *param) EL737priv *priv = (EL737priv *)param; epicsEventWaitStatus evStatus; double timeout = 60.; - char command[COMLEN], reply[COMLEN]; + char command[COMLEN], reply[COMLEN], errName[256]; asynStatus status; - int rs; + int rs, ctStatus; + long dbStatus, options, nElements = 1, pauseFlag = 0; //errlogPrintf("Within EL737 thread \n"); @@ -381,6 +467,7 @@ static void el737Thread(void *param) evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout); //errlogPrintf("EL737 thread woke up with %d\n", evStatus); + if(evStatus == epicsEventWaitOK) { /* FEAR: we received a command!!!! @@ -402,7 +489,7 @@ static void el737Thread(void *param) if(priv->counting) { strcpy(command,"RS"); - status = el737_transactCommand(priv->asynContext,command,reply); + status = el737_transactCommand(priv, command,reply); if(status != asynSuccess){ errlogPrintf("devScalerEL737::el737Thread communication problem %s\n", priv->asynContext->errorMessage); @@ -414,15 +501,57 @@ static void el737Thread(void *param) priv->counting = 0; timeout = 60.; priv->values[9] = 0; + ctStatus = 0; } else if(rs == 1 || rs == 2){ /* counting */ priv->values[9] = 1; + ctStatus = 1; } else if(rs == 5 || rs == 6){ /* low rate */ priv->values[9] = 2; + ctStatus = 2; } else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){ - /* low rate */ - priv->values[9] = 2; + /* paused states */ + 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; + } } } diff --git a/sinqEPICSApp/src/el737Record.db b/sinqEPICSApp/src/el737Record.db index 3da0f9a..d11f8ea 100644 --- a/sinqEPICSApp/src/el737Record.db +++ b/sinqEPICSApp/src/el737Record.db @@ -1,9 +1,19 @@ -record(scaler,"") +record(bo,"$(P):Pause") { - field(NAME,"NZ:counter") - field(DESC,"NARZIS EL737 counter") - field(DTYP,"asynScalerEL737") - field(OUT,"INST_IO @asyn(cter1,0)") + 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)") } - diff --git a/testcter/startcter.cmd b/testcter/startcter.cmd new file mode 100644 index 0000000..22def9d --- /dev/null +++ b/testcter/startcter.cmd @@ -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")