- Fixed synchronisation issues - Fixed hsitogram memory writing from nxscript - Started module for writing SICS interfaces in Tcl - Fixed a bug in scan, which allowed to corrupt files - Fixed memory problems in napi5
1171 lines
33 KiB
C
1171 lines
33 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 --> ");
|
|
strcat(pBueffel,text);
|
|
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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pBueffel,"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],
|
|
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)
|
|
{
|
|
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) )
|
|
{
|
|
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->Continue = SQContinue;
|
|
|
|
return pNew;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int isSINQHMDriv(pHistDriver test)
|
|
{
|
|
if(test->Start == SQStart)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|