Changed required privilege for chnaging the threshold from manager to user in counter.c Changed an output code in macro.c
1210 lines
33 KiB
C
1210 lines
33 KiB
C
/*-------------------------------------------------------------------------
|
|
|
|
C O U N T E R
|
|
|
|
The SICS Interface to a single detector and his associated
|
|
monitors.
|
|
|
|
|
|
Mark Koennecke, January 1997
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include "fortify.h"
|
|
#include <string.h>
|
|
#include "sics.h"
|
|
#include "countdriv.h"
|
|
#include "counter.h"
|
|
#include "fupa.h"
|
|
#include "status.h"
|
|
#include "splitter.h"
|
|
#include "site.h"
|
|
/*-------------------------------------------------------------------------*/
|
|
/*
|
|
The monitor callback data structure
|
|
*/
|
|
typedef struct {
|
|
float fPreset;
|
|
float fCurrent;
|
|
char *pName;
|
|
} MonEvent, *pMonEvent;
|
|
|
|
/*-----------------------------------------------------------------------------*/
|
|
static int Halt(void *pData)
|
|
{
|
|
pCounter self = NULL;
|
|
|
|
assert(pData);
|
|
self = (pCounter) pData;
|
|
|
|
return self->pDriv->Halt(self->pDriv);
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
static void SetCounterError(void *pData, char *text)
|
|
{
|
|
pCounter self = NULL;
|
|
|
|
assert(pData);
|
|
self = (pCounter) pData;
|
|
|
|
if(self->error != NULL){
|
|
free(self->error);
|
|
}
|
|
self->error = strdup(text);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static void SetCountParameters(void *pData, float fPreset,
|
|
CounterMode eMode)
|
|
{
|
|
pCounter self = NULL;
|
|
|
|
assert(pData);
|
|
self = (pCounter) pData;
|
|
|
|
SetCounterPreset(self, fPreset);
|
|
SetCounterMode(self, eMode);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int StartCount(void *pData, SConnection * pCon)
|
|
{
|
|
pCounter self;
|
|
char pBueffel[132];
|
|
char pError[80];
|
|
int iRet;
|
|
int i;
|
|
int iErr;
|
|
time_t tX;
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
|
|
if (!GetCountLock(self->pCountInt, pCon)) {
|
|
return 0;
|
|
}
|
|
|
|
SetCounterError(pData,"None");
|
|
/* try at least three times to do it */
|
|
for (i = 0; i < 3; i++) {
|
|
iRet = self->pDriv->Start(self->pDriv);
|
|
if (iRet == OKOK) {
|
|
self->isUpToDate = 0;
|
|
self->badStatusCount = 0;
|
|
self->tStart = time(&tX);
|
|
InvokeCallBack(self->pCall, COUNTSTART, pCon);
|
|
return iRet;
|
|
} else {
|
|
iRet = self->pDriv->GetError(self->pDriv, &iErr, pError, 79);
|
|
sprintf(pBueffel, "WARNING: %s ", pError);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
iRet = self->pDriv->TryAndFixIt(self->pDriv, iErr);
|
|
if (iRet == COTERM) {
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting",
|
|
eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
ReleaseCountLock(self->pCountInt);
|
|
SetCounterError(pData,pError);
|
|
return HWFault;
|
|
}
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting", eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
ReleaseCountLock(self->pCountInt);
|
|
return HWFault;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int PauseCount(void *pData, SConnection * pCon)
|
|
{
|
|
pCounter self;
|
|
char pBueffel[132];
|
|
char pError[80];
|
|
int iRet;
|
|
int i;
|
|
int iErr;
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
|
|
/* try at least three times to do it */
|
|
for (i = 0; i < 3; i++) {
|
|
iRet = self->pDriv->Pause(self->pDriv);
|
|
if (iRet == OKOK) {
|
|
self->isUpToDate = 0;
|
|
return iRet;
|
|
} else {
|
|
iRet = self->pDriv->GetError(self->pDriv, &iErr, pError, 79);
|
|
sprintf(pBueffel, "WARNING: %s ", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
iRet = self->pDriv->TryAndFixIt(self->pDriv, iErr);
|
|
if (iRet == COTERM) {
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting",
|
|
eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
return HWFault;
|
|
}
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting", eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
return HWFault;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int ContinueCount(void *pData, SConnection * pCon)
|
|
{
|
|
pCounter self;
|
|
char pBueffel[132];
|
|
char pError[80];
|
|
int iRet;
|
|
int i;
|
|
int iErr;
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
|
|
/* try at least three times to do it */
|
|
for (i = 0; i < 3; i++) {
|
|
iRet = self->pDriv->Continue(self->pDriv);
|
|
if (iRet == OKOK) {
|
|
self->isUpToDate = 0;
|
|
return iRet;
|
|
} else {
|
|
iRet = self->pDriv->GetError(self->pDriv, &iErr, pError, 79);
|
|
sprintf(pBueffel, "WARNING: %s ", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
iRet = self->pDriv->TryAndFixIt(self->pDriv, iErr);
|
|
if (iRet == COTERM) {
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting",
|
|
eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
return HWFault;
|
|
}
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting", eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
return HWFault;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static int TransferData(void *pData, SConnection * pCon)
|
|
{
|
|
pCounter self = NULL;
|
|
int i, iRet;
|
|
char pError[80];
|
|
char pBueffel[132];
|
|
int iCode;
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/* try three times */
|
|
for (i = 0; i < 3; i++) {
|
|
iRet = self->pDriv->ReadValues(self->pDriv);
|
|
if (iRet == OKOK) {
|
|
self->isUpToDate = 1;
|
|
return OKOK;
|
|
} else {
|
|
self->pDriv->GetError(self->pDriv, &iCode, pError, 79);
|
|
sprintf(pBueffel, "WARNING: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
iRet = self->pDriv->TryAndFixIt(self->pDriv, iCode);
|
|
if (iRet == COTERM) {
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting",
|
|
eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
SetCounterError(pData,pError);
|
|
return HWFault;
|
|
}
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting", eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
return HWFault;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int CheckCountStatus(void *pData, SConnection * pCon)
|
|
{
|
|
pCounter self = NULL;
|
|
int i, iRet;
|
|
int eCt;
|
|
char pError[80], pBueffel[132];
|
|
int iErr;
|
|
float fControl = .0, rate;
|
|
MonEvent sMon;
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
eCt = self->pDriv->GetStatus(self->pDriv, &fControl);
|
|
if (eCt == HWFault) {
|
|
self->badStatusCount++;
|
|
iRet = self->pDriv->GetError(self->pDriv, &iErr, pError, 79);
|
|
sprintf(pBueffel, "WARNING: %s ", pError);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
iRet = self->pDriv->TryAndFixIt(self->pDriv, iErr);
|
|
if (iRet == COTERM || self->badStatusCount > 3) {
|
|
SCWrite(pCon, "ERROR: Cannot fix counter problem, aborting", eError);
|
|
SCSetInterrupt(pCon, eAbortBatch);
|
|
InvokeCallBack(self->pCall, COUNTEND, NULL);
|
|
ReleaseCountLock(self->pCountInt);
|
|
SetCounterError(pData,pError);
|
|
return eCt;
|
|
} else {
|
|
return HWBusy;
|
|
}
|
|
}
|
|
|
|
/* if(self->pDriv->fTime > .0){ */
|
|
/* rate = (float)(self->pDriv->lCounts[1])/self->pDriv->fTime; */
|
|
/* if(rate > 10000){ */
|
|
/* SCWrite(pCon,"WARNING: Your control monitor is running into dead time", */
|
|
/* eLogError); */
|
|
/* } */
|
|
/* } */
|
|
|
|
/*
|
|
handle count parameters and notify listeners on progress
|
|
*/
|
|
sMon.fCurrent = fControl;
|
|
sMon.fPreset = self->pDriv->fPreset;
|
|
sMon.pName = self->name;
|
|
self->badStatusCount = 0; /* clear: we managed to read OK */
|
|
if (self->iCallbackCounter > 20) {
|
|
InvokeCallBack(self->pCall, MONITOR, &sMon);
|
|
tracePar(self->name,"control:%f", fControl);
|
|
self->iCallbackCounter = 0;
|
|
} else {
|
|
self->iCallbackCounter++;
|
|
}
|
|
self->pDriv->fLastCurrent = fControl;
|
|
|
|
/*
|
|
notification on finish
|
|
*/
|
|
if (eCt == HWIdle) {
|
|
self->isUpToDate = 0;
|
|
TransferData(self,pCon);
|
|
InvokeCallBack(self->pCall, COUNTEND, NULL);
|
|
ReleaseCountLock(self->pCountInt);
|
|
}
|
|
return eCt;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int SaveCounterStatus(void *pData, char *name, FILE * fd)
|
|
{
|
|
pCounter self = NULL;
|
|
|
|
assert(pData);
|
|
assert(fd);
|
|
|
|
self = (pCounter) pData;
|
|
|
|
fprintf(fd, "# Counter %s\n", name);
|
|
fprintf(fd, "%s SetPreset %f\n", name, self->pDriv->fPreset);
|
|
if (self->pDriv->eMode == eTimer) {
|
|
fprintf(fd, "%s SetMode Timer\n", name);
|
|
} else {
|
|
fprintf(fd, "%s SetMode Monitor\n", name);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static void *CounterGetInterface(void *pData, int iID)
|
|
{
|
|
pCounter self = NULL;
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
if (iID == COUNTID) {
|
|
return self->pCountInt;
|
|
} else if (iID == CALLBACKINTERFACE) {
|
|
return self->pCall;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void DeleteCounter(void *pData)
|
|
{
|
|
pCounter self = NULL;
|
|
|
|
assert(pData);
|
|
self = (pCounter) pData;
|
|
|
|
if (self->pDes) {
|
|
DeleteDescriptor(self->pDes);
|
|
}
|
|
|
|
if (self->pCountInt) {
|
|
free(self->pCountInt);
|
|
}
|
|
if (self->pCall) {
|
|
DeleteCallBackInterface(self->pCall);
|
|
}
|
|
|
|
if (self->name) {
|
|
free(self->name);
|
|
}
|
|
if (self->pDriv) {
|
|
DeleteCounterDriver(self->pDriv);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int DoCount(pCounter self, float fPreset, SConnection * pCon, int iBlock)
|
|
{
|
|
int iRet, level;
|
|
char pBueffel[132];
|
|
Status eOld;
|
|
|
|
assert(self);
|
|
|
|
/* check authorisation */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
sprintf(pBueffel, "ERROR: you are not authorised to count");
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* set Preset */
|
|
SetCounterPreset(self, fPreset);
|
|
|
|
if (iBlock == 0) {
|
|
level = RUNRUN;
|
|
} else {
|
|
level = RUNDRIVE;
|
|
}
|
|
iRet = StartDevice(GetExecutor(), self->name, self->pDes, self, pCon,
|
|
level, fPreset);
|
|
if (!iRet) {
|
|
SCWrite(pCon, "Counting aborted", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* continue only if in blocking mode, or from tas scan (iBlock == 2) */
|
|
if (iBlock != 1) {
|
|
return 1;
|
|
}
|
|
|
|
/* wait forever until done or interrupted */
|
|
iRet = Wait4Success(GetExecutor());
|
|
if (iRet == DEVINT) {
|
|
SCWrite(pCon, "Counting aborted due to Interrupt", eError);
|
|
} else if (iRet == DEVERROR) {
|
|
SCWrite(pCon, "Counting finished with Problems", eError);
|
|
iRet = 1;
|
|
} else {
|
|
SCWrite(pCon, "Counting finished", eValue);
|
|
iRet = 1;
|
|
}
|
|
return iRet;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int MakeCounter(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pCounter pNew = NULL;
|
|
pCounterDriver pDriv = NULL;
|
|
float fFail = -1;
|
|
int iRet;
|
|
char pBueffel[256];
|
|
pSite site = NULL;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
|
|
if (argc < 3) {
|
|
SCWrite(pCon, "ERROR: insuficient number of arguments to MakeCounter",
|
|
eError);
|
|
return 0;
|
|
}
|
|
strtolower(argv[1]);
|
|
strtolower(argv[2]);
|
|
site = getSite();
|
|
if (site != NULL) {
|
|
pDriv = site->CreateCounterDriver(pCon, argc, argv);
|
|
}
|
|
|
|
/*
|
|
test for simulation driver, which is for everybody
|
|
*/
|
|
if (strcmp(argv[2], "sim") == 0) {
|
|
if (argc > 3) {
|
|
fFail = atof(argv[3]);
|
|
pDriv = NewSIMCounter(argv[1], fFail);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* test for regression testing counter
|
|
*/
|
|
if (strcmp(argv[2], "regress") == 0) {
|
|
pDriv = NewRegressCounter(argv[1]);
|
|
}
|
|
|
|
/*
|
|
* test for McStas simulation counter driver
|
|
*/
|
|
if (strcmp(argv[2], "mcstas") == 0) {
|
|
pDriv = NewMcStasCounter(argv[1]);
|
|
}
|
|
|
|
if (!pDriv) {
|
|
snprintf(pBueffel,255, "ERROR: cannot create requested driver %s", argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* create Counter and command */
|
|
pNew = CreateCounter(argv[1], pDriv);
|
|
if (!pNew) {
|
|
snprintf(pBueffel, 255,"ERROR: cannot create counter %s", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
iRet =
|
|
AddCommand(pSics, argv[1], CountAction, DeleteCounter,
|
|
(void *) pNew);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,255, "ERROR: duplicate command %s not created", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------*/
|
|
int SetCounterMode(pCounter self, CounterMode eNew)
|
|
{
|
|
return self->setMode(self,eNew);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SetCounterModeImpl(pCounter self, CounterMode eNew)
|
|
{
|
|
int i;
|
|
|
|
assert(self);
|
|
if (eNew == self->pDriv->eMode) {
|
|
return 1;
|
|
}
|
|
|
|
if (eNew == eTimer) {
|
|
for (i = 0; i < self->iExponent; i++) {
|
|
self->pDriv->fPreset /= 10.;
|
|
}
|
|
tracePar(self->name,"mode:timer");
|
|
}
|
|
if (eNew == ePreset) {
|
|
for (i = 0; i < self->iExponent; i++) {
|
|
self->pDriv->fPreset *= 10.;
|
|
}
|
|
tracePar(self->name,"mode:monitor");
|
|
}
|
|
self->pDriv->eMode = eNew;
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
CounterMode GetCounterMode(pCounter self)
|
|
{
|
|
return self->getMode(self);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static CounterMode GetCounterModeImpl(pCounter self)
|
|
{
|
|
assert(self);
|
|
return self->pDriv->eMode;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int GetNMonitor(pCounter self)
|
|
{
|
|
return self->getNMonitor(self);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static int GetNMonitorImpl(pCounter self)
|
|
{
|
|
assert(self);
|
|
return self->pDriv->iNoOfMonitors;
|
|
}
|
|
|
|
int GetControlMonitor(pCounter self)
|
|
{
|
|
return self->pDriv->iControlMonitor;
|
|
}
|
|
|
|
int SetControlMonitor(pCounter self, int channel)
|
|
{
|
|
int maxchan = self->pDriv->iNoOfMonitors - 1;
|
|
if (channel < 0 || channel > maxchan) {
|
|
return 0;
|
|
}
|
|
self->pDriv->iControlMonitor = channel;
|
|
return 1;
|
|
}
|
|
|
|
#ifdef NONINTF
|
|
extern float nintf(float f);
|
|
#endif
|
|
/*------------------------------------------------------------------------*/
|
|
int SetCounterPreset(pCounter self, float fVal)
|
|
{
|
|
return self->setPreset(self,fVal);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static int SetCounterPresetImpl(pCounter self, float fVal)
|
|
{
|
|
int i;
|
|
|
|
assert(self);
|
|
|
|
if (fVal < .0) {
|
|
return 0;
|
|
}
|
|
if (GetCounterMode(self) == ePreset) {
|
|
for (i = 0; i < self->iExponent; i++) {
|
|
fVal *= 10.;
|
|
}
|
|
fVal = nintf(fVal);
|
|
}
|
|
self->pDriv->fPreset = fVal;
|
|
tracePar(self->name,"preset:%f", fVal);
|
|
|
|
return 1;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
float GetCounterPreset(pCounter self)
|
|
{
|
|
return self->getPreset(self);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
float GetControlValue(pCounter self)
|
|
{
|
|
return self->getControlValue(self);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static float GetControlValueImpl(pCounter self)
|
|
{
|
|
return self->pDriv->fLastCurrent;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static float GetCounterPresetImpl(pCounter self)
|
|
{
|
|
int i;
|
|
float fVal;
|
|
|
|
assert(self);
|
|
|
|
fVal = self->pDriv->fPreset;
|
|
if (self->pDriv->eMode == ePreset) {
|
|
for (i = 0; i < self->iExponent; i++) {
|
|
fVal /= 10.;
|
|
}
|
|
}
|
|
return fVal;
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
long GetCounts(pCounter self, SConnection * pCon)
|
|
{
|
|
return self->getCounts(self, pCon);
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
static long GetCountsImpl(pCounter self, SConnection * pCon)
|
|
{
|
|
assert(self);
|
|
if (!self->isUpToDate) {
|
|
self->pCountInt->TransferData(self, pCon);
|
|
}
|
|
return self->pDriv->lCounts[self->pDriv->iControlMonitor];
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
long GetMonitor(pCounter self, int iNum, SConnection * pCon)
|
|
{
|
|
return self->getMonitor(self, iNum, pCon);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static long GetMonitorImpl(pCounter self, int iNum, SConnection * pCon)
|
|
{
|
|
assert(self);
|
|
|
|
if (!self->isUpToDate) {
|
|
self->pCountInt->TransferData(self, pCon);
|
|
}
|
|
if ((iNum < 0) || (iNum >= self->pDriv->iNoOfMonitors)) {
|
|
return -1L;
|
|
} else {
|
|
return self->pDriv->lCounts[iNum];
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
void SetMonitorValue(pCounter self, int index, long value)
|
|
{
|
|
return self->setMonitor(self, index, value);
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
static void SetMonitorValueImpl(pCounter self, int index, long value)
|
|
{
|
|
assert(self);
|
|
|
|
if (index >= 0 && index < self->pDriv->iNoOfMonitors) {
|
|
self->pDriv->lCounts[index] = value;
|
|
}
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
float GetCountTime(pCounter self, SConnection * pCon)
|
|
{
|
|
return self->getTime(self, pCon);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static float GetCountTimeImpl(pCounter self, SConnection * pCon)
|
|
{
|
|
assert(self);
|
|
|
|
if (!self->isUpToDate) {
|
|
self->pCountInt->TransferData(self, pCon);
|
|
}
|
|
return self->pDriv->fTime;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
static int isAuthorised(SConnection * pCon, int iCode)
|
|
{
|
|
char pBueffel[132];
|
|
|
|
if (!SCMatchRights(pCon, iCode)) {
|
|
sprintf(pBueffel, "ERROR: you are not authorised to count");
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int CounterInterest(int iEvent, void *pEvent, void *pUser)
|
|
{
|
|
SConnection *pCon = NULL;
|
|
pMonEvent pMon = NULL;
|
|
char pBueffel[512];
|
|
int rights;
|
|
|
|
pCon = (SConnection *) pUser;
|
|
pMon = (pMonEvent) pEvent;
|
|
|
|
if (pCon == NULL || !SCisConnected(pCon)) {
|
|
return -1;
|
|
}
|
|
|
|
if (iEvent != MONITOR || pCon == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
snprintf(pBueffel,511, "%s.CountStatus = %f %d", pMon->pName, pMon->fPreset,
|
|
(int) nintf(pMon->fCurrent));
|
|
/**
|
|
* prevent this to be written to log files
|
|
*/
|
|
SCSetRights(pCon, usSpy);
|
|
SCWrite(pCon, pBueffel, eEvent);
|
|
return 1;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
pCounter CreateCounter(char *name, pCounterDriver pDriv)
|
|
{
|
|
pCounter pRes = NULL;
|
|
|
|
assert(pDriv);
|
|
|
|
pRes = (pCounter) malloc(sizeof(Counter));
|
|
if (!pRes) {
|
|
return NULL;
|
|
}
|
|
pRes->pDes = CreateDescriptor("SingleCounter");
|
|
if (!pRes->pDes) {
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
/* initialize Descriptor functions */
|
|
pRes->pDes->GetInterface = CounterGetInterface;
|
|
pRes->pDes->SaveStatus = SaveCounterStatus;
|
|
|
|
/* initialise countable interface */
|
|
pRes->pCountInt = CreateCountableInterface();
|
|
if (!pRes->pCountInt) {
|
|
DeleteDescriptor(pRes->pDes);
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->pCountInt->SetCountParameters = SetCountParameters;
|
|
pRes->pCountInt->StartCount = StartCount;
|
|
pRes->pCountInt->CheckCountStatus = CheckCountStatus;
|
|
pRes->pCountInt->TransferData = TransferData;
|
|
pRes->pCountInt->Halt = Halt;
|
|
pRes->pCountInt->Pause = PauseCount;
|
|
pRes->pCountInt->Continue = ContinueCount;
|
|
pRes->iCallbackCounter = 20;
|
|
|
|
pRes->setMode = SetCounterModeImpl;
|
|
pRes->getMode = GetCounterModeImpl;
|
|
pRes->getNMonitor = GetNMonitorImpl;
|
|
pRes->setPreset = SetCounterPresetImpl;
|
|
pRes->getPreset = GetCounterPresetImpl;
|
|
pRes->getControlValue = GetControlValueImpl;
|
|
pRes->getCounts = GetCountsImpl;
|
|
pRes->getMonitor = GetMonitorImpl;
|
|
pRes->setMonitor = SetMonitorValueImpl;
|
|
pRes->getTime = GetCountTimeImpl;
|
|
|
|
pRes->pCall = CreateCallBackInterface();
|
|
|
|
pRes->pDriv = pDriv;
|
|
pRes->isUpToDate = 1;
|
|
pRes->iExponent = 0;
|
|
pRes->name = strdup(name);
|
|
pRes->error = strdup("None");
|
|
return pRes;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
int CountAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pCounter self = NULL;
|
|
int iRet, iRet2, i;
|
|
FuPaResult PaRes;
|
|
char pBueffel[256], pError[80];
|
|
char **argx;
|
|
float fVal;
|
|
long lVal;
|
|
long lID;
|
|
CounterMode eMode;
|
|
FuncTemplate ActionTemplate[] = {
|
|
{"count", 1, {FUPAFLOAT}},
|
|
{"getpreset", 0, {0.0}},
|
|
{"setpreset", 1, {FUPAFLOAT}},
|
|
{"getmode", 0, {0, 0}},
|
|
{"setmode", 1, {FUPATEXT}},
|
|
{"getcounts", 0, {0, 0}},
|
|
{"getmonitor", 1, {FUPAINT, 0}},
|
|
{"setexponent", 1, {FUPAINT, 0}},
|
|
{"getexponent", 0, {0, 0}},
|
|
{"interest", 0, {0, 0}},
|
|
{"uninterest", 0, {0, 0}},
|
|
{"status", 0, {0, 0}},
|
|
{"gettime", 0, {0, 0}},
|
|
{"countnb", 1, {FUPAFLOAT}},
|
|
{"getthreshold", 1, {FUPAINT}},
|
|
{"setthreshold", 2, {FUPAINT, FUPAFLOAT}},
|
|
{"stop", 0, {0, 0}},
|
|
{"mode", 1, {FUPAOPT}},
|
|
{"preset", 1, {FUPAOPT}},
|
|
{"send", 0, {0, 0}},
|
|
{"setpar", 3, {FUPATEXT, FUPAINT, FUPAFLOAT}},
|
|
{"getpar", 2, {FUPATEXT, FUPAOPT}},
|
|
{"getnmon", 0, {0, 0}},
|
|
{"state", 0, {0, 0}},
|
|
{"error", 0, {0, 0}},
|
|
{"getchannel",0,{0}},
|
|
{"setchannel",1,{FUPAINT}},
|
|
{"countstatus", 0, {0, 0}}
|
|
};
|
|
char *pMode[] = {
|
|
"timer",
|
|
"monitor",
|
|
NULL
|
|
};
|
|
|
|
self = (pCounter) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
assert(pSics);
|
|
|
|
/* parse function args */
|
|
argtolower(argc, argv);
|
|
argx = &argv[1];
|
|
iRet =
|
|
EvaluateFuPa((pFuncTemplate) & ActionTemplate, 28, argc - 1, argx,
|
|
&PaRes);
|
|
if (iRet < 0) {
|
|
snprintf(pBueffel, 255,"%s", PaRes.pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* do something! */
|
|
switch (iRet) {
|
|
case 0: /* Count */
|
|
return DoCount(self, PaRes.Arg[0].fVal, pCon, 1);
|
|
break;
|
|
case 1: /* GetPreset */
|
|
fVal = GetCounterPreset(self);
|
|
sprintf(pBueffel, "%s.Preset = %f", argv[0], fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
break;
|
|
case 2: /* Set Preset */
|
|
if (isRunning(self->pCountInt)) {
|
|
SCWrite(pCon, "ERROR: cannot change preset while counting", eError);
|
|
return 0;
|
|
}
|
|
if (isAuthorised(pCon, usUser)) {
|
|
iRet2 = SetCounterPreset(self, PaRes.Arg[0].fVal);
|
|
SCparChange(pCon);
|
|
if (iRet2)
|
|
SCSendOK(pCon);
|
|
return iRet2;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
case 3: /* GetMode */
|
|
eMode = GetCounterMode(self);
|
|
if (eMode == eTimer) {
|
|
sprintf(pBueffel, "%s.Mode = Timer", argv[0]);
|
|
} else {
|
|
sprintf(pBueffel, "%s.Mode = Monitor", argv[0]);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
break;
|
|
case 4: /* Set Mode */
|
|
if (isRunning(self->pCountInt)) {
|
|
SCWrite(pCon, "ERROR: cannot change mode while counting", eError);
|
|
return 0;
|
|
}
|
|
if (isAuthorised(pCon, usUser)) {
|
|
if (strcmp(PaRes.Arg[0].text, "timer") == 0) {
|
|
SetCounterMode(self, eTimer);
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(PaRes.Arg[0].text, "monitor") == 0) {
|
|
SetCounterMode(self, ePreset);
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,255, "ERROR: %s not recognized as valid counter mode",
|
|
PaRes.Arg[0].text);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
case 5: /* GetCounts */
|
|
lVal = GetCounts(self, pCon);
|
|
sprintf(pBueffel, "%s.Counts = %ld", argv[0], lVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
|
|
case 6: /* GetMonitor */
|
|
lVal = GetMonitor(self, PaRes.Arg[0].iVal, pCon);
|
|
if (lVal < 0) {
|
|
sprintf(pBueffel, "ERROR: %d out of range for monitors",
|
|
PaRes.Arg[0].iVal);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
sprintf(pBueffel, "%s.Monitor %d = %ld", argv[0], PaRes.Arg[0].iVal,
|
|
lVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
case 7: /* SetExponent */
|
|
if (!SCMatchRights(pCon, usMugger)) {
|
|
return 0;
|
|
}
|
|
self->iExponent = PaRes.Arg[0].iVal;
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
case 8: /* GetExponent */
|
|
sprintf(pBueffel, "%s.Exponent = %d", argv[0], self->iExponent);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
case 9: /* interest */
|
|
lID = RegisterCallback(self->pCall, MONITOR, CounterInterest,
|
|
SCCopyConnection(pCon), SCDeleteConnection);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
case 10: /* uninterest */
|
|
RemoveCallbackCon(self->pCall, pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
case 11: /* status */
|
|
case 27:
|
|
self->pCountInt->TransferData(self, pCon);
|
|
if (GetCounterMode(self) == ePreset) {
|
|
lVal = GetCounterPreset(self);
|
|
for(i = 0; i < self->iExponent; i++){
|
|
lVal *= 10;
|
|
}
|
|
sprintf(pBueffel, "%s.CountStatus = %d %d Beam: %ld E6",
|
|
argv[0],
|
|
(int) nintf(lVal),
|
|
(int) nintf(GetControlValue(self)),
|
|
GetMonitor(self, 4, pCon) / 100000);
|
|
} else {
|
|
sprintf(pBueffel, "%s.CountStatus = %8.2f %8.2f Beam %ld E6",
|
|
argv[0],
|
|
self->pDriv->fPreset,
|
|
self->pDriv->fLastCurrent,
|
|
GetMonitor(self, 4, pCon) / 100000);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
case 12: /* gettime */
|
|
fVal = GetCountTime(self, pCon);
|
|
sprintf(pBueffel, "%s.CountTime = %f", argv[0], fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
case 13:
|
|
/* countnb, non blocking count */
|
|
return DoCount(self, PaRes.Arg[0].fVal, pCon, 0);
|
|
break;
|
|
case 14:
|
|
/* get threshold value */
|
|
iRet = self->pDriv->Get(self->pDriv, "threshold",
|
|
PaRes.Arg[0].iVal, &fVal);
|
|
if (iRet <= 0) {
|
|
self->pDriv->GetError(self->pDriv, &iRet, pError, 79);
|
|
sprintf(pBueffel, "ERROR: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
} else {
|
|
sprintf(pBueffel, "%s.threshold%1.1d = %f",
|
|
argv[0], PaRes.Arg[0].iVal, fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
break;
|
|
case 15:
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon,
|
|
"ERROR: Insufficient privilege to set threshold", eError);
|
|
return 0;
|
|
}
|
|
if (isRunning(self->pCountInt)) {
|
|
SCWrite(pCon,
|
|
"ERROR: cannot change threshold while counting",
|
|
eError);
|
|
return 0;
|
|
}
|
|
/* set threshold value */
|
|
iRet = self->pDriv->Set(self->pDriv, "threshold",
|
|
PaRes.Arg[0].iVal, PaRes.Arg[1].fVal);
|
|
if (iRet <= 0) {
|
|
self->pDriv->GetError(self->pDriv, &iRet, pError, 79);
|
|
sprintf(pBueffel, "ERROR: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
} else {
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
break;
|
|
case 16:
|
|
/* stop */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
return 0;
|
|
}
|
|
self->pCountInt->Halt(self);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
case 17:
|
|
/* mode */
|
|
if (PaRes.Arg[0].iVal) { /* set case */
|
|
if (isRunning(self->pCountInt)) {
|
|
SCWrite(pCon, "ERROR: cannot change mode while counting", eError);
|
|
return 0;
|
|
}
|
|
if (isAuthorised(pCon, usUser)) {
|
|
if (strcmp(PaRes.Arg[0].text, "timer") == 0) {
|
|
SetCounterMode(self, eTimer);
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(PaRes.Arg[0].text, "monitor") == 0) {
|
|
SetCounterMode(self, ePreset);
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,255,
|
|
"ERROR: %s not recognized as valid counter mode",
|
|
PaRes.Arg[0].text);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
}
|
|
} else { /* get case */
|
|
|
|
eMode = GetCounterMode(self);
|
|
if (eMode == eTimer) {
|
|
sprintf(pBueffel, "%s.Mode = Timer", argv[0]);
|
|
} else {
|
|
sprintf(pBueffel, "%s.Mode = Monitor", argv[0]);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
break;
|
|
}
|
|
break;
|
|
case 18: /* preset */
|
|
if (PaRes.Arg[0].iVal) { /* set case */
|
|
if (isRunning(self->pCountInt)) {
|
|
SCWrite(pCon, "ERROR: cannot set preset while counting", eError);
|
|
return 0;
|
|
}
|
|
if (isAuthorised(pCon, usUser)) {
|
|
iRet2 = SetCounterPreset(self, PaRes.Arg[0].fVal);
|
|
if (iRet2)
|
|
SCSendOK(pCon);
|
|
SCparChange(pCon);
|
|
return iRet2;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else { /* read case */
|
|
|
|
fVal = GetCounterPreset(self);
|
|
sprintf(pBueffel, "%s.Preset = %f", argv[0], fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
break;
|
|
case 19: /* send */
|
|
/* only manager may use this */
|
|
if (!SCMatchRights(pCon, usMugger)) {
|
|
return 0;
|
|
}
|
|
Arg2Text(argc - 2, &argv[2], pError, 79);
|
|
iRet = self->pDriv->Send(self->pDriv, pError, pBueffel, 255);
|
|
if (iRet == 1) {
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
} else {
|
|
self->pDriv->GetError(self->pDriv, &iRet, pError, 79);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
break;
|
|
case 20: /* setpar */
|
|
if (isRunning(self->pCountInt)) {
|
|
SCWrite(pCon, "ERROR: cannot change parameters while counting",
|
|
eError);
|
|
return 0;
|
|
}
|
|
if (!SCMatchRights(pCon, usMugger)) {
|
|
return 0;
|
|
}
|
|
iRet = self->pDriv->Set(self->pDriv, PaRes.Arg[0].text,
|
|
PaRes.Arg[1].iVal, PaRes.Arg[2].fVal);
|
|
if (iRet == 1) {
|
|
SCparChange(pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
self->pDriv->GetError(self->pDriv, &iRet, pError, 79);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
break;
|
|
case 21: /* getpar */
|
|
if (!SCMatchRights(pCon, usMugger)) {
|
|
return 0;
|
|
}
|
|
iRet = self->pDriv->Get(self->pDriv, PaRes.Arg[0].text,
|
|
PaRes.Arg[1].iVal, &fVal);
|
|
if (iRet == 1) {
|
|
snprintf(pBueffel,255, "%s.%s %s = %f", argv[0], PaRes.Arg[0].text,
|
|
PaRes.Arg[1].text, fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
} else {
|
|
self->pDriv->GetError(self->pDriv, &iRet, pError, 79);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
break;
|
|
case 22: /* getnmon */
|
|
snprintf(pBueffel, 131, "%s.getnmon = %d", argv[0], GetNMonitor(self));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
break;
|
|
case 23: /* state */
|
|
if(isRunning(self->pCountInt)){
|
|
snprintf(pBueffel, 131, "%s.state = run", argv[0]);
|
|
} else {
|
|
snprintf(pBueffel, 131, "%s.state = idle", argv[0]);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
break;
|
|
case 24: /* error */
|
|
snprintf(pBueffel, 131, "%s.error = %s", argv[0],self->error);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
break;
|
|
case 25: /* getchannel */
|
|
snprintf(pBueffel,131,"%s.getchannel = %d", argv[0], GetControlMonitor(self));
|
|
SCWrite(pCon,pBueffel,eValue);
|
|
return 1;
|
|
break;
|
|
case 26: /* setchannel */
|
|
if (SetControlMonitor(self, PaRes.Arg[0].iVal)) {
|
|
return 1;
|
|
} else {
|
|
SCWrite(pCon,"ERROR: Invalid channel id",eError);
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
assert(0); /* internal error */
|
|
}
|
|
return 0;
|
|
}
|