- Fixes to hkl code
- Fixes to make RITA work - tasub extended to calculate UB from cell alone, support for elastic mode - New MultiCounter as abstraction for counting on HM's - regression test driver for counters
This commit is contained in:
380
multicounter.c
Normal file
380
multicounter.c
Normal file
@ -0,0 +1,380 @@
|
||||
/**
|
||||
* 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 <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <tcl.h>
|
||||
#include "multicounter.h"
|
||||
#include "counter.h"
|
||||
#include "HistMem.h"
|
||||
#include "macro.h"
|
||||
#include "splitter.h"
|
||||
|
||||
#define MAXSLAVE 16
|
||||
/*=============== 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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*=============== 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;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user