- Added missing file epicscounter.c
This commit is contained in:
435
epicscounter.c
Normal file
435
epicscounter.c
Normal file
@ -0,0 +1,435 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
This is a single counter implemented on top of EPICS slaer record.
|
||||
This is not general: In order to support the special features of a
|
||||
neutron counter, we use the scaler record in a special way.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, February 2013
|
||||
---------------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sics.h>
|
||||
#include <status.h>
|
||||
#include <countdriv.h>
|
||||
#include <counter.h>
|
||||
|
||||
/* EPICS stuff */
|
||||
#include <tsDefs.h>
|
||||
#include <cadef.h>
|
||||
#include <ezca.h>
|
||||
/* #include <alarmString.h>*/
|
||||
#include <menuAlarmStat.h>
|
||||
#include <db_access.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
/*------------------ our private data structure ------------------------*/
|
||||
typedef struct {
|
||||
char *rootName;
|
||||
int thresholdCounter;
|
||||
int thresholdValue;
|
||||
int thresholdChanged;
|
||||
char *ezcaError;
|
||||
int ezcaCode;
|
||||
int connectCount;
|
||||
} EPICSCounter, *pEPICSCounter;
|
||||
|
||||
|
||||
/*========================================================================
|
||||
These two functions currently rely on the idea that the EPICS stops
|
||||
and starts without clearing counters in between. The sequence of
|
||||
things necessary to start it, suggests this. If this is not the case then
|
||||
this will not work.
|
||||
===========================================================================*/
|
||||
static int EPICSPause(struct __COUNTER *self)
|
||||
{
|
||||
int status;
|
||||
pEPICSCounter pPriv = NULL;
|
||||
|
||||
/*
|
||||
not implemented
|
||||
*/
|
||||
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
/*=======================================================================*/
|
||||
static int EPICSContinue(struct __COUNTER *self)
|
||||
{
|
||||
int status;
|
||||
pEPICSCounter pPriv = NULL;
|
||||
|
||||
/*
|
||||
not implemented
|
||||
*/
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
/*=======================================================================*/
|
||||
static void CountHaltThreadFunc(void *param)
|
||||
{
|
||||
char *pvName = (char *)param;
|
||||
short stop = 0;
|
||||
chid cid;
|
||||
|
||||
ca_context_create(ca_disable_preemptive_callback);
|
||||
ca_create_channel(pvName,NULL,NULL,10,&cid);
|
||||
ca_pend_io(5.);
|
||||
ca_put(DBR_SHORT,cid,&stop);
|
||||
ca_pend_io(5.0);
|
||||
free(pvName);
|
||||
printf("HaltThread ends\n");
|
||||
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int EPICSHalt(struct __COUNTER *self)
|
||||
{
|
||||
int status;
|
||||
pEPICSCounter pPriv = NULL;
|
||||
char pvName[132];
|
||||
short stop = 0;
|
||||
|
||||
assert(self);
|
||||
pPriv = (pEPICSCounter) self->pData;
|
||||
assert(pPriv);
|
||||
|
||||
snprintf(pvName,sizeof(pvName),"%s.CNT", pPriv->rootName);
|
||||
/* ezcaPut(pvName,ezcaShort,1,&stop); */
|
||||
epicsThreadCreate("Lieselotte",
|
||||
epicsThreadPriorityHigh,
|
||||
epicsThreadStackMedium,
|
||||
CountHaltThreadFunc,
|
||||
(void *)strdup(pvName));
|
||||
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
/*=======================================================================*/
|
||||
static int EPICSTransfer(struct __COUNTER *self)
|
||||
{
|
||||
int status, i;
|
||||
pEPICSCounter priv = NULL;
|
||||
char pvName[132];
|
||||
long m;
|
||||
|
||||
assert(self);
|
||||
priv = (pEPICSCounter) self->pData;
|
||||
assert(priv);
|
||||
|
||||
/*
|
||||
load monitors
|
||||
*/
|
||||
for(i = 2; i < 10; i++){
|
||||
snprintf(pvName,sizeof(pvName),"%s.S%d",priv->rootName,i);
|
||||
status = ezcaGet(pvName,ezcaLong,1,&m);
|
||||
if(status == EZCA_OK) {
|
||||
self->lCounts[i-2] = m;
|
||||
} else {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
read time
|
||||
*/
|
||||
snprintf(pvName,sizeof(pvName),"%s.S1",priv->rootName);
|
||||
status = ezcaGet(pvName,ezcaLong,1,&m);
|
||||
if(status == EZCA_OK) {
|
||||
self->fTime = (float)m/1000.;
|
||||
} else {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int EPICSGetStatus(struct __COUNTER *self, float *fControl)
|
||||
{
|
||||
pEPICSCounter priv = (pEPICSCounter) self->pData;
|
||||
char pvName[132];
|
||||
short cnt;
|
||||
long m;
|
||||
int i, valChange = 0, status;
|
||||
|
||||
|
||||
assert(priv);
|
||||
|
||||
if((status = EPICSTransfer(self)) != OKOK){
|
||||
return status;
|
||||
}
|
||||
priv->connectCount = 0;
|
||||
if(self->eMode == eTimer){
|
||||
*fControl = self->fTime;
|
||||
} else {
|
||||
*fControl = (float)self->lCounts[1];
|
||||
}
|
||||
|
||||
/*
|
||||
read extended status
|
||||
*/
|
||||
snprintf(pvName,sizeof(pvName),"%s.S10",priv->rootName);
|
||||
status = ezcaGet(pvName,ezcaLong,1,&m);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
/*
|
||||
read cnt
|
||||
*/
|
||||
snprintf(pvName,sizeof(pvName),"%s.CNT",priv->rootName);
|
||||
status = ezcaGet(pvName,ezcaShort,1,&cnt);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
/*
|
||||
analyse status
|
||||
*/
|
||||
switch(m){
|
||||
case 0:
|
||||
if(cnt == 0){
|
||||
return HWIdle;
|
||||
} else {
|
||||
return HWBusy;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
return HWBusy;
|
||||
case 2:
|
||||
return HWNoBeam;
|
||||
case 3:
|
||||
return HWPause;
|
||||
default:
|
||||
/*
|
||||
bad status code form EPICS
|
||||
*/
|
||||
assert(1);
|
||||
}
|
||||
return HWFault;
|
||||
}
|
||||
/*-------------- dummy callback for Start -------------------------*/
|
||||
static void StartDummy(struct event_handler_args d)
|
||||
{
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int EPICSStart(struct __COUNTER *self)
|
||||
{
|
||||
pEPICSCounter priv = NULL;
|
||||
char pvName[132];
|
||||
int status, pr2;
|
||||
double dTime;
|
||||
long lPreset;
|
||||
short cnt = 1;
|
||||
chid *cid;
|
||||
|
||||
assert(self);
|
||||
priv = (pEPICSCounter) self->pData;
|
||||
assert(priv);
|
||||
|
||||
if(priv->thresholdChanged){
|
||||
snprintf(pvName,sizeof(pvName),"%s.PR3",priv->rootName);
|
||||
status = ezcaPut(pvName,ezcaLong,1,&priv->thresholdCounter);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
snprintf(pvName,sizeof(pvName),"%s.PR4",priv->rootName);
|
||||
status = ezcaPut(pvName,ezcaLong,1,&priv->thresholdValue);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
} else {
|
||||
priv->thresholdChanged = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(self->eMode == eTimer){
|
||||
dTime = self->fPreset;
|
||||
snprintf(pvName,sizeof(pvName),"%s.TP",priv->rootName);
|
||||
status = ezcaPut(pvName,ezcaDouble,1,&dTime);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
pr2 = 0;
|
||||
} else {
|
||||
snprintf(pvName,sizeof(pvName),"%s.PR1",priv->rootName);
|
||||
lPreset = (long)self->fPreset;
|
||||
status = ezcaPut(pvName,ezcaLong,1,&lPreset);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
pr2 = 10;
|
||||
}
|
||||
|
||||
snprintf(pvName,sizeof(pvName),"%s.PR2",priv->rootName);
|
||||
status = ezcaPut(pvName,ezcaLong,1,&pr2);
|
||||
if(status != EZCA_OK) {
|
||||
ezcaGetErrorString("ERROR: EPICS: ", &priv->ezcaError);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
snprintf(pvName,sizeof(pvName),"%s.CNT",priv->rootName);
|
||||
ezcaPvToChid(pvName,&cid);
|
||||
status = ca_put_callback(DBR_SHORT,*cid,&cnt, StartDummy,NULL);
|
||||
if(status != ECA_NORMAL){
|
||||
snprintf(pvName, sizeof(pvName),"Bad CA status %d", status);
|
||||
priv->ezcaError = strdup(pvName);
|
||||
priv->ezcaCode = status;
|
||||
return HWFault;
|
||||
} else {
|
||||
ca_pend_event(.05);
|
||||
priv->connectCount = 0;
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
/*======================================================================*/
|
||||
static int EPICSGetError(struct __COUNTER *self, int *iCode,
|
||||
char *errorText, int errlen)
|
||||
{
|
||||
char pBueffel[132];
|
||||
pEPICSCounter priv = NULL;
|
||||
|
||||
priv = (pEPICSCounter) self->pData;
|
||||
if(priv->ezcaError != NULL){
|
||||
strncpy(errorText,priv->ezcaError,errlen);
|
||||
ezcaFree(priv->ezcaError);
|
||||
priv->ezcaError = NULL;
|
||||
} else {
|
||||
strncpy(errorText,"Unknown error",errlen);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=======================================================================*/
|
||||
static int EPICSFixIt(struct __COUNTER *self, int iCode)
|
||||
{
|
||||
pEPICSCounter priv = NULL;
|
||||
|
||||
priv = (pEPICSCounter) self->pData;
|
||||
if(priv->ezcaCode == EZCA_NOTCONNECTED && priv->connectCount < 2) {
|
||||
priv->connectCount++;
|
||||
return COREDO;
|
||||
}
|
||||
return COTERM;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int EPICSSet(struct __COUNTER *self, char *name,
|
||||
int iCter, float fVal)
|
||||
{
|
||||
pEPICSCounter pPriv = NULL;
|
||||
int iVal;
|
||||
|
||||
assert(self);
|
||||
pPriv = (pEPICSCounter) self->pData;
|
||||
assert(pPriv);
|
||||
|
||||
if(strcmp(name,"threshold") == 0){
|
||||
pPriv->thresholdCounter = iCter;
|
||||
pPriv->thresholdValue = (int)fVal;
|
||||
pPriv->thresholdChanged = 1;
|
||||
return OKOK;
|
||||
} else {
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*===================================================================*/
|
||||
static int EPICSGet(struct __COUNTER *self, char *name,
|
||||
int iCter, float *fVal)
|
||||
{
|
||||
pEPICSCounter pPriv = NULL;
|
||||
|
||||
assert(self);
|
||||
pPriv = (pEPICSCounter) self->pData;
|
||||
assert(pPriv);
|
||||
|
||||
if(strcmp(name,"threshold") == 0){
|
||||
*fVal = pPriv->thresholdValue;
|
||||
return OKOK;
|
||||
} else {
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
|
||||
/*=====================================================================*/
|
||||
static int EPICSSend(struct __COUNTER *self, char *text,
|
||||
char *reply, int replylen)
|
||||
{
|
||||
strlcpy(reply, "EPICS does not feast on ASCII strings, refused!",
|
||||
replylen);
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
/*====================================================================*/
|
||||
pCounterDriver MakeEPICSCounter(char *rootname)
|
||||
{
|
||||
pEPICSCounter pPriv = NULL;
|
||||
pCounterDriver self = NULL;
|
||||
int i;
|
||||
char pvName[132];
|
||||
|
||||
|
||||
/*
|
||||
memory for everybody
|
||||
*/
|
||||
self = CreateCounterDriver("epics", "epics");
|
||||
pPriv = (pEPICSCounter) malloc(sizeof(EPICSCounter));
|
||||
if (self == NULL || pPriv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(pPriv, 0, sizeof(EPICSCounter));
|
||||
pPriv->thresholdChanged = 1;
|
||||
pPriv->rootName = strdup(rootname);
|
||||
|
||||
/*
|
||||
install monitors
|
||||
*/
|
||||
for(i = 1; i < 11; i++){
|
||||
snprintf(pvName,sizeof(pvName),"%s.S%d", rootname,i);
|
||||
ezcaSetMonitor(pvName,ezcaLong,1);
|
||||
}
|
||||
snprintf(pvName,sizeof(pvName),"%s.CNT", rootname);
|
||||
ezcaSetMonitor(pvName,ezcaShort,1);
|
||||
|
||||
/*
|
||||
assign function pointers
|
||||
*/
|
||||
self->GetStatus = EPICSGetStatus;
|
||||
self->Start = EPICSStart;
|
||||
self->Pause = EPICSPause;
|
||||
self->Continue = EPICSContinue;
|
||||
self->Halt = EPICSHalt;
|
||||
self->ReadValues = EPICSTransfer;
|
||||
self->GetError = EPICSGetError;
|
||||
self->TryAndFixIt = EPICSFixIt;
|
||||
self->Set = EPICSSet;
|
||||
self->Get = EPICSGet;
|
||||
self->Send = EPICSSend;
|
||||
self->KillPrivate = NULL;
|
||||
self->iNoOfMonitors = 8;
|
||||
|
||||
self->pData = pPriv;
|
||||
return self;
|
||||
}
|
Reference in New Issue
Block a user