1077 lines
28 KiB
C
1077 lines
28 KiB
C
/*---------------------------------------------------------------------------
|
|
|
|
S I N Q H M D R I V
|
|
|
|
This is the SICS driver to the SINQ histogram memory.
|
|
|
|
Mark Koennecke, April 1997
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
|
|
Modified to work without counter in slave mode.
|
|
Mark Koennecke, January 2001
|
|
|
|
----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <fortify.h>
|
|
#include <sics.h>
|
|
#include <countdriv.h>
|
|
#include <counter.h>
|
|
#include <HistMem.h>
|
|
#include "hardsup/sinqhm.h"
|
|
#include "hardsup/sinqhm.i" /* for byte switching stuff */
|
|
#include <stringdict.h>
|
|
#include <HistDriv.i>
|
|
#include "sinqhmdriv.i"
|
|
/*-----------------------------------------------------------------------*/
|
|
static void PrintHMError(char *text, SConnection * pCon)
|
|
{
|
|
char pBueffel[1064];
|
|
|
|
strcpy(pBueffel, "ERROR: Histogram Memory --> ");
|
|
strlcat(pBueffel, text,1024);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void ErrInit(SinqHMDriv * self)
|
|
{
|
|
self->iLastHMError = 0;
|
|
self->iLastCTError = 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static char *pHistMode[] = {
|
|
"transparent",
|
|
"normal",
|
|
"tof",
|
|
"strobo",
|
|
"hrpt",
|
|
"psd",
|
|
"sanstof",
|
|
NULL
|
|
};
|
|
|
|
static HistMode Text2Mode(char *text)
|
|
{
|
|
int i = 0;
|
|
|
|
while (pHistMode[i] != NULL) {
|
|
if (strcmp(pHistMode[i], text) == 0) {
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
/* not found */
|
|
return -1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static char *pFlowMode[] = {
|
|
"ignore",
|
|
"ceil",
|
|
"count",
|
|
"reflect",
|
|
NULL
|
|
};
|
|
|
|
static OverFlowMode Text2Flow(char *text)
|
|
{
|
|
int i = 0;
|
|
|
|
while (pFlowMode[i] != NULL) {
|
|
if (strcmp(pFlowMode[i], text) == 0) {
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
/* not found */
|
|
return -1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
Configure deconfigures first, in order to have a clean state. Than the HM
|
|
is configured and a client connection will be built. Configure requires,
|
|
that the pSINQHM data structure has been initialised by CreateSINQHMDriver.
|
|
*/
|
|
|
|
static int SQConfigure(pHistDriver self, SConnection * pCon,
|
|
pStringDict pOpt, SicsInterp * pSics)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
int status, iMode;
|
|
char pError[132];
|
|
char pHMComputer[256], pValue[80], pBueffel[256];
|
|
float fVal;
|
|
char pcCounter[256];
|
|
CommandList *pCom = NULL;
|
|
int iStart = 0;
|
|
int iInit = 0, i, iRet;
|
|
int xOff, xFac, yOff, yFac;
|
|
int iPort, iLength;
|
|
int extraDetectors, noDet;
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
assert(pCon);
|
|
assert(pOpt);
|
|
|
|
pInternal = (SinqHMDriv *) self->pPriv;
|
|
ErrInit(pInternal);
|
|
|
|
|
|
/* enter histmode */
|
|
iRet = StringDictGet(pOpt, "histmode", pValue, 79);
|
|
if (!iRet) {
|
|
SCWrite(pCon, "ERROR: internal Value not found!", eError);
|
|
return 0;
|
|
}
|
|
strtolower(pValue);
|
|
iRet = Text2Mode(pValue);
|
|
if (iRet < 0) {
|
|
snprintf(pBueffel,255, "ERROR: Invalid parameter %s to HistMode", pValue);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pInternal->eHistMode = iRet;
|
|
|
|
/* handle overflowmode */
|
|
iRet = StringDictGet(pOpt, "overflowmode", pValue, 79);
|
|
if (!iRet) {
|
|
SCWrite(pCon, "ERROR: internal Value not found!", eError);
|
|
return 0;
|
|
}
|
|
strtolower(pValue);
|
|
iRet = Text2Flow(pValue);
|
|
if (iRet < 0) {
|
|
snprintf(pBueffel,255, "ERROR: Invalid parameter %s to OverflowMode",
|
|
pValue);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pInternal->eFlow = iRet;
|
|
|
|
/* BinWidth */
|
|
iRet = StringDictGetAsNumber(pOpt, "binwidth", &fVal);
|
|
if (!iRet) {
|
|
iRet = StringDictGet(pOpt, "binwidth", pValue, 79);
|
|
if (iRet) {
|
|
snprintf(pBueffel,255, "ERROR: %s not valid for BinWidth ", pValue);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
} else {
|
|
SCWrite(pCon, "ERROR: internal Value not found!", eError);
|
|
return 0;
|
|
}
|
|
}
|
|
if (fVal < 1) {
|
|
snprintf(pBueffel,255, "ERROR: %f is invalid for BinWidth", fVal);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pInternal->iBinWidth = (int) fVal;
|
|
|
|
/*
|
|
extra detectors
|
|
*/
|
|
iRet = StringDictGet(pOpt, "extradetector", pValue, 79);
|
|
if (iRet) {
|
|
extraDetectors = atoi(pValue);
|
|
} else {
|
|
extraDetectors = 0;
|
|
}
|
|
pInternal->extraDetector = extraDetectors;
|
|
|
|
|
|
|
|
/* check BinWidth */
|
|
if ((pInternal->iBinWidth != 1) && (pInternal->iBinWidth != 2)
|
|
&& (pInternal->iBinWidth != 4)) {
|
|
PrintHMError("Unsuported BinWidth specified, 1,2,4 are permissable",
|
|
pCon);
|
|
return 0;
|
|
}
|
|
|
|
/* if not initialised, analyze options database for the stuff we need */
|
|
if (pInternal->pMaster == NULL) {
|
|
iStart = 1;
|
|
/* the histogram memory */
|
|
status = StringDictGet(pOpt, "hmcomputer", pHMComputer, 254);
|
|
if (!status) {
|
|
PrintHMError("No network name for histogram memory computer found",
|
|
pCon);
|
|
return 0;
|
|
}
|
|
status = StringDictGetAsNumber(pOpt, "hmport", &fVal);
|
|
if (!status) {
|
|
PrintHMError("No network name for histogram memory computer found",
|
|
pCon);
|
|
return 0;
|
|
}
|
|
iPort = (int) fVal;
|
|
|
|
/* the counter */
|
|
status = StringDictGet(pOpt, "counter", pcCounter, 254);
|
|
if (!status) {
|
|
SCWrite(pCon, "WARNING: no counter control found for this HM",
|
|
eWarning);
|
|
pInternal->pCounter = NULL;
|
|
} else {
|
|
pCom = FindCommand(pSics, pcCounter);
|
|
if (!pCom) {
|
|
PrintHMError("WARNING: no counter for HM found! ", pCon);
|
|
pInternal->pCounter = NULL;
|
|
} else {
|
|
pInternal->pCounter = (pCounter) pCom->pData;
|
|
if (!pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID)) {
|
|
PrintHMError("Counter for histogram memory is invalid", pCon);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
/* ok! put in HM */
|
|
pInternal->pMaster = CreateSINQHM(pHMComputer, iPort);
|
|
if (!pInternal->pMaster) {
|
|
PrintHMError("No memory to allocate SINQHM", pCon);
|
|
return 0;
|
|
}
|
|
} else {
|
|
/* close the connection if there is such a thing */
|
|
SINQHMCloseDAQ(pInternal->pMaster);
|
|
}
|
|
|
|
/* in any case let us propagate the state of affairs to
|
|
SINQHM
|
|
*/
|
|
|
|
SINQHMSetPar(pInternal->pMaster, self->data->rank,
|
|
getHMDataLength(self->data), pInternal->iBinWidth);
|
|
|
|
|
|
/* actual configuration. On first call, check for flag INIt in
|
|
options. We do need to configure, if the HM has configured
|
|
itself already. What is does, these days.
|
|
*/
|
|
if (iStart) {
|
|
status = StringDictGetAsNumber(pOpt, "init", &fVal);
|
|
if (!status) {
|
|
iInit = 0;
|
|
} else {
|
|
if (fVal > 0.9) {
|
|
iInit = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iInit == 0) {
|
|
/* do a deconfig first */
|
|
status = SINQHMDeconfigure(pInternal->pMaster, 1);
|
|
if (status < 0) {
|
|
SINQHMError2Text(status, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return 0;
|
|
}
|
|
|
|
if ((pInternal->iBinWidth != 1) && (pInternal->iBinWidth != 2)
|
|
&& (pInternal->iBinWidth != 4)) {
|
|
PrintHMError("Unsuported BinWidth specified, 1,2,4 are permissable",
|
|
pCon);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* configure */
|
|
switch (pInternal->eHistMode) {
|
|
case eHTransparent:
|
|
iMode = SQHM__TRANS;
|
|
break;
|
|
case eHNormal:
|
|
iMode = SQHM__HM_DIG;
|
|
break;
|
|
case eHTOF:
|
|
case eSANSTOF:
|
|
iMode = SQHM__TOF;
|
|
/* recalculate some parameters */
|
|
noDet = 1;
|
|
for (i = 0; i < self->data->rank; i++) {
|
|
noDet *= self->data->iDim[i];
|
|
}
|
|
noDet += extraDetectors;
|
|
iLength = noDet * self->data->nTimeChan;
|
|
SINQHMDefineBank(pInternal->pMaster, 0, 0, noDet,
|
|
self->data->timeBinning, self->data->nTimeChan);
|
|
break;
|
|
case eHStrobo:
|
|
iMode = SQHM__HM_PSD | SQHM__STROBO;
|
|
break;
|
|
case eHRPT:
|
|
iMode = SQHM__HRPT;
|
|
break;
|
|
case ePSD:
|
|
iMode = SQHM__HM_PSD;
|
|
break;
|
|
default:
|
|
PrintHMError("Unsupported mode requested", pCon);
|
|
return 0;
|
|
}
|
|
switch (pInternal->eFlow) {
|
|
case eOIgnore:
|
|
iMode = iMode | SQHM__BO_IGN;
|
|
break;
|
|
case eOCeil:
|
|
iMode = iMode | SQHM__BO_SMAX;
|
|
break;
|
|
case eOCount:
|
|
iMode = iMode | SQHM__BO_CNT;
|
|
break;
|
|
case eReflect:
|
|
iMode = iMode | SQHM__REFLECT;
|
|
break;
|
|
default:
|
|
PrintHMError("Unsupported overflowmode requested", pCon);
|
|
return 0;
|
|
}
|
|
if (pInternal->eHistMode != ePSD) {
|
|
status = SINQHMConfigure(pInternal->pMaster,
|
|
iMode,
|
|
self->data->rank,
|
|
getHMDataLength(self->data) +
|
|
extraDetectors * self->data->nTimeChan,
|
|
pInternal->iBinWidth, 0, 0);
|
|
} else {
|
|
status = StringDictGetAsNumber(pOpt, "xoff", &fVal);
|
|
if (!status) {
|
|
PrintHMError("No xOff value for PSD mode found", pCon);
|
|
return 0;
|
|
}
|
|
xOff = (int) fVal;
|
|
status = StringDictGetAsNumber(pOpt, "xfac", &fVal);
|
|
if (!status) {
|
|
PrintHMError("No xFac value for PSD mode found", pCon);
|
|
return 0;
|
|
}
|
|
xFac = (int) fVal;
|
|
status = StringDictGetAsNumber(pOpt, "yoff", &fVal);
|
|
if (!status) {
|
|
PrintHMError("No yOff value for PSD mode found", pCon);
|
|
return 0;
|
|
}
|
|
yOff = (int) fVal;
|
|
status = StringDictGetAsNumber(pOpt, "yfac", &fVal);
|
|
if (!status) {
|
|
PrintHMError("No yFac value for PSD mode found", pCon);
|
|
return 0;
|
|
}
|
|
yFac = (int) fVal;
|
|
/* xSize and ySize are supposed to be in dim */
|
|
status = SINQHMConfigurePSD(pInternal->pMaster,
|
|
iMode,
|
|
self->data->iDim[0],
|
|
xOff,
|
|
xFac,
|
|
self->data->iDim[1] +
|
|
pInternal->extraDetector, yOff, yFac,
|
|
pInternal->iBinWidth,
|
|
self->data->timeBinning,
|
|
self->data->nTimeChan);
|
|
}
|
|
|
|
if (status < 0) {
|
|
SINQHMError2Text(status, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* initiate a client connection for DAQ */
|
|
status = SINQHMOpenDAQ(pInternal->pMaster);
|
|
if (status < 0) {
|
|
SINQHMError2Text(status, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return 0;
|
|
}
|
|
|
|
/* tell the counter box our current status */
|
|
if (pInternal->pCounter != NULL) {
|
|
SetCounterMode(pInternal->pCounter, self->eCount);
|
|
SetCounterPreset(pInternal->pCounter, self->fCountPreset);
|
|
}
|
|
|
|
self->iReconfig = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQStart(pHistDriver self, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
pICountable pCountInt = NULL;
|
|
int status, iMode, nHist, length;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* tell the counter box our current status */
|
|
if (pInternal->pCounter != NULL) {
|
|
SetCounterMode(pInternal->pCounter, self->eCount);
|
|
pInternal->pCounter->pDriv->fPreset = self->fCountPreset;
|
|
}
|
|
|
|
/* first zero the HM */
|
|
if (pInternal->eHistMode == ePSD && self->data->nTimeChan > 2) {
|
|
/*
|
|
this is special for AMOR and should be replaced by -1, -1, -1
|
|
logic ASAP
|
|
*/
|
|
nHist = (self->data->iDim[0] * self->data->iDim[1] + 2) *
|
|
self->data->nTimeChan;
|
|
status = SINQHMZero(pInternal->pMaster, -1, -1, -1);
|
|
} else {
|
|
length = getHMDataLength(self->data);
|
|
if (pInternal->extraDetector > 0 && isInTOFMode(self->data)) {
|
|
length += pInternal->extraDetector * getNoOfTimebins(self->data);
|
|
}
|
|
status = SINQHMZero(pInternal->pMaster, -1, 0, length);
|
|
}
|
|
/*
|
|
status = SINQHMZero(pInternal->pMaster,-1,-1,-1);
|
|
*/
|
|
if (status < 0) {
|
|
pInternal->iLastHMError = status;
|
|
return HWFault;
|
|
}
|
|
|
|
/* start the HM */
|
|
status = SINQHMStartDAQ(pInternal->pMaster);
|
|
if ((status < 0) && (status != DAQ_INHIBIT)) {
|
|
pInternal->iLastHMError = status;
|
|
return HWFault;
|
|
}
|
|
|
|
/*
|
|
When SICS was interrupted while the measurement was paused
|
|
the inhibit flag may still be set. We clear this here in order to
|
|
fix this bug.
|
|
*/
|
|
status = SINQHMContinueDAQ(pInternal->pMaster);
|
|
if ((status < 0) && (status != DAQ_INHIBIT)) {
|
|
pInternal->iLastHMError = status;
|
|
return HWFault;
|
|
}
|
|
|
|
|
|
/* start the El737 counter */
|
|
if (pInternal->pCounter != NULL) {
|
|
pCountInt =
|
|
pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID);
|
|
if (pCountInt) {
|
|
ReleaseCountLock(pCountInt);
|
|
return pCountInt->StartCount(pInternal->pCounter, pCon);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQPause(pHistDriver self, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
pICountable pCountInt = NULL;
|
|
int status, iMode;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* pause the HM */
|
|
status = SINQHMInhibitDAQ(pInternal->pMaster);
|
|
if ((status < 0) && (status != DAQ_INHIBIT)) {
|
|
pInternal->iLastHMError = status;
|
|
return HWFault;
|
|
}
|
|
|
|
/* pause the El737 counter */
|
|
if (pInternal->pCounter != NULL) {
|
|
pCountInt =
|
|
pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID);
|
|
if (pCountInt) {
|
|
return pCountInt->Pause(pInternal->pCounter, pCon);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQContinue(pHistDriver self, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
pICountable pCountInt = NULL;
|
|
int status, iMode;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* continue the HM */
|
|
status = SINQHMContinueDAQ(pInternal->pMaster);
|
|
if ((status < 0) && (status != DAQ_INHIBIT)) {
|
|
pInternal->iLastHMError = status;
|
|
return HWFault;
|
|
}
|
|
|
|
/* continue the El737 counter */
|
|
if (pInternal->pCounter != NULL) {
|
|
pCountInt =
|
|
pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID);
|
|
if (pCountInt) {
|
|
return pCountInt->Continue(pInternal->pCounter, pCon);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQHalt(pHistDriver self)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
pICountable pCountInt = NULL;
|
|
int status, iRet;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
iRet = 1;
|
|
|
|
/* Halt HM */
|
|
status = SINQHMStopDAQ(pInternal->pMaster);
|
|
if (status < 0) {
|
|
iRet = 0;
|
|
}
|
|
|
|
/* Halt counter */
|
|
if (pInternal->pCounter != NULL) {
|
|
pCountInt =
|
|
pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID);
|
|
if (pCountInt) {
|
|
status = pCountInt->Halt(pInternal->pCounter);
|
|
if (!status) {
|
|
iRet = 0;
|
|
} else {
|
|
iRet = 1;
|
|
}
|
|
}
|
|
return iRet;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SQStatus(pHistDriver self, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
pICountable pCountInt = NULL;
|
|
int status, iRet;
|
|
char pError[132];
|
|
int iMode, iRank, iLength, iDaq, iBin, iClient;
|
|
float fControl;
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* first check at counter */
|
|
if (pInternal->pCounter != NULL) {
|
|
pCountInt =
|
|
pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID);
|
|
if (pCountInt) {
|
|
status = pCountInt->CheckCountStatus(pInternal->pCounter, pCon);
|
|
if (status == HWFault) {
|
|
ReleaseCountLock(pCountInt);
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* now check at HM */
|
|
iRet = SINQHMGetStatus(pInternal->pMaster, &iMode, &iDaq,
|
|
&iRank, &iBin, &iLength, &iClient);
|
|
if (iRet < 0) {
|
|
SINQHMError2Text(iRet, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return HWFault;
|
|
}
|
|
|
|
if (iDaq == 2) {
|
|
return HWPause;
|
|
}
|
|
/*
|
|
else if(iDaq == 1)
|
|
{
|
|
status = HWBusy;
|
|
}
|
|
*/
|
|
else if (iDaq == 0) {
|
|
status = HWIdle;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQError(pHistDriver self, int *iCode, char *pError, int iErrLen)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* first check for HM errors */
|
|
if (pInternal->iLastHMError < 0) {
|
|
SINQHMError2Text(pInternal->iLastHMError, pError, iErrLen);
|
|
*iCode = pInternal->iLastHMError;
|
|
return 1;
|
|
}
|
|
|
|
/* now counter errors */
|
|
if (pInternal->pCounter != NULL) {
|
|
return pInternal->pCounter->pDriv->GetError(pInternal->pCounter->pDriv,
|
|
iCode, pError, iErrLen);
|
|
} else {
|
|
/* this can't be */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQFixIt(pHistDriver self, int iCode)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* check for HM Errors */
|
|
if (pInternal->iLastHMError < 0) {
|
|
switch (iCode) {
|
|
case RECEIVE_ERROR:
|
|
case INSUFFICIENT_DATA:
|
|
/* may happen after a bad command. Currently the HM-client
|
|
dies in this stage. This should fix this.
|
|
*/
|
|
SINQHMCloseDAQ(pInternal->pMaster);
|
|
SINQHMOpenDAQ(pInternal->pMaster);
|
|
return COREDO;
|
|
break;
|
|
|
|
case BYTE_ORDER_CHAOS:
|
|
case HIST_BAD_RECV:
|
|
case SEND_ERROR:
|
|
return COREDO;
|
|
break;
|
|
|
|
default:
|
|
return COTERM;
|
|
}
|
|
}
|
|
|
|
/* do counter errors */
|
|
if (pInternal->pCounter != NULL) {
|
|
return pInternal->pCounter->pDriv->TryAndFixIt(pInternal->pCounter->
|
|
pDriv, iCode);
|
|
}
|
|
return COTERM;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SQGetData(pHistDriver self, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
pICountable pCountInt = NULL;
|
|
int iMode, iDaq, iRank, iBin, iLength, iClient, iRet;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* now check at HM */
|
|
iRet = SINQHMGetStatus(pInternal->pMaster, &iMode, &iDaq,
|
|
&iRank, &iBin, &iLength, &iClient);
|
|
if (iRet < 0) {
|
|
SINQHMError2Text(iRet, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return HWFault;
|
|
}
|
|
|
|
/* stop DAQ, if still active */
|
|
/*
|
|
if(iDaq == 1)
|
|
{
|
|
SINQHMStopDAQ(pInternal->pMaster);
|
|
}
|
|
*/
|
|
|
|
/* do only counter, histograms are read on demand */
|
|
if (pInternal->pCounter != NULL) {
|
|
pCountInt =
|
|
pInternal->pCounter->pDes->GetInterface(pInternal->pCounter,
|
|
COUNTID);
|
|
if (pCountInt) {
|
|
return pCountInt->TransferData(pInternal->pCounter, pCon);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQGetHistogram(pHistDriver self, SConnection * pCon,
|
|
int iNum, int iStart, int iEnd, HistInt * plData)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
void *pData = NULL;
|
|
char *pPtr;
|
|
SQint16 *pPtr16;
|
|
SQint32 *pPtr32;
|
|
int i, iLen, iByte, status;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* we do not need to do a lot of copying when datasizes match! */
|
|
iByte = (iEnd - iStart) * pInternal->iBinWidth;
|
|
if (pInternal->iBinWidth == sizeof(HistInt)) {
|
|
/* read HM */
|
|
status = SINQHMRead(pInternal->pMaster,
|
|
iNum, iStart, iEnd, plData, iByte);
|
|
if (status < 0) {
|
|
SINQHMError2Text(status, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* we need to convert datasizes: allocate storage */
|
|
pData = (void *) malloc(iByte * sizeof(char));
|
|
if (!pData) {
|
|
PrintHMError("Out of memory in SinqHMDriv", pCon);
|
|
return 0;
|
|
}
|
|
memset(pData, 0, iByte);
|
|
|
|
/* read HM */
|
|
status =
|
|
SINQHMRead(pInternal->pMaster, iNum, iStart, iEnd, pData, iByte);
|
|
if (status < 0) {
|
|
SINQHMError2Text(status, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
return 0;
|
|
}
|
|
|
|
/* convert to correct datasize */
|
|
switch (pInternal->iBinWidth) {
|
|
case 1:
|
|
pPtr = (char *) pData;
|
|
for (i = 0; i < iEnd; i++) {
|
|
plData[i] = (HistInt) pPtr[i];
|
|
}
|
|
break;
|
|
case 2:
|
|
pPtr16 = (SQint16 *) pData;
|
|
for (i = 0; i < iEnd; i++) {
|
|
plData[i] = (HistInt) pPtr16[i];
|
|
}
|
|
break;
|
|
case 4:
|
|
/* 32 bit is native here now. May need change on other machine,
|
|
no conversion necessary
|
|
*/
|
|
pPtr32 = (SQint32 *) pData;
|
|
/* for(i = 0; i < iEnd; i++)
|
|
{
|
|
plData[i] = (HistInt)pPtr32[i];
|
|
}
|
|
*/
|
|
memcpy(plData, pPtr32, iEnd * sizeof(HistInt));
|
|
break;
|
|
}
|
|
|
|
free(pData);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQSetHistogram(pHistDriver self, SConnection * pCon,
|
|
int iNum, int iStart, int iEnd, HistInt * plData)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
void *pData = NULL;
|
|
char *pPtr;
|
|
SQint16 *pPtr16;
|
|
SQint32 *pPtr32;
|
|
int i, iLen, iByte, status;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* allocate storage */
|
|
iByte = iEnd * pInternal->iBinWidth;
|
|
pData = (void *) malloc(iByte * sizeof(char));
|
|
if (!pData) {
|
|
PrintHMError("Out of memory in SinqHMDriv", pCon);
|
|
return 0;
|
|
}
|
|
memset(pData, 0, iByte);
|
|
|
|
/* convert from long to supported binwidth */
|
|
switch (pInternal->iBinWidth) {
|
|
case 1:
|
|
pPtr = (char *) pData;
|
|
for (i = 0; i < iEnd; i++) {
|
|
pPtr[i] = plData[i];
|
|
}
|
|
break;
|
|
case 2:
|
|
pPtr16 = (SQint16 *) pData;
|
|
for (i = 0; i < iEnd; i++) {
|
|
pPtr16[i] = plData[i];
|
|
}
|
|
break;
|
|
case 4:
|
|
pPtr32 = (SQint32 *) pData;
|
|
for (i = 0; i < iEnd; i++) {
|
|
pPtr32[i] = plData[i];
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* send data */
|
|
status = SINQHMWrite(pInternal->pMaster, iNum, iStart, iEnd, pData);
|
|
if (status < 0) {
|
|
SINQHMError2Text(status, pError, 131);
|
|
PrintHMError(pError, pCon);
|
|
free(pData);
|
|
return 0;
|
|
}
|
|
|
|
free(pData);
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static long SQGetMonitor(pHistDriver self, int i, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
if (pInternal->pCounter != NULL) {
|
|
return GetMonitor(pInternal->pCounter, i, pCon);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static float SQGetTime(pHistDriver self, SConnection * pCon)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
char pError[132];
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
if (pInternal->pCounter != NULL) {
|
|
return GetCountTime(pInternal->pCounter, pCon);
|
|
}
|
|
return -999.99;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int SQPreset(pHistDriver self, SConnection * pCon, HistInt iVal)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
char pError[132];
|
|
HistInt *plData = NULL;
|
|
int i, status, nHist;
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
/* get memory */
|
|
if (pInternal->eHistMode == ePSD && self->data->nTimeChan > 2) {
|
|
nHist =
|
|
self->data->iDim[0] * self->data->iDim[1] * self->data->nTimeChan;
|
|
} else {
|
|
nHist = getHMDataLength(self->data);
|
|
}
|
|
plData = (HistInt *) malloc(nHist * sizeof(HistInt));
|
|
if (!plData) {
|
|
PrintHMError("Out of memory in SinqHMDriv", pCon);
|
|
return 0;
|
|
}
|
|
|
|
/* initialise */
|
|
for (i = 0; i < nHist; i++) {
|
|
plData[i] = iVal;
|
|
}
|
|
|
|
status = SQSetHistogram(self, pCon, -1, 0, nHist, plData);
|
|
free(plData);
|
|
return status;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int SQFreePrivate(pHistDriver self)
|
|
{
|
|
SinqHMDriv *pInternal;
|
|
|
|
assert(self);
|
|
assert(self->pPriv);
|
|
|
|
pInternal = self->pPriv;
|
|
|
|
if (pInternal->pMaster) {
|
|
DeleteSINQHM(pInternal->pMaster);
|
|
}
|
|
free(pInternal);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
pHistDriver CreateSINQDriver(pStringDict pOption)
|
|
{
|
|
pHistDriver pNew = NULL;
|
|
SinqHMDriv *pInternal = NULL;
|
|
|
|
/* create the general driver */
|
|
pNew = CreateHistDriver(pOption);
|
|
if (!pNew) {
|
|
return NULL;
|
|
}
|
|
|
|
/* add our options */
|
|
StringDictAddPair(pOption, "hmcomputer", "psds02.psi.ch");
|
|
StringDictAddPair(pOption, "hmport", "2400");
|
|
StringDictAddPair(pOption, "counter", "Rudolf");
|
|
StringDictAddPair(pOption, "xsize", "256");
|
|
StringDictAddPair(pOption, "xoff", "100");
|
|
StringDictAddPair(pOption, "xfac", "10");
|
|
StringDictAddPair(pOption, "ysize", "256");
|
|
StringDictAddPair(pOption, "yoff", "100");
|
|
StringDictAddPair(pOption, "yfac", "10");
|
|
StringDictAddPair(pOption, "init", "1");
|
|
StringDictAddPair(pOption, "histmode", "normal");
|
|
StringDictAddPair(pOption, "overflowmode", "ceil");
|
|
StringDictAddPair(pOption, "binwidth", "4");
|
|
|
|
/* initialise our private data structure */
|
|
pInternal = (SinqHMDriv *) malloc(sizeof(SinqHMDriv));
|
|
if (!pInternal) {
|
|
free(pNew);
|
|
return NULL;
|
|
}
|
|
memset(pInternal, 0, sizeof(SinqHMDriv));
|
|
pNew->pPriv = pInternal;
|
|
pInternal->eHistMode = eHNormal;
|
|
pInternal->eFlow = eOCeil;
|
|
pInternal->iBinWidth = 4;
|
|
|
|
|
|
/* configure all those functions */
|
|
pNew->Configure = SQConfigure;
|
|
pNew->Start = SQStart;
|
|
pNew->Halt = SQHalt;
|
|
pNew->GetCountStatus = SQStatus;
|
|
pNew->GetError = SQError;
|
|
pNew->TryAndFixIt = SQFixIt;
|
|
pNew->GetData = SQGetData;
|
|
pNew->GetHistogram = SQGetHistogram;
|
|
pNew->SetHistogram = SQSetHistogram;
|
|
pNew->GetMonitor = SQGetMonitor;
|
|
pNew->GetTime = SQGetTime;
|
|
pNew->Preset = SQPreset;
|
|
pNew->FreePrivate = SQFreePrivate;
|
|
pNew->Pause = SQPause;
|
|
pNew->SubSample = DefaultSubSample;
|
|
pNew->Continue = SQContinue;
|
|
|
|
return pNew;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int isSINQHMDriv(pHistDriver test)
|
|
{
|
|
if (test->Start == SQStart)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|