Files
sics/multicounter.c
Ferdi Franceschini cff9290272 SICS-195
countdriv.h
CounterDriver:  iControlMonitor id (default=0)

countdriv.c
CreateCounterDriver: set the default control monitor to channel zero

counter.h
counter.c
Commands to get and set the control monitor
GetCounts return the counts from the current control monitor, ie iControlMonitor
TODO loadCountData, get time from controlling monitor.

scan.c
Set control monitor on counter when setting scan channel

multicounter.c
MMCStart, set slave monitors with a  timer preset of about a year to make sure that they don't stop before the controlling monitor.

r2642 | ffr | 2008-07-10 15:21:21 +1000 (Thu, 10 Jul 2008) | 20 lines
2012-11-15 13:39:59 +11:00

446 lines
13 KiB
C

/**
* 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
#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, controlMonitor;
int oneYear=32000000;
pCounter pCount = NULL;
pMultiCounter self = NULL;
char buffer[128];
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
controlMonitor = GetControlMonitor((pCounter)pCount);
for(i = 0; i < self->nSlaves; i++){
if (i == controlMonitor) {
self->slaves[i]->SetCountParameters(self->slaveData[i],
pCount->pDriv->fPreset, pCount->pDriv->eMode);
} else {
self->slaves[i]->SetCountParameters(self->slaveData[i],
oneYear, eTimer);
}
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, controlMonitor;
pCounter pCountController = NULL;
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;
}
controlMonitor = GetControlMonitor((pCounter)pCount);
pCountController = (pCounter)self->slaveData[controlMonitor];
status = self->slaves[controlMonitor]->CheckCountStatus(pCountController,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);
// SICS-195 get time from controlling monitor
// 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;
pCounter pCountController = NULL;
pMultiCounter self = NULL;
int tclStatus;
int controlMonitor;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
controlMonitor = GetControlMonitor(pCount);
pCountController = (pCounter)self->slaveData[controlMonitor];
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);
}
}
pCount->pDriv->fTime = pCountController->pDriv->fTime;
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 *pData, int *iCode,
char *error, int errlen){
pCounter pCount = NULL;
pCount = (pCounter)pData;
if(pCount->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;
/*
now loop through the remaining arguments, thereby entering them into
the slave list.
*/
for(i = 2, self->nSlaves = 0; 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++;
}
pDriv->iNoOfMonitors = self->nSlaves;
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 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;
}