/** * This is a second generation style counter object. It is supposed to work * nicely with a scriptcontext to drive the actual hardware. This is supposed * to interface to single counters and histogram memories. This tries to be * backwards compatible with the old style counter module; thus some * fields in the data structure will not be used. * * copyright: see file COPYRIGHT * * Mark Koennecke, February 2009 */ #include #include #include #include "sicshipadaba.h" /*--------------------------------------------------------------------------- * defines for commmands * -------------------------------------------------------------------------*/ #define START 1000 #define STOP 1001 #define PAUSE 1002 #define CONT 1003 /*---------------------------------------------------------------------------*/ typedef struct { float fPreset; float fCurrent; char *pName; } MonEvent, *pMonEvent; /*---------------------------------------------------------------------------*/ int SecCtrInvokeFunction(pCounter self, SConnection *pCon, int code) { pHdb node = NULL; hdbValue v; node = GetHipadabaNode(self->pDes->parNode, "control"); assert(node != NULL); v = MakeHdbFloat(code); return SetHipadabaPar(node,v,pCon); } /*---------------------------------------------------------------------------*/ static int SecCtrHalt(void *pData) { pCounter self = (pCounter)pData; assert(self != NULL); SecCtrInvokeFunction(self,pServ->dummyCon, STOP); ReleaseCountLock(self->pCountInt); return 1; } /*---------------------------------------------------------------------------*/ static int SecStartCount(void *pData, SConnection *pCon) { pCounter self = (pCounter)pData; int status; pHdb node; assert(self != NULL); if (!GetCountLock(self->pCountInt, pCon)) { return 0; } status = SecCtrInvokeFunction(self,pCon, START); self->haltFixFlag = 0; if(status == 1){ self->isUpToDate = 0; self->badStatusCount = 0; self->tStart = time(NULL); node = GetHipadabaNode(self->pDes->parNode, "status"); UpdateHipadabaPar(node,MakeHdbText("run"), pCon); node = GetHipadabaNode(self->pDes->parNode, "control"); UpdateHipadabaPar(node,MakeHdbFloat(.0), pCon); SetHdbProperty(node,"geterror", NULL); /* * set time to 0. Otherwise, if there is a delay, * the check for overrun counters in SecCtrCheckStatus * may trigger! */ node = GetHipadabaNode(self->pDes->parNode, "time"); UpdateHipadabaPar(node,MakeHdbFloat(.0), pCon); InvokeCallBack(self->pCall,COUNTSTART, pCon); return 1; } else { ReleaseCountLock(self->pCountInt); return HWFault; } } /*---------------------------------------------------------------------------*/ static int SecPause(void *pData, SConnection *pCon) { pCounter self = (pCounter)pData; assert(self != NULL); return SecCtrInvokeFunction(self,pCon, PAUSE); } /*---------------------------------------------------------------------------*/ static int SecContinue(void *pData, SConnection *pCon) { pCounter self = (pCounter)pData; assert(self != NULL); return SecCtrInvokeFunction(self,pCon, CONT); } /*----------------------------------------------------------------------------*/ static int SecCtrCheckStatus(void *pData, SConnection *pCon) { pCounter self = (pCounter)pData; pHdb node = NULL, control = NULL; hdbValue v; int status; MonEvent sMon; float fControl, fPreset; assert(self != NULL); node = GetHipadabaNode(self->pDes->parNode,"status"); assert(node != NULL); status = GetHipadabaPar(node,&v,pCon); if(status != 1){ ReleaseCountLock(self->pCountInt); return HWFault; } if(v.v.text == NULL){ return HWBusy; } if (strstr(v.v.text, "idle") != NULL) { InvokeCallBack(self->pCall, COUNTEND, NULL); ReleaseCountLock(self->pCountInt); status = HWIdle; } else if (strstr(v.v.text, "run") != NULL) { status = HWBusy; } else if (strstr(v.v.text, "nobeam") != NULL) { status = HWNoBeam; } else if (strstr(v.v.text, "pause") != NULL) { status = HWPause; } else if (strstr(v.v.text, "error") != NULL) { InvokeCallBack(self->pCall, COUNTEND, NULL); ReleaseCountLock(self->pCountInt); status = HWFault; } else { SCPrintf(pCon, eError, "ERROR: unknown counter status %s found", v.v.text); ReleaseCountLock(self->pCountInt); status = HWFault; } ReleaseHdbValue(&v); node = GetHipadabaNode(self->pDes->parNode,"control"); assert(node != NULL); GetHipadabaPar(node,&v,pCon); fControl = v.v.doubleValue; node = GetHipadabaNode(self->pDes->parNode,"preset"); assert(node != NULL); GetHipadabaPar(node,&v,pCon); fPreset = v.v.doubleValue; sMon.fCurrent = fControl; sMon.fPreset = fPreset; sMon.pName = self->name; self->badStatusCount = 0; /* * check for overrun counter boxes */ if(self->getMode(self) == eTimer && (sMon.fCurrent > sMon.fPreset +1) && self->haltFixFlag == 0){ SecCtrHalt(self); self->haltFixFlag = 1; } /* * invoke notifiactions, if necessary */ if (self->iCallbackCounter > 20) { InvokeCallBack(self->pCall, MONITOR, &sMon); self->iCallbackCounter = 0; } else { self->iCallbackCounter++; } return status; } /*--------------------------------------------------------------------------- * Here is an issue: this ought to wait until data has arrived. Callers * think now that the data is up to date. With scriptcontext this may not be * the case. The update may come later or even never. Perhaps this needs * to be emulated: * - set a property to some value when starting * - add an update callback which deletes the property when done. * - Check that property or the geterror property here in a loop * until done or we timeout. * -----------------------------------------------------------------------*/ static int SecCtrTransferData(void *pData, SConnection *pCon) { pCounter self = (pCounter)pData; assert(self != NULL); pHdb node = NULL; hdbValue v; int status; node = GetHipadabaNode(self->pDes->parNode,"values"); assert(node != NULL); self->isUpToDate = 1; status = GetHipadabaPar(node,&v,pCon); ReleaseHdbValue(&v); return status; } /*------------------------------------------------------------------------*/ static void *SecCtrCounterGetInterface(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; } /*--------------------------------------------------------------------------*/ static int SecCtrSetMode(pCounter self, CounterMode eNew) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"mode"); assert(node != NULL); switch(eNew){ case eTimer: v = MakeHdbText("timer"); break; case ePreset: v = MakeHdbText("monitor"); break; } return SetHipadabaPar(node,v,NULL); } /*---------------------------------------------------------------------------*/ static CounterMode SecCtrGetMode(pCounter self) { hdbValue v; pHdb node = NULL; CounterMode mode; node = GetHipadabaNode(self->pDes->parNode,"mode"); assert(node != NULL); GetHipadabaPar(node,&v,NULL); assert(v.v.text != NULL); if(strcmp(v.v.text,"timer") == 0){ mode = eTimer; } else { mode = ePreset; } ReleaseHdbValue(&v); return mode; } /*--------------------------------------------------------------------------*/ static int SecCtrSetPreset(pCounter self, float val) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"preset"); assert(node != NULL); v = MakeHdbFloat(val); return SetHipadabaPar(node,v,NULL); } /*--------------------------------------------------------------------------*/ static void SecCtrSetCountParameters(void *pData, float fPreset, CounterMode eMode) { pCounter self = NULL; assert(pData); self = (pCounter) pData; SetCounterPreset(self, fPreset); SetCounterMode(self, eMode); } /*---------------------------------------------------------------------------*/ static float SecCtrGetPreset(pCounter self) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"preset"); assert(node != NULL); GetHipadabaPar(node,&v,NULL); return (float)v.v.doubleValue; } /*---------------------------------------------------------------------------*/ static float SecCtrGetControlValue(pCounter self) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"control"); assert(node != NULL); GetHipadabaPar(node,&v,NULL); return (float)v.v.doubleValue; } /*--------------------------------------------------------------------------*/ static int SecCtrGetNMonitor(pCounter self) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"values"); assert(node != NULL); GetHipadabaPar(node,&v,NULL); return v.arrayLength; } /*--------------------------------------------------------------------------*/ static long SecCtrGetMonitor(pCounter self, int iNum, SConnection *pCon) { hdbValue v; pHdb node = NULL; long val; if (!self->isUpToDate) { self->pCountInt->TransferData(self, pCon); } node = GetHipadabaNode(self->pDes->parNode,"values"); assert(node != NULL); GetHipadabaPar(node,&v,pCon); if(iNum >= 0 && iNum < v.arrayLength){ val = (long)v.v.intArray[iNum]; } else { val = -1L; } ReleaseHdbValue(&v); return val; } /*--------------------------------------------------------------------------*/ static long SecCtrGetCounts(pCounter self, SConnection *pCon) { return SecCtrGetMonitor(self,0,pCon); } /*--------------------------------------------------------------------------*/ static void SecCtrSetMonitor(pCounter self, int iNum, long val) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"values"); assert(node != NULL); GetHipadabaPar(node,&v,NULL); if(iNum >= 0 && iNum < v.arrayLength){ v.v.intArray[iNum] = val; UpdateHipadabaPar(node,v,NULL); } } /*---------------------------------------------------------------------------*/ static float SecCtrGetTime(pCounter self, SConnection *pCon) { hdbValue v; pHdb node = NULL; node = GetHipadabaNode(self->pDes->parNode,"time"); assert(node != NULL); GetHipadabaPar(node,&v,pCon); return (float)v.v.doubleValue; } /*--------------------------------------------------------------------------*/ static int CountCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { float preset; if(nPar < 1){ return 0; } preset = par[0]->value.v.doubleValue; return DoCount((pCounter)ccmd, preset, con, 1); } /*--------------------------------------------------------------------------*/ static int CountNBCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { float preset; if(nPar < 1){ return 0; } preset = par[0]->value.v.doubleValue; return DoCount((pCounter)ccmd, preset, con, 0); } /*--------------------------------------------------------------------------*/ static int StopCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { pCounter self = (pCounter)ccmd; return self->pCountInt->Halt(self); } /*--------------------------------------------------------------------------*/ static int PauseCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { pCounter self = (pCounter)ccmd; return self->pCountInt->Pause(self,con); } /*--------------------------------------------------------------------------*/ static int ContinueCmd(pSICSOBJ ccmd, SConnection * con, Hdb * cmdNode, Hdb * par[], int nPar) { pCounter self = (pCounter)ccmd; return self->pCountInt->Continue(self,con); } /*--------------------------------------------------------------------------*/ pCounter CreateSecCounter(SConnection *pCon, char *type, char *name, int length) { pCounter pRes = NULL; pHdb node = NULL, child = NULL; pRes = (pCounter) malloc(sizeof(Counter)); if (!pRes) { SCWrite(pCon,"ERROR: out of memory in MakeSecCter", eError); return NULL; } memset(pRes,0,sizeof(Counter)); pRes->pDes = CreateDescriptor(type); if (!pRes->pDes) { SCWrite(pCon,"ERROR: out of memory in MakeSecCter", eError); return 0; } /* initialize Descriptor functions */ pRes->pDes->GetInterface = SecCtrCounterGetInterface; pRes->pDes->SaveStatus = SaveSICSOBJ; /* initialise countable interface */ pRes->pCountInt = CreateCountableInterface(); if (!pRes->pCountInt) { DeleteDescriptor(pRes->pDes); SCWrite(pCon,"ERROR: out of memory in MakeSecCter", eError); return 0; } pRes->pCountInt->SetCountParameters = SecCtrSetCountParameters; pRes->pCountInt->StartCount = SecStartCount; pRes->pCountInt->CheckCountStatus = SecCtrCheckStatus; pRes->pCountInt->TransferData = SecCtrTransferData; pRes->pCountInt->Halt = SecCtrHalt; pRes->pCountInt->Pause = SecPause; pRes->pCountInt->Continue = SecContinue; pRes->iCallbackCounter = 20; pRes->setMode = SecCtrSetMode; pRes->getMode = SecCtrGetMode; pRes->getNMonitor = SecCtrGetNMonitor; pRes->setPreset = SecCtrSetPreset; pRes->getPreset = SecCtrGetPreset; pRes->getControlValue = SecCtrGetControlValue; pRes->getCounts = SecCtrGetCounts; pRes->getMonitor = SecCtrGetMonitor; pRes->setMonitor = SecCtrSetMonitor; pRes->getTime = SecCtrGetTime; pRes->pCall = CreateCallBackInterface(); pRes->isUpToDate = 1; pRes->iExponent = 0; pRes->name = strdup(name); node = MakeHipadabaNode(name,HIPNONE, 0); pRes->pDes->parNode = node; pRes->objectNode = node; child = MakeSICSHdbPar("time", usInternal, MakeHdbFloat(.0)); if (child == NULL) { return NULL; } AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("preset", usUser, MakeHdbFloat(.0)); if (child == NULL) { return NULL; } SetHdbProperty(child, "__save", "true"); AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("mode", usUser, MakeHdbText("monitor")); if (child == NULL) { return NULL; } SetHdbProperty(child, "__save", "true"); AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("status", usInternal, MakeHdbText("idle")); if (child == NULL) { return NULL; } AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("control", usUser, MakeHdbFloat(.0)); if (child == NULL) { return NULL; } AddHipadabaChild(node, child, NULL); child = MakeSICSHdbPar("values", usInternal, makeHdbValue(HIPINTAR, length)); if (child == NULL) { return NULL; } AddHipadabaChild(node, child, NULL); child = AddSICSHdbPar(node,"count", usUser, MakeSICSFunc(CountCmd)); AddSICSHdbPar(child, "preset", usUser, MakeHdbFloat(2)); child = AddSICSHdbPar(node,"countnb", usUser, MakeSICSFunc(CountNBCmd)); AddSICSHdbPar(child, "preset", usUser, MakeHdbFloat(2)); child = AddSICSHdbPar(node,"stop", usUser, MakeSICSFunc(StopCmd)); child = AddSICSHdbPar(node,"pause", usUser, MakeSICSFunc(PauseCmd)); child = AddSICSHdbPar(node,"continue", usUser, MakeSICSFunc(ContinueCmd)); return pRes; } /*--------------------------------------------------------------------------*/ int MakeSecCter(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pCounter pRes = NULL; int status, length; pHdb node, child; if(argc < 3) { SCWrite(pCon,"ERROR: need at least a name and length to create a counter", eError); return 0; } length = atoi(argv[2]); pRes = CreateSecCounter(pCon,"SingleCounter", argv[1], length); if(pRes == NULL){ return 0; } status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, DeleteCounter, (void *) pRes); if (status != 1) { SCPrintf(pCon,eError, "ERROR: duplicate command %s not created", argv[1]); return 0; } return 1; }