/** * The MultiCounter is another counter which coordinates multiple * counting objects, counters and histogram memories. It also calls a * script function after TransferData which collects counters and monitors. * The purpose is to have a flexible counter abstraction for upper level * code such as maximizers and scan functions. The script can deal with * counting on monitors or on sums of histogram memories. * * This is a bit unclean. The counter driver is of no use, therefore its * private data structure is used to hold the other counters and the name * of the script. It would have been better to inherit from counter but * that would have required lost of type casts. I am to lazy for this. * * copyright: see file COPYRIGHT * * Mark Koennecke, September 2006 */ #include #include #include #include #include "multicounter.h" #include "counter.h" #include "HistMem.h" #include "macro.h" #include "splitter.h" #define MAXSLAVE 16 #define NOCOUNTERS -2727 /*=============== code for the driver ======================================*/ typedef struct { void *slaveData[MAXSLAVE]; pICountable slaves[MAXSLAVE]; char *transferScript; int nSlaves; }MultiCounter, *pMultiCounter; /*--------------------------------------------------------------------------*/ static void KillMultiDriver(struct __COUNTER *data){ pMultiCounter self = (pMultiCounter)data->pData; if(self == NULL){ return; } if(self->transferScript != NULL){ free(self->transferScript); } free(self); } /*============== countable interface functions ============================*/ static int MMCCHalt(void *pData){ int i, retVal = OKOK, status; pCounter pCount = NULL; pMultiCounter self = NULL; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); for(i = 0; i < self->nSlaves; i++){ status = self->slaves[i]->Halt(self->slaveData[i]); if(status != OKOK) retVal = status; } return retVal; } /*-------------------------------------------------------------------------*/ static int MMCCStart(void *pData, SConnection *pCon) { int i, status; pCounter pCount = NULL; pMultiCounter self = NULL; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); for(i = 0; i < self->nSlaves; i++){ self->slaves[i]->SetCountParameters(self->slaveData[i], pCount->pDriv->fPreset, pCount->pDriv->eMode); status = self->slaves[i]->StartCount(self->slaveData[i],pCon); if(status != OKOK){ MMCCHalt(pData); return status; } } pCount->isUpToDate = 0; pCount->tStart = time(NULL); InvokeCallBack(pCount->pCall,COUNTSTART,pCon); return OKOK; } /*-------------------------------------------------------------------------*/ static int MMCCStatus(void *pData, SConnection *pCon){ int status,i; pCounter pCount = NULL; pMultiCounter self = NULL; pDummy pDum = NULL; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); if(self->nSlaves == 0) { pCount->pDriv->iErrorCode = NOCOUNTERS; return HWFault; } status = self->slaves[0]->CheckCountStatus(self->slaveData[0],pCon); if(status == HWIdle || status == HWFault){ /* stop counting on slaves when finished or when an error occurred. */ InvokeCallBack(pCount->pCall,COUNTEND,pCon); MMCCHalt(pCount); } for(i = 1; i < MAXSLAVE; i++){ if(self->slaves[i] != NULL){ pDum = (pDummy)self->slaveData[i]; if(strcmp(pDum->pDescriptor->name,"HistMem") == 0){ HistDirty((pHistMem)self->slaveData[i]); } } } return status; } /*-------------------------------------------------------------------------*/ static int MMCCPause(void *pData, SConnection *pCon){ int i, status; pCounter pCount = NULL; pMultiCounter self = NULL; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); for(i = 0; i < self->nSlaves; i++){ status = self->slaves[i]->Pause(self->slaveData[i],pCon); if(status != OKOK){ MMCCHalt(pCount); return status; } } return OKOK; } /*--------------------------------------------------------------------------*/ static int MMCCContinue(void *pData, SConnection *pCon){ int i, status; pCounter pCount = NULL; pMultiCounter self = NULL; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); for(i = 0; i < self->nSlaves; i++){ status = self->slaves[i]->Continue(self->slaveData[i],pCon); if(status != OKOK){ MMCCHalt(pCount); return status; } } return OKOK; } /*------------------------------------------------------------------------*/ static char *getNextMMCCNumber(char *pStart, char pNumber[80]){ int charCount = 0; pNumber[0] = '\0'; /* advance to first digit */ while(isspace(*pStart) && *pStart != '\0'){ pStart++; } if(*pStart == '\0'){ return NULL; } /* copy */ while(!isspace(*pStart) && *pStart != '\0' && charCount < 78){ pNumber[charCount] = *pStart; pStart++; charCount++; } pNumber[charCount] = '\0'; return pStart; } /*-------------------------------------------------------------------------*/ static void loadCountData(pCounter pCount, const char *data){ char *pPtr = NULL; char pNumber[80]; int i = 0; pPtr = (char *)data; pPtr = getNextMMCCNumber(pPtr,pNumber); pCount->pDriv->fTime = atof(pNumber); while(pPtr != NULL && i < MAXCOUNT){ pPtr = getNextMMCCNumber(pPtr,pNumber); pCount->pDriv->lCounts[i] = atoi(pNumber); i++; } } /*--------------------------------------------------------------------------*/ static int MMCCTransfer(void *pData, SConnection *pCon){ int i, retVal = OKOK, status; char pBueffel[132]; pCounter pCount = NULL; pMultiCounter self = NULL; int tclStatus; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); for(i = 0; i < self->nSlaves; i++){ status = self->slaves[i]->TransferData(self->slaveData[i], pCon); if(status != OKOK){ retVal = status; sprintf(pBueffel,"WARNING: slave histogram %d failed to transfer data", i); SCWrite(pCon,pBueffel,eWarning); } } if(self->transferScript != NULL){ MacroPush(pCon); tclStatus = Tcl_Eval(InterpGetTcl(pServ->pSics), self->transferScript); if(tclStatus != TCL_OK){ snprintf(pBueffel,131,"ERROR: TransferScript returned: %s", Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); SCWrite(pCon,pBueffel,eError); MacroPop(); return HWFault; } MacroPop(); loadCountData(pCount,Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); } return retVal; } /*-------------------------------------------------------------------------*/ static void MMCCParameter(void *pData, float fPreset, CounterMode eMode ){ int i; pCounter pCount = NULL; pMultiCounter self = NULL; pCount = (pCounter)pData; if(pCount != NULL){ self = (pMultiCounter)pCount->pDriv->pData; } assert(self); for(i = 0; i < self->nSlaves; i++){ self->slaves[i]->SetCountParameters(self->slaveData[i], fPreset, eMode); } } /*======================= Driver Interface ==============================*/ static int MultiCounterSet(struct __COUNTER *self, char *name, int iCter, float fVal){ return 0; } /*-----------------------------------------------------------------------*/ static int MultiCounterGet(struct __COUNTER *self, char *name, int iCter, float *fVal){ return 0; } /*-----------------------------------------------------------------------*/ static int MultiCounterSend(struct __COUNTER *self, char *pText, char *reply, int replylen){ strncpy(reply,"NOT Implemented",replylen); return 0; } /*---------------------------------------------------------------------*/ static int MultiCounterError(struct __COUNTER *pDriv, int *iCode, char *error, int errlen){ if(pDriv->iErrorCode == NOCOUNTERS){ strncpy(error,"NO counters configured!",errlen); } else { strncpy(error,"Not Implemented", errlen); } return COTERM; } /*----------------------------------------------------------------------*/ static int MultiCounterFix(struct __COUNTER *self, int iCode){ return COTERM; } /*=============== Interpreter Interface ================================ */ int MultiCounterAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pMultiCounter self = NULL; pCounter pCount = NULL; char buffer[256]; if(argc > 1){ strtolower(argv[1]); if(strcmp(argv[1],"transferscript") == 0){ pCount = (pCounter)pData; self = (pMultiCounter)pCount->pDriv->pData; if(argc < 3){ SCPrintf(pCon,eValue,"%s.transferscript = %s", argv[0],self->transferScript); return 1; } else { if(!SCMatchRights(pCon,usUser)){ return 0; } if(self->transferScript != NULL){ free(self->transferScript); } Arg2Text(argc-2,&argv[2],buffer,255); self->transferScript = strdup(buffer); SCSendOK(pCon); return 1; } } } return CountAction(pCon,pSics,pData,argc,argv); } /*------------------------------------------------------------------------*/ int MakeMultiCounter(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ int i, status; pCounter pNew = NULL; char pBueffel[132]; CommandList *pCom; pICountable pCount; pMultiCounter self = NULL; pCounterDriver pDriv = NULL; /* need at least two parameters */ if(argc < 3){ SCWrite(pCon,"ERROR: insufficient number of arguments to MakeMultiCounter", eError); return 0; } /* allocate our data structure */ self = malloc(sizeof(MultiCounter)); pDriv = malloc(sizeof(CounterDriver)); if(self == NULL || pDriv == NULL){ SCWrite(pCon,"ERROR: out of memory in MakeMultiCounter",eError); return 0; } memset(self,0,sizeof(MultiCounter)); memset(pDriv,0,sizeof(CounterDriver)); pDriv->pData = self; pDriv->KillPrivate = KillMultiDriver; pDriv->iNoOfMonitors = MAXCOUNT; pNew = CreateCounter(argv[1],pDriv); if(pNew == NULL){ SCWrite(pCon,"ERROR: out of memory in MakeMultiCounter",eError); return 0; } pDriv->Get = MultiCounterGet; pDriv->GetError = MultiCounterError; pDriv->TryAndFixIt = MultiCounterFix; pDriv->Set = MultiCounterSet; pDriv->Send = MultiCounterSend; /* assign interface functions */ pNew->pCountInt->Halt = MMCCHalt; pNew->pCountInt->StartCount = MMCCStart; pNew->pCountInt->CheckCountStatus = MMCCStatus; pNew->pCountInt->Pause = MMCCPause; pNew->pCountInt->Continue = MMCCContinue; pNew->pCountInt->TransferData = MMCCTransfer; pNew->pCountInt->SetCountParameters = MMCCParameter; /* now loop through the remaining arguments, thereby entering them into the slave list. */ for(i = 2; i < argc; i++){ pCom = FindCommand(pSics,argv[i]); if(!pCom){ sprintf(pBueffel,"ERROR: object %s not found in MakeMultiCounter", argv[i]); SCWrite(pCon,pBueffel,eError); continue; } pCount = GetCountableInterface(pCom->pData); if(!pCount){ sprintf(pBueffel,"ERROR: object %s is NOT countable", argv[i]); SCWrite(pCon,pBueffel,eError); continue; } self->slaves[self->nSlaves] = pCount; self->slaveData[self->nSlaves] = pCom->pData; self->nSlaves++; } /* now install our action command and we are done */ status = AddCommand(pSics,argv[1],MultiCounterAction,DeleteCounter, pNew); if(!status){ sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]); SCWrite(pCon,pBueffel,eError); DeleteCounter(pNew); return 0; } return 1; }