
This is our new RELEASE-4_0 branch which was taken from ansto/93d9a7c Conflicts: .gitignore SICSmain.c asynnet.c confvirtualmot.c counter.c devexec.c drive.c event.h exebuf.c exeman.c histmem.c interface.h motor.c motorlist.c motorsec.c multicounter.c napi.c napi.h napi4.c network.c nwatch.c nxscript.c nxxml.c nxxml.h ofac.c reflist.c scan.c sicshipadaba.c sicsobj.c site_ansto/docs/Copyright.txt site_ansto/instrument/lyrebird/config/tasmad/sicscommon/nxsupport.tcl site_ansto/instrument/lyrebird/config/tasmad/taspub_sics/tasscript.tcl statusfile.c tasdrive.c tasub.c tasub.h tasublib.c tasublib.h
532 lines
15 KiB
C
532 lines
15 KiB
C
/**
|
|
* This is a second generation histogram memory object. In contrast
|
|
* to counters and motors no attempt is made to provide backwards
|
|
* compatability with the old SICS way of doing things. This
|
|
* histogram memory object quite sensibly is derived from
|
|
* the counter object. It adds a rank, dimensions and variable
|
|
* data and a configuration method. For TOF, methods and variables
|
|
* for generating and maintaining time binnings are provided too.
|
|
*
|
|
* copyright: see file COPYRIGHT
|
|
*
|
|
* Mark Koennecke, May 2009
|
|
*
|
|
* Added bridging routines implementing first gen HM interfaces
|
|
*
|
|
* Mark Koennecke, December 2012
|
|
*/
|
|
#include <sics.h>
|
|
#include <sicshipadaba.h>
|
|
#include <counter.h>
|
|
#include "HistMem.h"
|
|
#include "HistMem.i"
|
|
#include "arrayutil.h"
|
|
|
|
#define CONFIG 1005
|
|
|
|
/* from countersec.c. */
|
|
int SecCtrInvokeFunction(pCounter self, SConnection *pCon, int code);
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int initArray(pCounter self, int value)
|
|
{
|
|
pHdb rank = NULL, dim = NULL, data = NULL, datalength;
|
|
int i, length;
|
|
hdbValue v;
|
|
|
|
rank = GetHipadabaNode(self->pDes->parNode,"rank");
|
|
assert(rank != NULL);
|
|
dim = GetHipadabaNode(self->pDes->parNode,"dim");
|
|
assert(dim != NULL);
|
|
data = GetHipadabaNode(self->pDes->parNode,"data");
|
|
assert(data != NULL);
|
|
datalength = GetHipadabaNode(self->pDes->parNode,"datalength");
|
|
assert(datalength != NULL);
|
|
|
|
length = dim->value.v.intArray[0];
|
|
for(i = 1; i < dim->value.arrayLength; i++){
|
|
length *= dim->value.v.intArray[i];
|
|
}
|
|
/* printf("initArray called with length %d\n", length);*/
|
|
|
|
v = MakeHdbInt(length);
|
|
UpdateHipadabaPar(datalength, v, NULL);
|
|
|
|
v = makeHdbValue(HIPINTVARAR, length);
|
|
if(v.v.intArray == NULL){
|
|
return 0;
|
|
}
|
|
for(i = 0; i < length; i++){
|
|
v.v.intArray[i] = value;
|
|
}
|
|
UpdateHipadabaPar(data,v,NULL);
|
|
ReleaseHdbValue(&v);
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
static hdbCallbackReturn HMDimCallback(pHdb currentNode, void *data,
|
|
pHdbMessage message)
|
|
{
|
|
pHdbDataMessage update = NULL;
|
|
|
|
if((update = GetHdbUpdateMessage(message)) != NULL){
|
|
copyHdbValue(update->v, ¤tNode->value);
|
|
initArray((pCounter)data, 0);
|
|
}
|
|
return hdbContinue;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int ResetCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
if(nPar < 1){
|
|
SCWrite(pCon, "ERROR: need a parameter to set", eError);
|
|
return 0;
|
|
}
|
|
|
|
if(!initArray((pCounter) ccmd, par[0]->value.v.intValue )){
|
|
SCWrite(pCon,"ERROR: out of memory initializing HM", eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int NoTimeBinCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
pHdb timeNode = NULL;
|
|
|
|
timeNode = GetHipadabaNode(ccmd->objectNode,"time_binning");
|
|
if(timeNode == NULL){
|
|
SCWrite(pCon,"ERROR: HM has no time binning",eError);
|
|
return 0;
|
|
}
|
|
SCPrintf(pCon,eValue,"%s.totimebin = %d", ccmd->objectNode->name,
|
|
timeNode->value.arrayLength);
|
|
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int TimebinsCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
pHdb timeNode = NULL;
|
|
pDynString data= NULL;
|
|
|
|
timeNode = GetHipadabaNode(ccmd->objectNode,"time_binning");
|
|
if(timeNode == NULL){
|
|
SCWrite(pCon,"ERROR: HM has no time binning",eError);
|
|
return 0;
|
|
}
|
|
data = formatValue(timeNode->value,timeNode);
|
|
if(data != NULL){
|
|
SCPrintf(pCon,eValue,"%s.timebins = %s", ccmd->objectNode->name,
|
|
GetCharArray(data));
|
|
DeleteDynString(data);
|
|
} else {
|
|
SCWrite(pCon,"ERROR: out of memory formatting timebins", eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int GenbinCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
double start, step;
|
|
int np, i;
|
|
pHdb tof = NULL, dim = NULL;
|
|
hdbValue v;
|
|
|
|
if(nPar < 3){
|
|
SCWrite(pCon, "ERROR: need start step n parameters to gengin",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
start = par[0]->value.v.doubleValue;
|
|
step = par[1]->value.v.doubleValue;
|
|
np = par[2]->value.v.intValue;
|
|
|
|
tof = GetHipadabaNode(ccmd->pDes->parNode,"time_binning");
|
|
assert(tof != NULL);
|
|
|
|
dim = GetHipadabaNode(ccmd->pDes->parNode,"dim");
|
|
assert(dim != NULL);
|
|
|
|
v = makeHdbValue(HIPFLOATVARAR,np );
|
|
if(v.v.floatArray == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in genbin", eError);
|
|
return 0;
|
|
}
|
|
for(i = 0; i < np; i++){
|
|
v.v.floatArray[i] = start + i*step;
|
|
}
|
|
UpdateHipadabaPar(tof,v,pCon);
|
|
ReleaseHdbValue(&v);
|
|
|
|
GetHipadabaPar(dim,&v, pCon);
|
|
v.v.intArray[v.arrayLength-1] = np;
|
|
UpdateHipadabaPar(dim,v,pCon);
|
|
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int ConfigureCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
pHdb dimNode = NULL;
|
|
|
|
if(nPar < 1) {
|
|
SCWrite(pCon,"ERROR: need a parameter to read", eError);
|
|
return 0;
|
|
}
|
|
dimNode = GetHipadabaNode(ccmd->objectNode,"dim");
|
|
|
|
assert(dimNode != NULL);
|
|
|
|
if(strcmp(par[0]->value.v.text,"dim0") == 0){
|
|
SCPrintf(pCon,eValue,"%s.dim0 = %d", ccmd->objectNode->name,
|
|
dimNode->value.v.intArray[0]);
|
|
} else if(strcmp(par[0]->value.v.text,"dim1") == 0){
|
|
SCPrintf(pCon,eValue,"%s.dim1 = %d", ccmd->objectNode->name,
|
|
dimNode->value.v.intArray[1]);
|
|
} else {
|
|
SCPrintf(pCon,eError,"ERROR: subcommand %s to configure not found",
|
|
par[0]->value.v.text);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SumCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
pHdb dimNode = NULL, dataNode = NULL;
|
|
int xstart, xend, ystart, yend, i;
|
|
long lSum = 0;
|
|
|
|
dimNode = GetHipadabaNode(ccmd->objectNode,"dim");
|
|
dataNode = GetHipadabaNode(ccmd->objectNode,"data");
|
|
assert(dimNode != NULL && dataNode != NULL);
|
|
|
|
switch(dimNode->value.arrayLength){
|
|
case 1:
|
|
if(nPar < 2) {
|
|
SCWrite(pCon,"ERROR: need start and end for summing 1D data",eError);
|
|
return 0;
|
|
}
|
|
xstart = par[0]->value.v.intValue;
|
|
xend = par[1]->value.v.intValue;
|
|
if(xstart < 0){
|
|
xstart = 0;
|
|
}
|
|
if(xend > dataNode->value.arrayLength){
|
|
xend = dataNode->value.arrayLength;
|
|
}
|
|
for(i = xstart; i < xend; i++){
|
|
lSum += dataNode->value.v.intArray[i];
|
|
}
|
|
SCPrintf(pCon,eValue,"%s.sum = %ld", ccmd->objectNode->name, lSum);
|
|
break;
|
|
case 2:
|
|
if(nPar < 4) {
|
|
SCWrite(pCon,"ERROR: need start and end in x and y for summing 2D data",eError);
|
|
return 0;
|
|
}
|
|
xstart = par[0]->value.v.intValue;
|
|
xend = par[1]->value.v.intValue;
|
|
if(xstart < 0){
|
|
xstart = 0;
|
|
}
|
|
if(xend > dimNode->value.v.intArray[0]){
|
|
xend = dimNode->value.v.intArray[0];
|
|
}
|
|
ystart = par[2]->value.v.intValue;
|
|
yend = par[3]->value.v.intValue;
|
|
if(ystart < 0){
|
|
ystart = 0;
|
|
}
|
|
if(yend > dimNode->value.v.intArray[1]){
|
|
yend = dimNode->value.v.intArray[1];
|
|
}
|
|
lSum = sumWindow(dataNode->value.v.intArray, xstart,xend,dimNode->value.v.intArray[0],
|
|
ystart, yend, dimNode->value.v.intArray[1]);
|
|
SCPrintf(pCon,eValue,"%s.sum = %ld", ccmd->objectNode->name, lSum);
|
|
break;
|
|
default:
|
|
SCPrintf(pCon, eError, "ERROR: summing not supported for %d dimensional data",
|
|
dimNode->value.arrayLength);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
static int TotalCmd(pSICSOBJ ccmd, SConnection * pCon,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
pHdb dataNode = NULL;
|
|
long lSum = 0;
|
|
int i;
|
|
|
|
dataNode = GetHipadabaNode(ccmd->objectNode,"data");
|
|
assert(dataNode != NULL);
|
|
for(i = 0, lSum = 0; i < dataNode->value.arrayLength; i++){
|
|
lSum += dataNode->value.v.intArray[i];
|
|
}
|
|
SCPrintf(pCon,eValue,"%s.total = %ld", ccmd->objectNode->name, lSum);
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int InitCmd(pSICSOBJ ccmd, SConnection * con,
|
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
|
{
|
|
return SecCtrInvokeFunction((pCounter)ccmd,con,CONFIG);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int HMCtrTransferData(void *pData, SConnection *pCon)
|
|
{
|
|
pCounter self = (pCounter)pData;
|
|
assert(self != NULL);
|
|
pHdb node = NULL;
|
|
hdbValue v;
|
|
int status;
|
|
|
|
node = GetHipadabaNode(self->pDes->parNode,"data");
|
|
assert(node != NULL);
|
|
self->isUpToDate = 1;
|
|
status = GetHipadabaPar(node,&v,pCon);
|
|
ReleaseHdbValue(&v);
|
|
return status;
|
|
}
|
|
/*-------------------------------------------------------------------------
|
|
* automatically update the last entry of the dim variable when
|
|
* setting time_binning
|
|
--------------------------------------------------------------------------*/
|
|
static hdbCallbackReturn HMTOFCallback(pHdb currentNode, void *data,
|
|
pHdbMessage message)
|
|
{
|
|
pHdbDataMessage update = NULL;
|
|
hdbValue dim;
|
|
pHdb dimNode = NULL;
|
|
|
|
if((update = GetHdbUpdateMessage(message)) != NULL){
|
|
dimNode = GetHipadabaNode(currentNode->mama,"dim");
|
|
assert(dimNode != NULL);
|
|
GetHipadabaPar(dimNode,&dim,NULL);
|
|
dim.v.intArray[dim.arrayLength-1] = update->v->arrayLength;
|
|
UpdateHipadabaPar(dimNode, dim, NULL);
|
|
}
|
|
return hdbContinue;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* Usage:
|
|
* MakeSecHM name rank (tof)
|
|
* -------------------------------------------------------------------------*/
|
|
int MakeSecHM(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pCounter pRes = NULL;
|
|
int rank, status;
|
|
pHdb node = NULL, child = NULL;
|
|
|
|
if(argc < 3) {
|
|
SCWrite(pCon,"ERROR: need at least a name and rank to create a HM",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
rank = atoi(argv[2]);
|
|
|
|
pRes = CreateSecCounter(pCon,"HistMemSec", argv[1], 2);
|
|
if(pRes == NULL){
|
|
return 0;
|
|
}
|
|
/*
|
|
remove count and rename countnb to it
|
|
*/
|
|
node = GetHipadabaNode(pRes->pDes->parNode,"count");
|
|
DeleteHipadabaNode(node,NULL);
|
|
node = GetHipadabaNode(pRes->pDes->parNode,"countnb");
|
|
strcpy(node->name,"count");
|
|
|
|
|
|
pRes->pCountInt->TransferData = HMCtrTransferData;
|
|
|
|
node = pRes->objectNode;
|
|
child = GetHipadabaNode(node,"values");
|
|
if(child!= NULL){
|
|
DeleteHipadabaNode(child,pCon);
|
|
}
|
|
|
|
child = MakeSICSHdbPar("rank", usMugger, MakeHdbInt(rank));
|
|
if (child == NULL) {
|
|
return 0;
|
|
}
|
|
AddHipadabaChild(node, child, NULL);
|
|
|
|
child = MakeSICSHdbPar("dim", usMugger, makeHdbValue(HIPINTVARAR,rank));
|
|
if (child == NULL) {
|
|
return 0;
|
|
}
|
|
AppendHipadabaCallback(child,
|
|
MakeHipadabaCallback(HMDimCallback, pRes, NULL));
|
|
AddHipadabaChild(node, child, NULL);
|
|
|
|
child = MakeSICSHdbPar("datalength", usInternal, MakeHdbInt(100));
|
|
if (child == NULL) {
|
|
return 0;
|
|
}
|
|
AddHipadabaChild(node, child, NULL);
|
|
|
|
child = MakeSICSHdbPar("data", usMugger, makeHdbValue(HIPINTVARAR,100));
|
|
if (child == NULL) {
|
|
return 0;
|
|
}
|
|
AddHipadabaChild(node, child, NULL);
|
|
|
|
child = AddSICSHdbPar(node,"set", usMugger, MakeSICSFunc(ResetCmd));
|
|
AddSICSHdbPar(child, "value", usUser, MakeHdbInt(0));
|
|
|
|
child = AddSICSHdbPar(node,"init", usMugger, MakeSICSFunc(InitCmd));
|
|
|
|
child = AddSICSHdbPar(node,"sum", usSpy, MakeSICSFunc(SumCmd));
|
|
AddSICSHdbPar(child, "xstart", usSpy, MakeHdbInt(0));
|
|
AddSICSHdbPar(child, "xend", usSpy, MakeHdbInt(0));
|
|
AddSICSHdbPar(child, "ystart", usSpy, MakeHdbInt(0));
|
|
AddSICSHdbPar(child, "yend", usSpy, MakeHdbInt(0));
|
|
|
|
child = AddSICSHdbPar(node,"total", usSpy, MakeSICSFunc(TotalCmd));
|
|
|
|
/*
|
|
* test TOF option
|
|
*/
|
|
if(argc > 3){
|
|
if(strcmp(argv[3],"tof") == 0){
|
|
child = MakeSICSHdbPar("time_binning", usMugger, makeHdbValue(HIPFLOATVARAR,100));
|
|
if (child == NULL) {
|
|
return 0;
|
|
}
|
|
AddHipadabaChild(node, child, NULL);
|
|
AppendHipadabaCallback(child,
|
|
MakeHipadabaCallback(HMTOFCallback, NULL, NULL));
|
|
|
|
child = AddSICSHdbPar(node,"genbin", usMugger, MakeSICSFunc(GenbinCmd));
|
|
AddSICSHdbPar(child, "start", usMugger, MakeHdbFloat(10.));
|
|
AddSICSHdbPar(child, "step", usMugger, MakeHdbFloat(10.));
|
|
AddSICSHdbPar(child, "np", usMugger, MakeHdbInt(10));
|
|
|
|
child = AddSICSHdbPar(node,"notimebin", usSpy, MakeSICSFunc(NoTimeBinCmd));
|
|
child = AddSICSHdbPar(node,"timebins", usSpy, MakeSICSFunc(TimebinsCmd));
|
|
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
/*===========================================================================
|
|
This is a set of adapter functions which make the second gen HM look like
|
|
a first generation one. This saves me from rewriting all the calculation codes
|
|
based on the first gen HM
|
|
|
|
!!!! BEWARE: In the functions below pHistMem should never be a pointer to a
|
|
HistMem but rather a second generation HM which is a counter object !!!!
|
|
===============================================================================*/
|
|
const float *GetSecHistTimeBin(pHistMem self, int *iLength)
|
|
{
|
|
float *tb = NULL;
|
|
pHdb tbNode = NULL;
|
|
int i;
|
|
pCounter pCter;
|
|
|
|
assert(self->pDes->parNode != NULL);
|
|
|
|
pCter = (pCounter)self;
|
|
tbNode = GetHipadabaNode(self->pDes->parNode,"time_binning");
|
|
if(tbNode == NULL){
|
|
return NULL;
|
|
}
|
|
*iLength = tbNode->value.arrayLength;
|
|
if(*iLength != pCter->tbLength){
|
|
if(pCter->timeBinning){
|
|
free(pCter->timeBinning);
|
|
}
|
|
pCter->timeBinning = malloc(*iLength*sizeof(float));
|
|
}
|
|
|
|
for(i = 0; i < *iLength; i++){
|
|
pCter->timeBinning[i] = tbNode->value.v.floatArray[i];
|
|
}
|
|
|
|
return (const float*)pCter->timeBinning;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
HistInt *GetSecHistogramPointer(pHistMem self,SConnection *pCon)
|
|
{
|
|
pHdb dataNode = NULL;
|
|
|
|
assert(self->pDes->parNode != NULL);
|
|
|
|
dataNode = GetHipadabaNode(self->pDes->parNode,"data");
|
|
if(dataNode == NULL){
|
|
return NULL;
|
|
}
|
|
return (HistInt *)dataNode->value.v.intArray;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int GetSecHistogram(pHistMem self, SConnection *pCon,
|
|
int i,int iStart, int iEnd, HistInt *lData, int iDataLen)
|
|
{
|
|
pHdb dataNode = NULL;
|
|
|
|
assert(self->pDes->parNode != NULL);
|
|
|
|
dataNode = GetHipadabaNode(self->pDes->parNode,"data");
|
|
if(dataNode == NULL){
|
|
return 0;
|
|
}
|
|
if(iEnd > dataNode->value.arrayLength){
|
|
iEnd = dataNode->value.arrayLength;
|
|
}
|
|
if ((iEnd - iStart) > iDataLen / sizeof(HistInt)) {
|
|
SCWrite(pCon, "WARNING: truncating request to fit data space",
|
|
eWarning);
|
|
iEnd = (iDataLen / sizeof(HistInt)) - 1;
|
|
}
|
|
memcpy(lData,dataNode->value.v.intArray+iStart, (iEnd-iStart)*sizeof(int));
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
void SecHistDirty(pHistMem self)
|
|
{
|
|
/* Nothing to do */
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int GetSecHistLength(pHistMem self)
|
|
{
|
|
pHdb dataNode = NULL;
|
|
int i, length = 1;
|
|
|
|
assert(self->pDes->parNode != NULL);
|
|
|
|
dataNode = GetHipadabaNode(self->pDes->parNode,"dim");
|
|
if(dataNode == NULL){
|
|
return 0;
|
|
}
|
|
for(i = 0; i < dataNode->value.arrayLength; i++){
|
|
length *= dataNode->value.v.intArray[i];
|
|
}
|
|
|
|
return length;
|
|
}
|