diff --git a/Makefile.RHEL8 b/Makefile.RHEL8 index e3d02c2..0319be5 100644 --- a/Makefile.RHEL8 +++ b/Makefile.RHEL8 @@ -13,7 +13,7 @@ REQUIRED+=scaler REQUIRED+=asynMotor # Release version -LIBVERSION=2024-v2 +LIBVERSION=2024-ed-dev2 # DB files to include in the release TEMPLATES += sinqEPICSApp/Db/dimetix.db diff --git a/sinqEPICSApp/src/devScalerEL737.c b/sinqEPICSApp/src/devScalerEL737.c index e134237..d5d4441 100644 --- a/sinqEPICSApp/src/devScalerEL737.c +++ b/sinqEPICSApp/src/devScalerEL737.c @@ -1,8 +1,8 @@ /** - * scaler device support for the PSI EL737 counter box. + * scaler device support for the PSI EL737 counter box. * The EL737 has modes: preset timer, preset monitor. - * The EL7373 has also the option to set a threshold on a monitor. - * The EL737 has a maximum of 8 monitors which can be read. + * The EL7373 has also the option to set a threshold on a monitor. + * The EL737 has a maximum of 8 monitors which can be read. * The up to 64 channels of the scaler record will be used as such: * 1 = Time*1000 * 2-9 monitor values @@ -10,63 +10,63 @@ * * The preset values are used as such: * 1 = Time*1000 or preset monitor - * 2 = mode switch: 0 = preset time, > 0 preset monitor + * 2 = mode switch: 0 = preset time, > 0 preset monitor * 2 = threshold monitor * 3 = threshold monitor count * - * This is less then ideal. But it is a workaround for the fact that the scalar record - * does not do all the tricks the EL737 knows: + * This is less then ideal. But it is a workaround for the fact that the scalar + * record does not do all the tricks the EL737 knows: * - 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 fields too. But this is much more work, breaks - * compatability with the scalar record completely and thus was not done for now. + * A better solution would be to extend the scalar record to have a proper + * status and count 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 + * The driver will run a separate thread which does all the * communication. * * Mark Koennecke, February 2013 * - * Enhanced by adding an addtional external pause and status flag in the database and code in here - * to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message. + * Enhanced by adding an addtional external pause and status flag in the + * database 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 * - * Enhanced with a separate thresholdCounter and threshold field in order to replace the - * hack for threshold handling. If these fields are present, the hack with presets 2 and - * 3 as described above is ignored. + * Enhanced with a separate thresholdCounter and threshold field in order to + * replace the hack for threshold handling. If these fields are present, the + * hack with presets 2 and 3 as described above is ignored. * * Mark Koennecke, August 2017 */ -#include -#include -#include +#include #include -#include -#include -#include -#include -#include #include -#include -#include #include +#include #include #include -#include -#include - -#include #include -#include - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* dset functions */ static long el737_init_record(struct scalerRecord *psr, CALLBACK *pcallback); static long el737_reset(scalerRecord *psr); static long el737_read(scalerRecord *psr, epicsUInt32 *val); -static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val); +static long el737_write_preset(scalerRecord *psr, int signal, + unsigned long val); static long el737_arm(scalerRecord *psr, int val); static long el737_done(scalerRecord *psr); @@ -82,580 +82,587 @@ static void el737Thread(void *param); #define COMLEN 132 SCALERDSET devScalerEL737 = { - 7, - NULL, - NULL, - el737_init_record, - NULL, - el737_reset, - el737_read, - el737_write_preset, - el737_arm, - el737_done -}; + 7, NULL, NULL, el737_init_record, + NULL, el737_reset, el737_read, el737_write_preset, + el737_arm, el737_done}; epicsExportAddress(dset, devScalerEL737); typedef struct { - unsigned long presets[13]; - unsigned long values[NCOUNT]; - unsigned int countCommand; - unsigned int counting; - unsigned long thresholdValue; - unsigned int sendThreshold; - scalerRecord *psr; - epicsEventId wakeUp; - asynUser *asynContext; - CALLBACK *pcallback; - DBADDR pause; - DBADDR status; - DBADDR msgTxt; - DBADDR threshCounter; - DBADDR threshold; - unsigned int dbInit; -}EL737priv; + unsigned long presets[13]; + unsigned long values[NCOUNT]; + unsigned int countCommand; + unsigned int counting; + unsigned long thresholdValue; + unsigned int sendThreshold; + scalerRecord *psr; + epicsEventId wakeUp; + asynUser *asynContext; + CALLBACK *pcallback; + DBADDR pause; + DBADDR status; + DBADDR msgTxt; + DBADDR threshCounter; + DBADDR threshold; + unsigned int dbInit; +} EL737priv; -static void dummyAsynCallback([[maybe_unused]] asynUser *pasynUser) -{ -} +static void dummyAsynCallback([[maybe_unused]] asynUser *pasynUser) {} -static void connectSlaveRecords(EL737priv *priv) -{ - char slaveName[PVNAME_SZ + 18], errName[256]; - long status; +static void connectSlaveRecords(EL737priv *priv) { + char slaveName[PVNAME_SZ + 18], errName[256]; + long status; - priv->dbInit = 1; - 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); - priv->dbInit = 0; - } 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); - priv->dbInit = 0; - } 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); - priv->dbInit = 0; - } else { - errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->status.precord->name); - } - - snprintf(slaveName,sizeof(slaveName),"%s:ThresholdCounter", priv->psr->name); - errlogPrintf("Name of thresholdCounter variable: %s\n", slaveName); - status = dbNameToAddr(slaveName,&priv->threshCounter); - if(status!= 0){ - errSymLookup(status,errName,sizeof(errName)); - errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName); - priv->dbInit = 0; - } else { - errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->threshCounter.precord->name); - } - - snprintf(slaveName, sizeof(slaveName), "%s:Threshold", priv->psr->name); - errlogPrintf("Name of thresholdCounter variable: %s\n", slaveName); - status = dbNameToAddr(slaveName,&priv->threshold); - if(status!= 0){ - errSymLookup(status,errName,sizeof(errName)); - errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName); - priv->dbInit = 0; - } else { - errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->threshold.precord->name); - } - priv->thresholdValue = -999; -} - -static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback) -{ - EL737priv *priv = NULL; - char *port, *userParam; - int signal, status, reason; - size_t in, out; - asynUser *dummyUser; - char command[80], reply[80]; - - /** - * initalize record fields - */ - psr->nch = NCOUNT; - psr->g1 = scalerG1_Y; - psr->g2 = scalerG1_Y; - psr->g3 = scalerG1_Y; - psr->g4 = scalerG1_Y; - psr->freq = 1000; - psr->cont = scalerCONT_OneShot; - - /* - * private data structure - */ - priv = callocMustSucceed(1,sizeof(EL737priv), "devScalerEL737 init_record()"); - priv->psr = psr; - priv->wakeUp = epicsEventCreate(epicsEventEmpty); - priv->pcallback = pcallback; - priv->dbInit = 0; - psr->dpvt = priv; - - - /* - * Hook up with device - */ - dummyUser = pasynManager->createAsynUser(dummyAsynCallback,0); - status = pasynEpicsUtils->parseLink(dummyUser, &psr->out, - &port, &signal, &userParam); - if (status != asynSuccess) { - errlogPrintf("devScalerEL737::init_record %s bad link %s\n", - psr->name, dummyUser->errorMessage); - psr->pact = 1; - return 0; - } - pasynManager->autoConnect(dummyUser, 1); - status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL); - if (status) { - asynPrint(dummyUser, ASYN_TRACE_ERROR, - "%s: cannot connect to EL737 controller\n", - "el737_init_scaler"); - psr->pact = 1; - return 0; - } - pasynOctetSyncIO->setOutputEos(priv->asynContext,"\r",strlen("\r")); - pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r")); - priv->asynContext->timeout = 2.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"); - pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command), - reply,sizeof(reply), 1.,&out,&in,&reason); - pasynManager->freeAsynUser(dummyUser); - - connectSlaveRecords(priv); - - /* - start the thread which actually runs the device - */ - epicsThreadCreate("EL737", - epicsThreadPriorityMedium, - epicsThreadStackMedium, - el737Thread, - priv); - - //errlogPrintf("EL7373 thread started \n"); - return 0; -} - -static long el737_reset(scalerRecord *psr) -{ - unsigned int i; - EL737priv *priv; - - priv = (EL737priv *)psr->dpvt; - for(i = 0; i < NCOUNT; i++){ - priv->values[i] = 0; - } - return 0; -} - -static long el737_read(scalerRecord *psr, epicsUInt32 *val) -{ - unsigned int i; - EL737priv *priv; - - priv = (EL737priv *)psr->dpvt; - for(i = 0; i < NCOUNT; i++){ - val[i] = (epicsUInt32)priv->values[i]; - } - - return 0; -} - -static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val) -{ - EL737priv *priv; - - // errlogPrintf("EL737: Setting preset %d to %ld\n", signal, val); - - priv = (EL737priv *)psr->dpvt; - if(signal >= 0 && signal < 13){ - priv->presets[signal] = val; - } - if(signal == THRESHVAL){ - priv->sendThreshold = 1; - epicsEventSignal(priv->wakeUp); - // errlogPrintf("EL737: Setting threshold \n"); - - } - return 0; -} - -static long el737_arm(scalerRecord *psr, int val) -{ - EL737priv *priv; - - priv = (EL737priv *)psr->dpvt; - priv->countCommand = val; - - // errlogPrintf("EL737: Sending arm %d \n", val); - - epicsEventSignal(priv->wakeUp); - - return 0; -} - -static long el737_done(scalerRecord *psr) -{ - EL737priv *priv; - priv = (EL737priv *)psr->dpvt; - - // errlogPrintf("EL737: Calling done with %d\n", psr->cnt); - if(priv->counting && psr->cnt == 0){ - priv->countCommand = 0; - epicsEventSignal(priv->wakeUp); - } - - if(priv->counting || priv->countCommand == 1){ - return 1; - } else { - return 0; - } -} - -static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],char reply[COMLEN]) -{ - asynStatus status; - size_t in, out; - int reason, dbStatus; - char myCommand[COMLEN], message[40]; - - pasynOctetSyncIO->flush(priv->asynContext); - - // errlogPrintf("EL737: sending command %s\n", command); - - strcpy(message,""); - 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(priv->asynContext, myCommand, strlen(myCommand), - reply,COMLEN, 1.,&out,&in,&reason); - strcpy(myCommand,"ECHO 2"); - status = pasynOctetSyncIO->writeRead(priv->asynContext, myCommand, strlen(myCommand), - reply,COMLEN, 1.,&out,&in,&reason); - return pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command), - reply,COMLEN, 1.,&out,&in,&reason); + priv->dbInit = 1; + 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); + priv->dbInit = 0; } 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,"?91") != NULL){ - strncpy(message,"Start Failure",sizeof(message)); - } else if(strstr(reply,"?92") != NULL){ - strncpy(message,"Failure while counting",sizeof(message)); - } else if(strstr(reply,"?93") != NULL){ - strncpy(message,"Read Failure",sizeof(message)); - } else { - if(strstr(reply,"?") != NULL) { - snprintf(message,sizeof(message),"HW error: %s", reply); - } - } + errlogPrintf("dbNameToAddr succeded for %s, record access %s\n", + slaveName, priv->pause.precord->name); } - } else { - if(errno == EAGAIN){ - errlogPrintf("Lost response to %s with EAGAIN\n", command); + + 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); + priv->dbInit = 0; } else { - snprintf(message,sizeof(message), "Lost communication with errno %d", errno); - /* force a reconnect */ - pasynOctetSyncIO->disconnect(priv->asynContext); + errlogPrintf("dbNameToAddr succeded for %s, record access %s\n", + slaveName, priv->msgTxt.precord->name); } - } - 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); + + 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); + priv->dbInit = 0; + } else { + errlogPrintf("dbNameToAddr succeded for %s, record access %s\n", + slaveName, priv->status.precord->name); } - } - return status; + + snprintf(slaveName, sizeof(slaveName), "%s:ThresholdCounter", + priv->psr->name); + errlogPrintf("Name of thresholdCounter variable: %s\n", slaveName); + status = dbNameToAddr(slaveName, &priv->threshCounter); + if (status != 0) { + errSymLookup(status, errName, sizeof(errName)); + errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, + errName); + priv->dbInit = 0; + } else { + errlogPrintf("dbNameToAddr succeded for %s, record access %s\n", + slaveName, priv->threshCounter.precord->name); + } + + snprintf(slaveName, sizeof(slaveName), "%s:Threshold", priv->psr->name); + errlogPrintf("Name of thresholdCounter variable: %s\n", slaveName); + status = dbNameToAddr(slaveName, &priv->threshold); + if (status != 0) { + errSymLookup(status, errName, sizeof(errName)); + errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, + errName); + priv->dbInit = 0; + } else { + errlogPrintf("dbNameToAddr succeded for %s, record access %s\n", + slaveName, priv->threshold.precord->name); + } + priv->thresholdValue = -999; } -static asynStatus sendStop(EL737priv *priv) -{ - char command[COMLEN], reply[COMLEN]; - // errlogPrintf("EL737: Sending stop\n"); - strcpy(command,"S"); - return el737_transactCommand(priv,command,reply); -} +static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback) { + EL737priv *priv = NULL; + char *port, *userParam; + int signal, status, reason; + size_t in, out; + asynUser *dummyUser; + char command[80], reply[80]; -static void runEvents(EL737priv *priv) -{ - char command[COMLEN], reply[COMLEN], errName[256]; - int status; - long dbStatus, nElements = 1, options = 0, threshCounter; - long unsigned int myThreshold; + /** + * initalize record fields + */ + psr->nch = NCOUNT; + psr->g1 = scalerG1_Y; + psr->g2 = scalerG1_Y; + psr->g3 = scalerG1_Y; + psr->g4 = scalerG1_Y; + psr->freq = 1000; + psr->cont = scalerCONT_OneShot; - /* - This is the better way to set the threshold rather then the old way below which uses - presets for that function. This one uses separate fields. - */ - if(priv->dbInit == 1 && priv->sendThreshold) { - dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL); - if(dbStatus != 0){ - errSymLookup(dbStatus,errName,sizeof(errName)); - errlogPrintf("Reading threshold failed with %s\n", errName); - } else { - if(myThreshold != priv->thresholdValue){ - /* - we have to set the threshold - */ - dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL); - if(dbStatus != 0) { - errSymLookup(dbStatus,errName,sizeof(errName)); - errlogPrintf("Reading thresholdCounter failed with %s\n", errName); - } else { - if(threshCounter == 0){ - threshCounter = 1; - } - sprintf(command,"DL %d %d", (int)threshCounter, - (int)myThreshold); - // errlogPrintf("Sending threshold command %s\n", command); - status = el737_transactCommand(priv,command,reply); - sprintf(command,"DR %d", (int)threshCounter); - status = el737_transactCommand(priv, command,reply); - if(status == asynSuccess){ - priv->sendThreshold = 0; - priv->thresholdValue = myThreshold; - } - } - } - } - } - - if(priv->sendThreshold == 1) { - // fallback when we do not have the DB fields or threshCounter is invalid - if(priv->presets[THRESHMON] > 0) { - sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON], - (int)priv->presets[THRESHVAL]); - // errlogPrintf("Sending threshold from presets, command %s\n", command); - status = el737_transactCommand(priv,command,reply); - sprintf(command,"DR %d", (int)priv->presets[THRESHMON]); - status = el737_transactCommand(priv, command,reply); - if(status == asynSuccess) { - priv->sendThreshold = 0; - } - } - } - - errlogPrintf("EL737: Doing a count command: %d\n", priv->countCommand); - if(priv->countCommand == 1){ - if(priv->presets[MODE] > 0) { - /* preset monitor */ - sprintf(command,"MP %d", (int)priv->presets[MONITOR]); - // errlogPrintf("EL737: Starting preset monitor\n"); - } else { - /* preset time */ - sprintf(command,"TP %f", priv->presets[TIMER]/1000.); - // errlogPrintf("EL737: Starting preset timer\n"); - } - status = el737_transactCommand(priv,command,reply); - priv->counting = 1; - } else { - if(priv->counting) { - /* Stop */ - status = sendStop(priv); - } else { - status = asynSuccess; - } - } - - - if(status != asynSuccess){ - errlogPrintf("devScalerEL737::el737Thread communication problem %s\n, errno =%d", - priv->asynContext->errorMessage, errno); - } -} - -static void updateValues(EL737priv *priv) -{ - char command[COMLEN], reply[COMLEN]; - int status; - float fTime; - long m1, m2 ,m3, m4, m5, m6 ,m7, m8; - - strcpy(command,"RA"); - status = el737_transactCommand(priv,command,reply); - if(status != asynSuccess){ - if(errno == EAGAIN){ - errlogPrintf("devScalerEL737::el737Thread lost response to %s with EAGAIN\n", command); - } else { - errlogPrintf("devScalerEL737::el737Thread communication problem %s, errno = %d\n", - priv->asynContext->errorMessage, errno); - } - return; - } - status = sscanf(reply, "%f %ld %ld %ld %ld %ld %ld %ld %ld", - &fTime, &m1, &m2, &m3, &m4, &m5, &m6, &m7, &m8); - if (status != 9) { /* - old form with 4 monitors + * private data structure + */ + priv = + callocMustSucceed(1, sizeof(EL737priv), "devScalerEL737 init_record()"); + priv->psr = psr; + priv->wakeUp = epicsEventCreate(epicsEventEmpty); + priv->pcallback = pcallback; + priv->dbInit = 0; + psr->dpvt = priv; + + /* + * Hook up with device + */ + dummyUser = pasynManager->createAsynUser(dummyAsynCallback, 0); + status = pasynEpicsUtils->parseLink(dummyUser, &psr->out, &port, &signal, + &userParam); + if (status != asynSuccess) { + errlogPrintf("devScalerEL737::init_record %s bad link %s\n", psr->name, + dummyUser->errorMessage); + psr->pact = 1; + return 0; + } + pasynManager->autoConnect(dummyUser, 1); + status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL); + if (status) { + asynPrint(dummyUser, ASYN_TRACE_ERROR, + "%s: cannot connect to EL737 controller\n", + "el737_init_scaler"); + psr->pact = 1; + return 0; + } + pasynOctetSyncIO->setOutputEos(priv->asynContext, "\r", strlen("\r")); + pasynOctetSyncIO->setInputEos(priv->asynContext, "\r", strlen("\r")); + priv->asynContext->timeout = 2.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"); + pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command), + reply, sizeof(reply), 1., &out, &in, &reason); + pasynManager->freeAsynUser(dummyUser); + + connectSlaveRecords(priv); + + /* + start the thread which actually runs the device */ - status = sscanf(reply, "%ld %ld %ld %ld %f", &m1, &m2, &m3, &m4, &fTime); - if (status != 5) { - errlogPrintf("devScalerEL737::el737Thread bad RA reply %s\n", - reply); - return; - } - } - priv->values[0] = (long)(fTime*1000); - priv->values[1] = m1; - priv->values[2] = m2; - priv->values[3] = m3; - priv->values[4] = m4; - priv->values[5] = m5; - priv->values[6] = m6; - priv->values[7] = m7; - priv->values[8] = m8; - + epicsThreadCreate("EL737", epicsThreadPriorityMedium, + epicsThreadStackMedium, el737Thread, priv); + + // errlogPrintf("EL7373 thread started \n"); + return 0; } -static void el737Thread(void *param) -{ - EL737priv *priv = (EL737priv *)param; - epicsEventWaitStatus evStatus; - double timeout = 60.; - char command[COMLEN], reply[COMLEN], errName[256]; - asynStatus status; - int rs, ctStatus; - long dbStatus, options, nElements = 1, pauseFlag = 0; +static long el737_reset(scalerRecord *psr) { + unsigned int i; + EL737priv *priv; - // errlogPrintf("EL737: Within EL737 thread \n"); + priv = (EL737priv *)psr->dpvt; + for (i = 0; i < NCOUNT; i++) { + priv->values[i] = 0; + } + return 0; +} - while(1){ - evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout); - // errlogPrintf("EL737 thread woke up with %d\n", evStatus); +static long el737_read(scalerRecord *psr, epicsUInt32 *val) { + unsigned int i; + EL737priv *priv; - if(evStatus == epicsEventWaitOK) { - /* - FEAR: we received a command!!!! - */ - runEvents(priv); - if(priv->counting == 1){ - timeout = .2; - usleep(500); - } + priv = (EL737priv *)psr->dpvt; + for (i = 0; i < NCOUNT; i++) { + val[i] = (epicsUInt32)priv->values[i]; + } + + return 0; +} + +static long el737_write_preset(scalerRecord *psr, int signal, + unsigned long val) { + EL737priv *priv; + + // errlogPrintf("EL737: Setting preset %d to %ld\n", signal, val); + + priv = (EL737priv *)psr->dpvt; + if (signal >= 0 && signal < 13) { + priv->presets[signal] = val; + } + if (signal == THRESHVAL) { + priv->sendThreshold = 1; + epicsEventSignal(priv->wakeUp); + // errlogPrintf("EL737: Setting threshold \n"); + } + return 0; +} + +static long el737_arm(scalerRecord *psr, int val) { + EL737priv *priv; + + priv = (EL737priv *)psr->dpvt; + priv->countCommand = val; + + // errlogPrintf("EL737: Sending arm %d \n", val); + + epicsEventSignal(priv->wakeUp); + + return 0; +} + +static long el737_done(scalerRecord *psr) { + EL737priv *priv; + priv = (EL737priv *)psr->dpvt; + + // errlogPrintf("EL737: Calling done with %d\n", psr->cnt); + if (priv->counting && psr->cnt == 0) { + priv->countCommand = 0; + epicsEventSignal(priv->wakeUp); + } + + if (priv->counting || priv->countCommand == 1) { + return 1; } else { - /* - Just do a poll..... - */ - - if(priv->counting && priv->countCommand == 0) { - /* Stop */ - status = sendStop(priv); - } - - - if(priv->counting) { - strcpy(command,"RS"); - status = el737_transactCommand(priv, command,reply); - if(status != asynSuccess){ - errlogPrintf("devScalerEL737::el737Thread communication problem %s\n", - priv->asynContext->errorMessage); - continue; - } - sscanf(reply,"%d",&rs); - //errlogPrintf("RS = %d\n", rs); - if(rs == 0) { - 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){ - /* 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); - continue; - } - } 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); - continue; - } - } - } - - updateValues(priv); - - if(rs == 0){ - callbackRequest(priv->pcallback); - } + return 0; } - } } +static asynStatus el737_transactCommand(EL737priv *priv, char command[COMLEN], + char reply[COMLEN]) { + asynStatus status; + size_t in, out; + int reason, dbStatus; + char myCommand[COMLEN], message[40]; + + pasynOctetSyncIO->flush(priv->asynContext); + + // errlogPrintf("EL737: sending command %s\n", command); + + strcpy(message, ""); + 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( + priv->asynContext, myCommand, strlen(myCommand), reply, COMLEN, + 1., &out, &in, &reason); + strcpy(myCommand, "ECHO 2"); + status = pasynOctetSyncIO->writeRead( + priv->asynContext, myCommand, strlen(myCommand), reply, COMLEN, + 1., &out, &in, &reason); + 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, "?91") != NULL) { + strncpy(message, "Start Failure", sizeof(message)); + } else if (strstr(reply, "?92") != NULL) { + strncpy(message, "Failure while counting", sizeof(message)); + } else if (strstr(reply, "?93") != NULL) { + strncpy(message, "Read Failure", sizeof(message)); + } else { + if (strstr(reply, "?") != NULL) { + snprintf(message, sizeof(message), "HW error: %s", reply); + } + } + } + } else { + if (errno == EAGAIN) { + errlogPrintf("Lost response to %s with EAGAIN\n", command); + } else { + snprintf(message, sizeof(message), + "Lost communication with errno %d", errno); + /* force a reconnect */ + pasynOctetSyncIO->disconnect(priv->asynContext); + } + } + 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; +} + +static asynStatus sendStop(EL737priv *priv) { + char command[COMLEN], reply[COMLEN]; + // errlogPrintf("EL737: Sending stop\n"); + strcpy(command, "S"); + return el737_transactCommand(priv, command, reply); +} + +static void runEvents(EL737priv *priv) { + char command[COMLEN], reply[COMLEN], errName[256]; + int status; + long dbStatus, nElements = 1, options = 0, threshCounter; + long unsigned int myThreshold; + + /* + This is the better way to set the threshold rather then the old way below + which uses presets for that function. This one uses separate fields. + */ + if (priv->dbInit == 1 && priv->sendThreshold) { + dbStatus = dbGetField(&priv->threshold, DBR_LONG, &myThreshold, + &options, &nElements, NULL); + if (dbStatus != 0) { + errSymLookup(dbStatus, errName, sizeof(errName)); + errlogPrintf("Reading threshold failed with %s\n", errName); + } else { + if (myThreshold != priv->thresholdValue) { + /* + we have to set the threshold + */ + dbStatus = + dbGetField(&priv->threshCounter, DBR_LONG, &threshCounter, + &options, &nElements, NULL); + if (dbStatus != 0) { + errSymLookup(dbStatus, errName, sizeof(errName)); + errlogPrintf("Reading thresholdCounter failed with %s\n", + errName); + } else { + if (threshCounter == 0) { + threshCounter = 1; + } + sprintf(command, "DL %d %d", (int)threshCounter, + (int)myThreshold); + // errlogPrintf("Sending threshold command %s\n", command); + status = el737_transactCommand(priv, command, reply); + sprintf(command, "DR %d", (int)threshCounter); + status = el737_transactCommand(priv, command, reply); + if (status == asynSuccess) { + priv->sendThreshold = 0; + priv->thresholdValue = myThreshold; + } + } + } + } + } + + if (priv->sendThreshold == 1) { + // fallback when we do not have the DB fields or threshCounter is + // invalid + if (priv->presets[THRESHMON] > 0) { + sprintf(command, "DL %d %d", (int)priv->presets[THRESHMON], + (int)priv->presets[THRESHVAL]); + // errlogPrintf("Sending threshold from presets, command %s\n", + // command); + status = el737_transactCommand(priv, command, reply); + sprintf(command, "DR %d", (int)priv->presets[THRESHMON]); + status = el737_transactCommand(priv, command, reply); + if (status == asynSuccess) { + priv->sendThreshold = 0; + } + } + } + + errlogPrintf("EL737: Doing a count command: %d\n", priv->countCommand); + if (priv->countCommand == 1) { + if (priv->presets[MODE] > 0) { + /* preset monitor */ + sprintf(command, "MP %d", (int)priv->presets[MONITOR]); + // errlogPrintf("EL737: Starting preset monitor\n"); + } else { + /* preset time */ + sprintf(command, "TP %f", priv->presets[TIMER] / 1000.); + // errlogPrintf("EL737: Starting preset timer\n"); + } + status = el737_transactCommand(priv, command, reply); + priv->counting = 1; + } else { + if (priv->counting) { + /* Stop */ + status = sendStop(priv); + } else { + status = asynSuccess; + } + } + + if (status != asynSuccess) { + errlogPrintf( + "devScalerEL737::el737Thread communication problem %s\n, errno =%d", + priv->asynContext->errorMessage, errno); + } +} + +static void updateValues(EL737priv *priv) { + char command[COMLEN], reply[COMLEN]; + int status; + float fTime; + long m1, m2, m3, m4, m5, m6, m7, m8; + + strcpy(command, "RA"); + status = el737_transactCommand(priv, command, reply); + if (status != asynSuccess) { + if (errno == EAGAIN) { + errlogPrintf( + "devScalerEL737::el737Thread lost response to %s with EAGAIN\n", + command); + } else { + errlogPrintf("devScalerEL737::el737Thread communication problem " + "%s, errno = %d\n", + priv->asynContext->errorMessage, errno); + } + return; + } + status = sscanf(reply, "%f %ld %ld %ld %ld %ld %ld %ld %ld", &fTime, &m1, + &m2, &m3, &m4, &m5, &m6, &m7, &m8); + if (status != 9) { + /* + old form with 4 monitors + */ + status = + sscanf(reply, "%ld %ld %ld %ld %f", &m1, &m2, &m3, &m4, &fTime); + if (status != 5) { + errlogPrintf("devScalerEL737::el737Thread bad RA reply %s\n", + reply); + return; + } + } + priv->values[0] = (long)(fTime * 1000); + priv->values[1] = m1; + priv->values[2] = m2; + priv->values[3] = m3; + priv->values[4] = m4; + priv->values[5] = m5; + priv->values[6] = m6; + priv->values[7] = m7; + priv->values[8] = m8; +} + +static void el737Thread(void *param) { + EL737priv *priv = (EL737priv *)param; + epicsEventWaitStatus evStatus; + double timeout = 60.; + char command[COMLEN], reply[COMLEN], errName[256]; + asynStatus status; + int rs, ctStatus; + long dbStatus, options, nElements = 1, pauseFlag = 0; + + // errlogPrintf("EL737: Within EL737 thread \n"); + + while (1) { + evStatus = epicsEventWaitWithTimeout(priv->wakeUp, timeout); + // errlogPrintf("EL737 thread woke up with %d\n", evStatus); + + if (evStatus == epicsEventWaitOK) { + /* + FEAR: we received a command!!!! + */ + runEvents(priv); + if (priv->counting == 1) { + timeout = .2; + usleep(500); + } + } else { + /* + Just do a poll..... + */ + + if (priv->counting && priv->countCommand == 0) { + /* Stop */ + status = sendStop(priv); + } + + if (priv->counting) { + strcpy(command, "RS"); + status = el737_transactCommand(priv, command, reply); + if (status != asynSuccess) { + errlogPrintf("devScalerEL737::el737Thread communication " + "problem %s\n", + priv->asynContext->errorMessage); + continue; + } + sscanf(reply, "%d", &rs); + // errlogPrintf("RS = %d\n", rs); + if (rs == 0) { + 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) { + /* 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); + continue; + } + } 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); + continue; + } + } + } + + updateValues(priv); + + if (rs == 0) { + callbackRequest(priv->pcallback); + } + } + } +} diff --git a/sinqEPICSApp/src/el737Record.db b/sinqEPICSApp/src/el737Record.db index d11f8ea..0a80130 100644 --- a/sinqEPICSApp/src/el737Record.db +++ b/sinqEPICSApp/src/el737Record.db @@ -1,19 +1,21 @@ - record(bo,"$(P):Pause") { - field(DTYP,"Soft Channel") + field(DTYP,"Soft Channel") } + record(longin,"$(P):Status") { - field(DTYP,"Soft Channel") + field(DTYP,"Soft Channel") } + record(stringin,"$(P):MsgTxt") { - field(DTYP,"Soft Channel") + field(DTYP,"Soft Channel") } + record(scaler,"$(P)") { - field(DESC,"$(DESC)") - field(DTYP,"asynScalerEL737") - field(OUT,"INST_IO @asyn($(PORT),0)") + field(DESC,"$(DESC)") + field(DTYP,"asynScalerEL737") + field(OUT,"INST_IO @asyn($(PORT),0)") }