Initial commit of SINQ EPICS Application
This commit is contained in:
437
sinqEPICSApp/src/devScalerEL737.c
Normal file
437
sinqEPICSApp/src/devScalerEL737.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* 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 up to 64 channels of the scaler record will be used as such:
|
||||
* 1 = Time*1000
|
||||
* 2-9 monitor values
|
||||
* 10 extended status. Annotates rate low, paused conditions...
|
||||
*
|
||||
* The preset values are used as such:
|
||||
* 1 = Time*1000 or 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:
|
||||
* - 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
|
||||
* compatability with the scalar record completely and thus was not done for now.
|
||||
*
|
||||
* The driver will run a separate thread which does all the
|
||||
* communication.
|
||||
*
|
||||
* Mark Koennecke, February 2013
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <asynOctetSyncIO.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsTime.h>
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
#include <callback.h>
|
||||
#include <recSup.h>
|
||||
#include <devSup.h>
|
||||
#include <cantProceed.h>
|
||||
|
||||
#include <scalerRecord.h>
|
||||
#include <devScaler.h>
|
||||
#include <asynEpicsUtils.h>
|
||||
|
||||
|
||||
/* dset functions */
|
||||
static long el737_init_record(struct scalerRecord *psr, CALLBACK *pcallback);
|
||||
static long el737_reset(scalerRecord *psr);
|
||||
static long el737_read(scalerRecord *psr, 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);
|
||||
|
||||
/* thread function which runs the device */
|
||||
static void el737Thread(void *param);
|
||||
|
||||
#define MODE 1
|
||||
#define TIMER 0
|
||||
#define MONITOR 1
|
||||
#define THRESHMON 2
|
||||
#define THRESHVAL 3
|
||||
#define NCOUNT 10
|
||||
#define COMLEN 132
|
||||
|
||||
SCALERDSET devScalerEL737 = {
|
||||
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 int sendThreshold;
|
||||
scalerRecord *psr;
|
||||
epicsEventId wakeUp;
|
||||
asynUser *asynContext;
|
||||
CALLBACK *pcallback;
|
||||
}EL737priv;
|
||||
|
||||
static void dummyAsynCallback(asynUser *pasynUser)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL);
|
||||
if (status) {
|
||||
asynPrint(dummyUser, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to EL734 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 = 1.0;
|
||||
strcpy(command,"RMT 1");
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
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, unsigned long *val)
|
||||
{
|
||||
unsigned int i;
|
||||
EL737priv *priv;
|
||||
|
||||
priv = (EL737priv *)psr->dpvt;
|
||||
for(i = 0; i < NCOUNT; i++){
|
||||
val[i] = priv->values[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val)
|
||||
{
|
||||
EL737priv *priv;
|
||||
|
||||
//errlogPrintf("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("Setting threshold \n");
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long el737_arm(scalerRecord *psr, int val)
|
||||
{
|
||||
EL737priv *priv;
|
||||
|
||||
priv = (EL737priv *)psr->dpvt;
|
||||
priv->countCommand = val;
|
||||
|
||||
//errlogPrintf("Sending arm %d \n", val);
|
||||
|
||||
epicsEventSignal(priv->wakeUp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long el737_done(scalerRecord *psr)
|
||||
{
|
||||
EL737priv *priv;
|
||||
priv = (EL737priv *)psr->dpvt;
|
||||
|
||||
// errlogPrintf("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(asynUser *asynContext, char command[COMLEN],char reply[COMLEN])
|
||||
{
|
||||
asynStatus status;
|
||||
size_t in, out;
|
||||
int reason;
|
||||
char myCommand[COMLEN];
|
||||
|
||||
pasynOctetSyncIO->flush(asynContext);
|
||||
|
||||
status = pasynOctetSyncIO->writeRead(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),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
strcpy(myCommand,"ECHO 2");
|
||||
status = pasynOctetSyncIO->writeRead(asynContext, myCommand, strlen(myCommand),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
return pasynOctetSyncIO->writeRead(asynContext, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static asynStatus sendStop(EL737priv *priv)
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
//errlogPrintf("Sending stop\n");
|
||||
strcpy(command,"S");
|
||||
return el737_transactCommand(priv->asynContext,command,reply);
|
||||
}
|
||||
|
||||
static void runEvents(EL737priv *priv)
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
int status;
|
||||
|
||||
if(priv->sendThreshold == 1){
|
||||
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);
|
||||
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
|
||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
||||
if(status == asynSuccess){
|
||||
priv->sendThreshold = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//errlogPrintf("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("Starting preset monitor\n");
|
||||
} else {
|
||||
/* preset time */
|
||||
sprintf(command,"TP %f", priv->presets[TIMER]/1000.);
|
||||
//errlogPrintf("Starting preset timer\n");
|
||||
}
|
||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
||||
if(status == asynSuccess){
|
||||
priv->counting = 1;
|
||||
}
|
||||
} else {
|
||||
if(priv->counting) {
|
||||
/* Stop */
|
||||
status = sendStop(priv);
|
||||
} else {
|
||||
status = asynSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
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->asynContext,command,reply);
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
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];
|
||||
asynStatus status;
|
||||
int rs;
|
||||
|
||||
//errlogPrintf("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 = .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->asynContext,command,reply);
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
break;
|
||||
}
|
||||
sscanf(reply,"%d",&rs);
|
||||
//errlogPrintf("RS = %d\n", rs);
|
||||
if(rs == 0) {
|
||||
priv->counting = 0;
|
||||
timeout = 60.;
|
||||
priv->values[9] = 0;
|
||||
} else if(rs == 1 || rs == 2){
|
||||
/* counting */
|
||||
priv->values[9] = 1;
|
||||
} else if(rs == 5 || rs == 6){
|
||||
/* low rate */
|
||||
priv->values[9] = 2;
|
||||
} else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){
|
||||
/* low rate */
|
||||
priv->values[9] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
updateValues(priv);
|
||||
|
||||
if(rs == 0){
|
||||
callbackRequest(priv->pcallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user