- Rearranged directory structure for forking out ANSTO
- Refactored site specific stuff into a site module - PSI specific stuff is now in the PSI directory. - The old version has been tagged with pre-ansto
This commit is contained in:
563
tdchm.c
Normal file
563
tdchm.c
Normal file
@ -0,0 +1,563 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
/*
|
||||
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 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;
|
||||
|
||||
status = disableTdc(tdc);
|
||||
if(status != 1){
|
||||
tdc->errorCode = COMMERROR;
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
if(tdc->counter != NULL){
|
||||
tdc->counter->pDriv->Halt(tdc->counter->pDriv);
|
||||
}
|
||||
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 disbale to 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:
|
||||
strncpy(perror,"Communication problem with TDC",iErrlen);
|
||||
break;
|
||||
case MAXEXCEEDED:
|
||||
strncpy(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{
|
||||
strncpy(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->FreePrivate = TDCFree;
|
||||
pNew->Pause = TDCPause;
|
||||
pNew->Continue = TDCContinue;
|
||||
|
||||
return pNew;
|
||||
}
|
Reference in New Issue
Block a user