Files
sicspsi/tdchm.c
koennecke 1e9f9d408c - Introduced a command history log for statistical and
syntax checking input purposes
- Rectified an error message in fourmess.c
- HMcontrol did not check for the HM to stop before returning. This
  caused weird data files at AMOR as the data had not yet been downloaded
  from the HM.
- Fixed an issue about parameters in multicounter
- Temporary fix in nxscript.c to always read the Hm from the HM and not
  a buffer. This is prior to rethinking caching strategies for old style
  HM's.
- Synchronize now copies fixed motors correctly. This used to cause
  irritation with users. This now requires a script syncdrive to exist
  in the sync server which takes care of handling the fixed flag when
  this is desired.
- Added initify to sicsdata in order to copy large value timebins over
  properly at AMOR
2010-06-01 10:01:01 +00:00

609 lines
14 KiB
C

/*--------------------------------------------------------------------------
This is a driver for the TDC histogram memory as supplied with the
Risoe instruments. This system uses a Z80 processor internally.
Communication is via a GPIB interface. For more information on this
device consult documentation available from Risoe.
The TDC needs a separate counter for controlling the count operation.
The counter is connected to the TDC and inhibits histogramming when the
counter is not ready. This is alos why many of the functions in this
file chain down to a counter.
copyright: see file COPYRIGHT
Mark Koennecke, February 2003
--------------------------------------------------------------------------*/
#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 <stringdict.h>
#include <HistDriv.i>
#include "ecb.h"
/*-------------------------- private definitions -----------------------*/
typedef enum { HMX, HMY, HMXY } TDCModes;
#define MAXTDCCHANNELS (128*128)
#define COMMERROR -301
#define MAXEXCEEDED -302
/*------------------------- private data structure ---------------------*/
typedef struct {
TDCModes mode;
int map;
int bank;
unsigned char fillByte;
int range;
int n;
int errorCode;
pCounter counter;
pECB tdc;
} Tdc, *pTdc;
/*=======================================================================*/
static int downloadConfiguration(pTdc self)
{
int status;
Z80_reg in, out;
int function;
/*
map
*/
in.d = (unsigned char) self->map;
status = ecbExecute(self->tdc, 134, in, &out);
if (status != 1) {
return status;
}
/*
mode
*/
switch (self->mode) {
case HMX:
function = 129;
break;
case HMY:
function = 130;
break;
case HMXY:
function = 128;
break;
default:
assert(0);
}
status = ecbExecute(self->tdc, function, in, &out);
if (status != 1) {
return status;
}
return 1;
}
/*----------------------------------------------------------------------*/
static int TDCConfigure(pHistDriver self, SConnection * pCon,
pStringDict pOpt, SicsInterp * pSics)
{
pTdc tdc = NULL;
char pValue[80];
float value;
int status;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
status = StringDictGet(pOpt, "mode", pValue, 79);
assert(status); /* defaults should have been set in driver creation */
if (strcmp(pValue, "HMX") == 0) {
tdc->mode = HMX;
} else if (strcmp(pValue, "HMY") == 0) {
tdc->mode = HMY;
} else if (strcmp(pValue, "HMXY") == 0) {
tdc->mode = HMXY;
} else {
SCWrite(pCon, "ERROR: invalid HM mode defaulted to HMXY", eError);
tdc->mode = HMXY;
}
status = StringDictGetAsNumber(pOpt, "map", &value);
if (!status) {
SCWrite(pCon, "ERROR: invalid map value", eError);
} else {
tdc->map = (int) rint(value);
}
status = StringDictGetAsNumber(pOpt, "bank", &value);
if (!status) {
SCWrite(pCon, "ERROR: invalid bank value", eError);
} else {
tdc->bank = (int) rint(value);
if (tdc->bank != 0 && tdc->bank != 1) {
SCWrite(pCon, "ERROR: invalid bank value defaulted to 0", eError);
tdc->bank = 0;
}
}
status = StringDictGetAsNumber(pOpt, "range", &value);
if (!status) {
SCWrite(pCon, "ERROR: invalid range value", eError);
} else {
tdc->range = (int) rint(value);
}
status = StringDictGetAsNumber(pOpt, "n", &value);
if (!status) {
SCWrite(pCon, "ERROR: invalid n value", eError);
} else {
tdc->n = (int) rint(value);
}
status = StringDictGet(pOpt, "counter", pValue, 79);
/*
ignore errors here, in order to support operations without counter
*/
if (!status) {
tdc->counter = NULL;
}
tdc->counter = FindCommandData(pSics, pValue, "SingleCounter");
tdc->fillByte = 0;
status = StringDictGet(pOpt, "ecb", pValue, 79);
assert(status);
tdc->tdc = FindCommandData(pSics, pValue, "ECB");
if (tdc->tdc == NULL) {
SCWrite(pCon, "ERROR: failed to locate ECB system, critical!", eError);
return 0;
}
status = downloadConfiguration(tdc);
if (!status) {
tdc->errorCode = status;
return 0;
}
self->iReconfig = 0;
return 1;
}
/*=======================================================================*/
static int clearTdc(pTdc self, unsigned char fill)
{
Z80_reg in, out;
in.b = self->bank;
in.c = fill;
in.d = 0;
return ecbExecute(self->tdc, 133, in, &out);
}
/*---------------------------------------------------------------------*/
static int enableTdc(pTdc self)
{
Z80_reg in, out;
return 1;
/*
range and n are obscure parameters
*/
in.c = 0;
in.b = self->range;
in.d = (char) ((self->n >> 8) && 255);
in.e = (char) (self->n && 255);
return ecbExecute(self->tdc, 131, in, &out);
}
/*-----------------------------------------------------------------------*/
static int TDCStart(pHistDriver self, SConnection * pCon)
{
pTdc tdc = NULL;
int status;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
tdc->errorCode = 0;
status = clearTdc(tdc, 0);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
status = enableTdc(tdc);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
/*
start the counter if available
*/
if (tdc->counter != NULL) {
tdc->counter->pDriv->fPreset = self->fCountPreset;
tdc->counter->pDriv->eMode = self->eCount;
return tdc->counter->pDriv->Start(tdc->counter->pDriv);
}
return 1;
}
/*=====================================================================*/
static int disableTdc(pTdc self)
{
Z80_reg in, out;
return 1;
return ecbExecute(self->tdc, 132, in, &out);
}
/*-------------------------------------------------------------------*/
static int TDCHalt(pHistDriver self)
{
pTdc tdc = NULL;
int status;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
tdc->errorCode = 0;
if (tdc->counter != NULL) {
tdc->counter->pDriv->Halt(tdc->counter->pDriv);
}
status = disableTdc(tdc);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
return 1;
}
/*=====================================================================*/
static int TDCCountStatus(pHistDriver self, SConnection * pCon)
{
pTdc tdc = NULL;
int tdcstatus, status;
float fControl;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
if (tdc->counter != NULL) {
status =
tdc->counter->pDriv->GetStatus(tdc->counter->pDriv, &fControl);
}
/*
The TDC does not seem to have a means to figure if it is counting or not
or to do some sort of progress report. So it has to have an associated
counter in order to stop it at the end.
*/
/*
This is no proper fix. The proper fix would be to keep the state
in the private data structure as well and disable the TDC
on HWNoBeam and enable the TDC again if the
beam comes on. However, this is done in hardware at SANS-II. So we
leave it for now.
*/
if (status == HWIdle || status == HWFault) {
tdcstatus = disableTdc(tdc);
if (tdcstatus != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
}
return status;
}
/*=====================================================================*/
static int TDCGetError(pHistDriver self, int *iCode, char *perror,
int iErrlen)
{
pTdc tdc = NULL;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
*iCode = tdc->errorCode;
switch (tdc->errorCode) {
case COMMERROR:
strlcpy(perror, "Communication problem with TDC", iErrlen);
break;
case MAXEXCEEDED:
strlcpy(perror, "Requested to many channels for read", iErrlen);
break;
default:
if (tdc->counter != NULL) {
tdc->counter->pDriv->GetError(tdc->counter->pDriv,
iCode, perror, iErrlen);
} else {
strlcpy(perror, "Undefined error code", iErrlen);
}
break;
}
return 1;
}
/*=====================================================================*/
static int TDCFixIt(pHistDriver self, int iCode)
{
pTdc tdc = NULL;
int result;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
switch (iCode) {
case COMMERROR:
ecbClear(tdc->tdc);
result = COREDO;
break;
default:
if (tdc->counter != NULL) {
result = tdc->counter->pDriv->TryAndFixIt(tdc->counter->pDriv,
iCode);
} else {
result = COTERM;
}
break;
}
return result;
}
/*=====================================================================*/
static int TDCGetData(pHistDriver self, SConnection * pCon)
{
pTdc tdc = NULL;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
if (tdc->counter != NULL) {
return tdc->counter->pDriv->ReadValues(tdc->counter->pDriv);
}
return 1;
}
/*======================================================================*/
static long TDCGetMonitor(pHistDriver self, int i, SConnection * pCon)
{
pTdc tdc = NULL;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
if (tdc->counter != NULL) {
return GetMonitor(tdc->counter, i, pCon);
}
return -9999; /* no monitor available */
}
/*======================================================================*/
static float TDCGetTime(pHistDriver self, SConnection * pCon)
{
pTdc tdc = NULL;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
if (tdc->counter != NULL) {
return GetCountTime(tdc->counter, pCon);
}
return -9999.99; /* no time available */
}
/*=====================================================================*/
static int TDCPause(pHistDriver self, SConnection * pCon)
{
pTdc tdc = NULL;
int status;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
status = disableTdc(tdc);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
if (tdc->counter != NULL) {
return tdc->counter->pDriv->Pause(tdc->counter->pDriv);
}
return 1;
}
/*=====================================================================*/
static int TDCContinue(pHistDriver self, SConnection * pCon)
{
pTdc tdc = NULL;
int status;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
status = enableTdc(tdc);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
if (tdc->counter != NULL) {
return tdc->counter->pDriv->Continue(tdc->counter->pDriv);
}
return 1;
}
/*=======================================================================*/
static int TDCFree(pHistDriver self)
{
free(self->pPriv);
return 1;
}
/*======================================================================*/
static int TDCSetHistogram(pHistDriver self, SConnection * pCon,
int i, int iStart, int iEnd, HistInt * pData)
{
pTdc tdc = NULL;
int status;
char pBueffel[256];
Ecb_pack data;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
sprintf(pBueffel,
"WARNING: SetHistogram can only fill HM with a fill byte %s",
"\n using firts value for that");
SCWrite(pCon, pBueffel, eWarning);
data.result = pData[0];
status = clearTdc(tdc, data.b.byt0);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
return 1;
}
/*======================================================================*/
static int TDCPreset(pHistDriver self, SConnection * pCon, HistInt iVal)
{
pTdc tdc = NULL;
int status;
char pBueffel[256];
Ecb_pack data;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
sprintf(pBueffel,
"WARNING: Preset can only fill HM with a fill byte %s",
"\n using first value for that");
SCWrite(pCon, pBueffel, eWarning);
data.result = iVal;
status = clearTdc(tdc, data.b.byt0);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
return 1;
}
/*======================================================================*/
static int TDCGetHistogram(pHistDriver self, SConnection * pCon,
int bank, int iStart, int length,
HistInt * pData)
{
pTdc tdc = NULL;
int status;
unsigned short address, byteCount;
assert(self);
tdc = (pTdc) self->pPriv;
assert(tdc);
if (length > MAXTDCCHANNELS) {
tdc->errorCode = MAXEXCEEDED;
return HWFault;
}
address = (unsigned short) iStart;
/*
this is a fix because the TDC cannot send more then 64KB
*/
if (length >= 16384) {
length = 16383;
}
byteCount = length * 4;
status = ecbDMARead(tdc->tdc, address, pData, byteCount);
if (status != 1) {
tdc->errorCode = COMMERROR;
return HWFault;
}
return 1;
}
/*====================================================================*/
pHistDriver MakeTDCHM(pStringDict pOption)
{
pHistDriver pNew = NULL;
pTdc tdc = NULL;
/* create the general driver */
pNew = CreateHistDriver(pOption);
if (!pNew) {
return NULL;
}
/* add our options */
StringDictAddPair(pOption, "ecb", "blub");
StringDictAddPair(pOption, "range", "0");
StringDictAddPair(pOption, "n", "0");
StringDictAddPair(pOption, "bank", "0");
StringDictAddPair(pOption, "mode", "HMXY");
StringDictAddPair(pOption, "counter", "Gwendolin");
StringDictAddPair(pOption, "map", "9");
/* initialise our private data structure */
tdc = (pTdc) malloc(sizeof(Tdc));
if (tdc == NULL) {
free(pNew);
return NULL;
}
memset(tdc, 0, sizeof(Tdc));
tdc->map = 9;
tdc->mode = HMXY;
pNew->pPriv = tdc;
/* configure all those functions */
pNew->Configure = TDCConfigure;
pNew->Start = TDCStart;
pNew->Halt = TDCHalt;
pNew->GetCountStatus = TDCCountStatus;
pNew->GetError = TDCGetError;
pNew->TryAndFixIt = TDCFixIt;
pNew->GetData = TDCGetData;
pNew->GetHistogram = TDCGetHistogram;
pNew->SetHistogram = TDCSetHistogram;
pNew->GetMonitor = TDCGetMonitor;
pNew->GetTime = TDCGetTime;
pNew->Preset = TDCPreset;
pNew->SubSample = DefaultSubSample;
pNew->FreePrivate = TDCFree;
pNew->Pause = TDCPause;
pNew->Continue = TDCContinue;
return pNew;
}