/*----------------------------------------------------------------------------*/
/**
* @mainpage
*
* Copyright (c) 2012 Southeastern Universities Research Association, *
* Thomas Jefferson National Accelerator Facility *
* *
* This software was developed under a United States Government license *
* described in the NOTICE file included as part of this distribution. *
* *
* Authors: Bryan Moffit *
* moffit@jlab.org Jefferson Lab, MS-12B3 *
* Phone: (757) 269-5660 12000 Jefferson Ave. *
* Fax: (757) 269-5800 Newport News, VA 23606 *
* *
*----------------------------------------------------------------------------*
*
* Description:
* Primitive trigger control for VME CPUs using the TJNAF Trigger
* Supervisor (TS) card
*
*
*----------------------------------------------------------------------------*/
#ifdef VXWORKS
#include
#include
#include
#include
#include
#include
#include
#include
#else
#include
#include
#endif
#include
#include
#include
#include "jvme.h"
#include "tsLib.h"
/** Mutex to guard TS read/writes */
pthread_mutex_t tsMutex = PTHREAD_MUTEX_INITIALIZER;
/** Mutex Lock */
#define TSLOCK if(pthread_mutex_lock(&tsMutex)<0) perror("pthread_mutex_lock");
/** Mutex Unlock */
#define TSUNLOCK if(pthread_mutex_unlock(&tsMutex)<0) perror("pthread_mutex_unlock");
#define TILOCK TSLOCK
#define TIUNLOCK TSUNLOCK
#define tiVMESlot2PayloadPort tsVMESlot2PayloadPort
/* Global Variables */
volatile struct TS_A24RegStruct *TSp=NULL; /**< pointer to TS memory map */
volatile unsigned int *TSpd=NULL; /**< pointer to TS data FIFO */
unsigned long tsA24Offset=0; /**< Difference in CPU A24 Base and VME A24 Base */
unsigned int tsA32Base =0x10000000; /**< Minimum VME A32 Address for use by TS */
unsigned long tsA32Offset=0; /**< Difference in CPU A32 Base and VME A32 Base */
int tsCrateID=0x59; /**< Crate ID */
int tsBlockLevel=0; /**< Current Block level for TS */
int tsNextBlockLevel=0; /**< Next Block level for TS */
unsigned int tsIntCount = 0;
unsigned int tsAckCount = 0;
unsigned int tsDaqCount = 0; /**< Block count from previous update (in daqStatus) */
unsigned int tsReadoutMode = 0;
unsigned int tsTriggerSource = 0; /**< Set with tsSetTriggerSource(...) */
unsigned int tsSlaveMask = 0; /**< TI Slaves (mask) to be used with TI Master */
int tsDoAck = 0; /**< Instruction to perform a Readout Acknowledge */
int tsNeedAck = 0; /**< Requirement to perform a Readout Acknowledge */
static BOOL tsIntRunning = FALSE; /**< running flag */
static VOIDFUNCPTR tsIntRoutine = NULL; /**< user intererrupt service routine */
static int tsIntArg = 0; /**< arg to user routine */
static unsigned int tsIntLevel = TS_INT_LEVEL; /**< VME Interrupt level */
static unsigned int tsIntVec = TS_INT_VEC; /**< default interrupt vector */
static VOIDFUNCPTR tsAckRoutine = NULL; /**< user trigger acknowledge routine */
static int tsAckArg = 0; /**< arg to user trigger ack routine */
static int tsVersion = 0x0; /**< Firmware version */
static int tsSyncEventFlag = 0; /**< Sync Event/Block Flag */
static int tsSyncEventReceived = 0; /**< Indicates reception of sync event */
static int tsPartitionID = 0; /**< Partition ID (1-4) */
volatile struct PartitionStruct *TSpart=NULL; /**< pointer to partition registers */
static int tsDoSyncResetRequest =0; /**< Option to request a sync reset during readout ack */
static int tsSlotNumber=0; /**< Slot number in which the TI resides */
static int tsSwapTriggerBlock=0; /**< Decision on whether or not to swap the trigger block endianness */
static int tsBusError=0; /**< Bus Error block termination */
static int tsNoVXS=0; /**< 1 if not in VXS Crate */
static int tsSyncResetType=TS_SYNCCOMMAND_SYNCRESET_4US; /* Set default SyncReset Type to Fixed 4 us */
static unsigned int tsTrigPatternData[8][256]; /**< Trigger Table to be loaded */
static int tsDuplicationMode = 0; /**< 0: Normal TS Mode, 1: Duplication TS Mode */
/* Interrupt/Polling routine prototypes (static) */
static void tsInt(void);
#ifndef VXWORKS
static void tsPoll(void);
static void tsStartPollingThread(void);
static void tsPartPoll(void);
static void tsPartStartPollingThread(void);
/* polling thread pthread and pthread_attr */
pthread_attr_t tspollthread_attr;
pthread_t tspollthread;
#endif
#ifdef VXWORKS
extern int sysBusToLocalAdrs(int, char *, char **);
extern int intDisconnect(int);
extern int sysIntEnable(int);
IMPORT STATUS sysIntDisable(int);
IMPORT STATUS sysVmeDmaDone(int, int);
IMPORT STATUS sysVmeDmaSend(UINT32, UINT32, int, BOOL);
#endif
/** This is either 20 or 21 */
#define MAX_VME_SLOTS 21
/** VXS Payload Port to VME Slot map */
unsigned short PayloadPort[MAX_VME_SLOTS+1] =
{
0, /**< Filler for mythical VME slot 0 */
#if MAX_VME_SLOTS == 21
0, /**< VME Controller */
#endif
17, 15, 13, 11, 9, 7, 5, 3, 1,
0, /**< Switch Slot A - SD */
0, /**< Switch Slot B - CTP/GTP */
2, 4, 6, 8, 10, 12, 14, 16,
18 /**< VME Slot Furthest to the Right - TS */
};
/**
* @defgroup PreInit Pre-Initialization
* @defgroup Config Initialization/Configuration
* @defgroup Status Status
* @defgroup Readout Data Readout
* @defgroup IntPoll Interrupt/Polling
* @defgroup Part TS Partitioning
* @defgroup Dupl TS Duplication
* @defgroup Deprec Deprecated - To be removed
*/
/**
* @ingroup PreInit
* @brief Set the CrateID to be used during initialization
*
* @param cid Crate ID
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetCrateID_preInit(int cid)
{
if((cid<0) || (cid>0xff))
{
printf("%s: ERROR: Invalid Crate ID (%d)\n",
__FUNCTION__,cid);
return ERROR;
}
tsCrateID = cid;
return OK;
}
/**
* @ingroup Config
* @brief Initialize the TSp register space into local memory,
* and setup registers given user input
*
* @param tAddr
* - A24 VME Address of the TS
* - Slot number of TS (1 - 21)
* @param mode - Readout/Triggering Mode
* - 0: External Trigger - Interrupt Mode
* - 2: External Trigger - Polling Mode
*
* @param iFlag - Initialization mask
* - 0: Do not initialize the board, just setup the pointers to the registers
* - 2: Ignore firmware check
*
* @return OK if successful, otherwise ERROR.
*/
int
tsInit(unsigned int tAddr, unsigned int mode, int iFlag)
{
unsigned long laddr;
unsigned int rval, boardID, i2cread=0;
unsigned int firmwareInfo;
int stat;
int noBoardInit=0, noFirmwareCheck=0;
int tsType=0;
/* Check VME address */
if(tAddr<0 || tAddr>0xffffff)
{
printf("%s: ERROR: Invalid VME Address (%d)\n",__FUNCTION__,
tAddr);
}
if(tAddr==0)
{
printf("%s: Scanning for TS...\n",__FUNCTION__);
tAddr=tsFind();
if(tAddr==0)
{
printf("%s: ERROR: Unable to find TS\n",__FUNCTION__);
return ERROR;
}
}
if(tAddr<22)
{
/* User enter slot number, shift it to VME A24 address */
printf("%s: Initializing using slot number %d (VME address 0x%x)\n",
__FUNCTION__,
tAddr, tAddr<<19);
tAddr = tAddr<<19;
}
if(iFlag&TS_INIT_NO_INIT)
{
noBoardInit = 1;
}
if(iFlag&TS_INIT_SKIP_FIRMWARE_CHECK)
{
noFirmwareCheck=1;
}
if(iFlag&TS_INIT_DUPLICATION_MODE)
{
tsDuplicationMode=1;
}
else
{
tsDuplicationMode=0;
}
/* Form VME base address from slot number */
#ifdef VXWORKS
stat = sysBusToLocalAdrs(0x39,(char *)(unsigned long)tAddr,(char **)&laddr);
if (stat != 0)
{
printf("%s: ERROR: Error in sysBusToLocalAdrs res=%d \n",__FUNCTION__,stat);
return ERROR;
}
else
{
printf("TS address = 0x%lx\n",laddr);
}
#else
stat = vmeBusToLocalAdrs(0x39,(char *)(unsigned long)tAddr,(char **)&laddr);
if (stat != 0)
{
printf("%s: ERROR: Error in vmeBusToLocalAdrs res=%d \n",__FUNCTION__,stat);
return ERROR;
}
else
{
if(!noBoardInit)
printf("TS VME (Local) address = 0x%.8x (0x%.8lx)\n",tAddr,laddr);
}
#endif
tsA24Offset = laddr-tAddr;
/* Set Up pointer */
TSp = (struct TS_A24RegStruct *)laddr;
/* Check if TS board is readable */
#ifdef VXWORKS
stat = vxMemProbe((char *)(&TSp->boardID),0,4,(char *)&rval);
#else
stat = vmeMemProbe((char *)(&TSp->boardID),4,(char *)&rval);
#endif
if (stat != 0)
{
printf("%s: ERROR: TS card not addressable\n",__FUNCTION__);
TSp = NULL;
return(-1);
}
else
{
/* Check that it is a TS */
if(((rval&TS_BOARDID_TYPE_MASK)>>16) != TS_BOARDID_TYPE_TS)
{
printf("%s: ERROR: Invalid Board ID: 0x%x (rval = 0x%08x)\n",
__FUNCTION__,
(rval&TS_BOARDID_TYPE_MASK)>>16,rval);
TSp=NULL;
return(ERROR);
}
/* Check if this is board has a valid slot number */
boardID = (rval&TS_BOARDID_GEOADR_MASK)>>8;
if((boardID <= 0)||(boardID >21))
{
printf("%s: ERROR: Board Slot ID is not in range: %d\n",
__FUNCTION__,boardID);
TSp=NULL;
return(ERROR);
}
tsSlotNumber = boardID;
/* Determine whether or not we'll need to swap the trigger block endianess */
if( ((TSp->boardID & TS_BOARDID_TYPE_MASK)>>16) != TS_BOARDID_TYPE_TS)
tsSwapTriggerBlock=1;
else
tsSwapTriggerBlock=0;
}
/* Check to see if we're in a VXS Crate */
if((boardID==20) || (boardID==21))
{ /* It's possible... now check for valid i2c to SWB (SD) */
i2cread = vmeRead32(&TSp->SWB[(0x3C7C/4)]) & 0xFFFF; /* Device 1, Address 0x1F */
if((i2cread!=0) && (i2cread!=0xffff))
{ /* Valid response */
vmeSetMaximumVMESlots(boardID);
tsNoVXS=0;
}
else
{
tsNoVXS=0;
}
}
/* Check if we should exit here, or initialize some board defaults */
if(noBoardInit)
{
return OK;
}
/* Get the Firmware Information and print out some details */
firmwareInfo = tsGetFirmwareVersion();
if(firmwareInfo>0)
{
printf(" User ID: 0x%x \tFirmware (type - revision): %X - %x.%x\n",
(firmwareInfo&TS_FIRMWARE_ID_MASK)>>16,
(firmwareInfo&TS_FIRMWARE_TYPE_MASK)>>12,
(firmwareInfo&TS_FIRMWARE_MAJOR_VERSION_MASK)>>4,
firmwareInfo&TS_FIRWMARE_MINOR_VERSION_MASK);
tsVersion = firmwareInfo&0xFFF;
tsType = (firmwareInfo&TS_FIRMWARE_TYPE_MASK)>>12;
if((tsVersion < TS_SUPPORTED_FIRMWARE) || (tsType!=TS_SUPPORTED_TYPE))
{
if(noFirmwareCheck)
{
printf("%s: WARN: Type %x Firmware version (0x%x) not supported by this driver.\n Supported: Type %x version 0x%x (IGNORED)\n",
__FUNCTION__,
tsType,tsVersion,TS_SUPPORTED_TYPE,TS_SUPPORTED_FIRMWARE);
}
else
{
printf("%s: ERROR: Type %x Firmware version (0x%x) not supported by this driver.\n Supported Type %x version 0x%x\n",
__FUNCTION__,
tsType,tsVersion,TS_SUPPORTED_TYPE,TS_SUPPORTED_FIRMWARE);
TSp=NULL;
return ERROR;
}
}
}
else
{
printf("%s: ERROR: Invalid firmware 0x%08x\n",
__FUNCTION__,firmwareInfo);
return ERROR;
}
/*** SET DEFAULTS ***/
/* Disable trigger sources */
tsDisableTriggerSource(0);
tsReadoutMode = mode;
switch(mode)
{
case TS_READOUT_EXT_INT:
case TS_READOUT_EXT_POLL:
if(tsNoVXS==1)
{
/* BUSY from Loopback */
tsSetBusySource(TS_BUSY_LOOPBACK,1);
}
else
{
/* BUSY from Loopback and Switch Slot B */
tsSetBusySource(TS_BUSY_LOOPBACK | TS_BUSY_SWB,1);
}
/* Onboard Clock Source */
tsSetClockSource(TS_CLOCK_INTERNAL);
/* Loopback Sync Source */
tsSetSyncSource(TS_SYNC_LOOPBACK);
break;
default:
printf("%s: ERROR: Invalid TS Mode %d\n",
__FUNCTION__,mode);
return ERROR;
}
tsReadoutMode = mode;
/* Initialize trigger table with default patterns */
tsTriggerTableDefault();
/* Reset I2C engine */
vmeWrite32(&TSp->reset,TS_RESET_I2C);
/* Set Default Block Level to 1, and default crateID */
tsSetBlockLevel(1);
tsSetCrateID(tsCrateID);
/* Set Event format for CODA 3.0 */
tsSetEventFormat(3);
/* Setup A32 data buffer with library default */
tsSetAdr32(tsA32Base);
/* Enable Bus Errors on Block Transfer Terminiation, by default */
tsEnableBusError();
/* Set prescale factor to 1, by default */
tsSetPrescale(0);
/* MGT reset */
tsResetMGT();
/* Set this to 1 (ROC Lock mode), by default. */
tsSetBlockBufferLevel(1);
/* Setup a default Sync Delay and Pulse width */
tsSetSyncDelayWidth(0x54, 0x3f, 0);
/* Set Trigger 1 pulse delay (0*4ns = 0ns) and width [(7+1)*4ns = 32ns] */
tsSetTriggerPulse(1,0,7);
/* Set Trigger 2 pulse delay (0*4ns = 0ns) and width [(7+1)*4ns = 32ns] */
tsSetTriggerPulse(2,0,7);
return OK;
}
/**
* @ingroup Config
* @brief Find the TS within the prescribed "GEO Slot to A24 VME Address"
* range from slot 2 to 21.
*
* @return A24 VME address if found. Otherwise, 0
*/
unsigned int
tsFind()
{
int islot, stat, tsFound=0;
unsigned int tAddr, rval;
unsigned long laddr;
for(islot = 0; islot<20; islot++)
{
/* Form VME base address from slot number
Start from slot 21 and 20, then go from 2 to 19 */
switch(islot)
{
case 0:
tAddr = (21<<19);
break;
case 1:
tAddr = (20<<19);
break;
default:
tAddr = (islot<<19);
}
#ifdef VXWORKS
stat = sysBusToLocalAdrs(0x39,(char *)tAddr,(char **)&laddr);
#else
stat = vmeBusToLocalAdrs(0x39,(char *)(unsigned long)tAddr,(char **)&laddr);
#endif
if(stat != 0)
continue;
/* Check if this address is readable */
#ifdef VXWORKS
stat = vxMemProbe((char *)(laddr),0,4,(char *)&rval);
#else
stat = vmeMemProbe((char *)(laddr),4,(char *)&rval);
#endif
if (stat != 0)
{
continue;
}
else
{
/* Check that it is a TI */
if(((rval&TS_BOARDID_TYPE_MASK)>>16) != TS_BOARDID_TYPE_TS)
{
continue;
}
else
{
printf("%s: Found TS at 0x%08x\n",__FUNCTION__,tAddr);
tsFound=1;
break;
}
}
}
if(tsFound)
return tAddr;
else
return 0;
}
int
tsCheckAddresses()
{
unsigned int offset=0, expected=0, base=0;
int rval=OK;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
printf("%s:\n\t ---------- Checking TS address space ---------- \n",__FUNCTION__);
base = (unsigned long) &TSp->boardID;
offset = ((unsigned long) &TSp->trigger) - base;
expected = 0x20;
if(offset != expected)
{
printf("%s: ERROR TSp->triggerSource not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->GTPtrigger) - base;
expected = 0x40;
if(offset != expected)
{
printf("%s: ERROR TSp->GTPtrigger not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->syncWidth) - base;
expected = 0x80;
if(offset != expected)
{
printf("%s: ERROR TSp->syncWidth not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->adr24) - base;
expected = 0xD0;
if(offset != expected)
{
printf("%s: ERROR TSp->adr24 not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->reset) - base;
expected = 0x100;
if(offset != expected)
{
printf("%s: ERROR TSp->reset not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->part1) - base;
expected = 0x134;
if(offset != expected)
{
printf("%s: ERROR TSp->part1 not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->Scalers1) - base;
expected = 0x180;
if(offset != expected)
{
printf("%s: ERROR TSp->Scalers1 not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->part2) - base;
expected = 0x334;
if(offset != expected)
{
printf("%s: ERROR TSp->part2 not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->Scalers2) - base;
expected = 0x380;
if(offset != expected)
{
printf("%s: ERROR TSp->Scalers2 not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->GTPTriggerTable[0]) - base;
expected = 0x1080;
if(offset != expected)
{
printf("%s: ERROR TSp->GTPTriggerTable not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned long) &TSp->FPTriggerTable[0]) - base;
expected = 0x1090;
if(offset != expected)
{
printf("%s: ERROR TSp->FPTriggerTable not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned int) &TSp->JTAGPROMBase[0]) - base;
expected = 0x10000;
if(offset != expected)
{
printf("%s: ERROR TSp->JTAGPROMBase[0] not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned int) &TSp->JTAGFPGABase[0]) - base;
expected = 0x20000;
if(offset != expected)
{
printf("%s: ERROR TSp->JTAGFPGABase[0] not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned int) &TSp->SWA[0]) - base;
expected = 0x30000;
if(offset != expected)
{
printf("%s: ERROR TSp->SWA[0] not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
offset = ((unsigned int) &TSp->SWB[0]) - base;
expected = 0x40000;
if(offset != expected)
{
printf("%s: ERROR TSp->SWB[0] not at offset = 0x%x (@ 0x%x)\n",
__FUNCTION__,expected,offset);
rval = ERROR;
}
return rval;
}
/**
* @ingroup Status
* @brief Print some status information of the TS to standard out
*
* @param pflag if pflag>0, print out raw registers
*
*/
void
tsStatus(int pflag)
{
unsigned int boardID, fiber, intsetup;
unsigned int adr32, blocklevel, vmeControl, trigger, sync;
unsigned int busy, clock,prescale, blockBuffer;
unsigned int GTPtrigger, fpInput;
unsigned int output;
unsigned int livetime, busytime;
unsigned int inputCounter;
unsigned long TSBase;
unsigned int blockStatus[5], iblock, nblocksReady, nblocksNeedAck;
unsigned int nblocks;
unsigned int ifiber, fibermask;
unsigned int part_blockBuffer=0, part_busyConfig=0, part_busytime=0;
unsigned long long int l1a_count=0;
unsigned int blocklimit;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
l1a_count = tsGetEventCounter();
tsGetCurrentBlockLevel();
TSLOCK;
boardID = vmeRead32(&TSp->boardID);
fiber = vmeRead32(&TSp->fiber);
intsetup = vmeRead32(&TSp->intsetup);
adr32 = vmeRead32(&TSp->adr32);
blocklevel = vmeRead32(&TSp->blocklevel);
vmeControl = vmeRead32(&TSp->vmeControl);
trigger = vmeRead32(&TSp->trigger);
sync = vmeRead32(&TSp->sync);
busy = vmeRead32(&TSp->busy);
clock = vmeRead32(&TSp->clock);
prescale = vmeRead32(&TSp->trig1Prescale);
blockBuffer = vmeRead32(&TSp->blockBuffer);
GTPtrigger = vmeRead32(&TSp->GTPtrigger);
fpInput = vmeRead32(&TSp->fpInput);
output = vmeRead32(&TSp->output);
blocklimit = vmeRead32(&TSp->blocklimit);
/* Latch scalers before readout */
vmeWrite32(&TSp->reset, TS_RESET_LATCH_TIMERS);
livetime = vmeRead32(&TSp->livetime);
busytime = vmeRead32(&TSp->busytime);
inputCounter = vmeRead32(&TSp->inputCounter);
for(iblock=0;iblock<4;iblock++)
blockStatus[iblock] = vmeRead32(&TSp->blockStatus[iblock]);
blockStatus[4] = vmeRead32(&TSp->adr24);
nblocks = vmeRead32(&TSp->nblocks);
if((tsPartitionID!=0) && (TSpart!=NULL))
{
part_blockBuffer = vmeRead32(&TSpart->blockBuffer);
part_busyConfig = vmeRead32(&TSpart->busyConfig);
part_busytime = vmeRead32(&TSpart->busytime);
}
TSUNLOCK;
TSBase = (unsigned long)TSp;
printf("\n");
#ifdef VXWORKS
printf("STATUS for TS at base address 0x%08x \n",
(unsigned int) TSp);
#else
printf("STATUS for TS at VME (Local) base address 0x%08x (0x%08lx) \n",
(unsigned int)((unsigned long) TSp - tsA24Offset), (unsigned long) TSp);
#endif
printf("--------------------------------------------------------------------------------\n");
printf(" A32 Data buffer ");
if((vmeControl&TS_VMECONTROL_A32) == TS_VMECONTROL_A32)
{
printf("ENABLED at ");
#ifdef VXWORKS
printf("base address 0x%08x\n",
(unsigned int)TSpd);
#else
printf("VME (Local) base address 0x%08x (0x%08lx)\n",
(unsigned int)((unsigned long)TSpd - tsA32Offset), (unsigned long)TSpd);
#endif
}
else
printf("DISABLED\n");
printf(" Readout Count: %d\n",tsIntCount);
printf(" Ack Count: %d\n",tsAckCount);
printf(" L1A Count: %llu\n",l1a_count);
printf(" Block Count: %d\n",nblocks & TS_NBLOCKS_COUNT_MASK);
printf(" Block Limit: %d %s\n",blocklimit,
(blockBuffer & TS_BLOCKBUFFER_BUSY_ON_BLOCKLIMIT)?"* Finished *":"- In Progress -");
if(pflag>0)
{
printf(" Registers (offset):\n");
printf(" boardID (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->boardID) - TSBase, boardID);
printf(" fiber (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->fiber) - TSBase, fiber);
printf(" intsetup (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->intsetup) - TSBase, intsetup);
printf(" adr32 (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->adr32) - TSBase, adr32);
printf(" blocklevel (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->blocklevel) - TSBase, blocklevel);
printf(" vmeControl (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->vmeControl) - TSBase, vmeControl);
printf(" trigger (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->trigger) - TSBase, trigger);
printf(" sync (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->sync) - TSBase, sync);
printf(" busy (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->busy) - TSBase, busy);
printf(" clock (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->clock) - TSBase, clock);
printf(" blockBuffer (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->blockBuffer) - TSBase, blockBuffer);
printf(" output (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->output) - TSBase, output);
printf(" livetime (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->livetime) - TSBase, livetime);
printf(" busytime (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->busytime) - TSBase, busytime);
printf(" nblocks (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->nblocks) - TSBase, nblocks);
}
printf("\n");
printf(" Block Level = %d ", tsBlockLevel);
if(tsBlockLevel != tsNextBlockLevel)
printf("(To be set = %d)\n", tsNextBlockLevel);
else
printf("\n");
if(tsSlaveMask)
{
printf(" TI Slaves Configured on HFBR (0x%x) = ",tsSlaveMask);
for(ifiber=0; ifiber<2; ifiber++)
{
if( tsSlaveMask & (1<>8, (intsetup&TS_INTSETUP_VECTOR_MASK));
if(vmeControl&TS_VMECONTROL_BERR)
printf(" Bus Errors Enabled\n");
else
printf(" Bus Errors Disabled\n");
printf(" Blocks ready for readout: %d\n",(blockBuffer&TS_BLOCKBUFFER_BLOCKS_READY_MASK)>>24);
/* Slave block status */
fibermask = tsSlaveMask;
for(ifiber=0; ifiber<8; ifiber++)
{
if( fibermask & (1<>8;
}
else
{
nblocksReady = (blockStatus[(ifiber-1)/2] & TS_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[(ifiber-1)/2] & TS_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
}
printf(" Fiber %d : Blocks ready / need acknowledge: %d / %d\n",
ifiber+1,nblocksReady, nblocksNeedAck);
}
}
/* Loopback block status */
nblocksReady = (blockStatus[4] & TS_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[4] & TS_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
printf(" Loopback : Blocks ready / need acknowledge: %d / %d\n",
nblocksReady, nblocksNeedAck);
printf(" Events in current block: %d\n",
(nblocks & TS_NBLOCKS_EVENTS_IN_BLOCK_MASK)>>24);
if((tsPartitionID!=0) && (TSpart!=NULL))
{
printf("Partition ID%d\n",tsPartitionID);
printf(" blockBuffer = 0x%08x\n",part_blockBuffer);
printf(" busyConfig = 0x%08x\n",part_busyConfig);
printf(" busytime = 0x%08x\n",part_busytime);
}
printf(" Input counter %d\n",inputCounter);
printf("--------------------------------------------------------------------------------\n");
printf("\n\n");
}
/**
* @ingroup Config
* @brief Print a summary of all fiber port connections to potential TI Slaves
*
* @param pflag
* - 0 - Default output
* - 1 - Print Raw Registers
*
*/
void
tsSlaveStatus(int pflag)
{
int iport=0, ibs=0, ifiber=0;
unsigned int TSBase;
unsigned int hfbr_tiID[2];
unsigned int master_tiID;
unsigned int blockStatus[3];
unsigned int fiber=0, busy=0, trigsrc=0;
int nblocksReady=0, nblocksNeedAck=0, slaveCount=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
for(iport=0; iport<2; iport++)
{
hfbr_tiID[iport] = vmeRead32(&TSp->hfbr_tiID[iport]);
}
master_tiID = vmeRead32(&TSp->master_tiID);
fiber = vmeRead32(&TSp->fiber);
busy = vmeRead32(&TSp->busy);
trigsrc = vmeRead32(&TSp->trigger);
for(ibs=0; ibs<2; ibs++)
{
blockStatus[ibs] = vmeRead32(&TSp->blockStatus[ibs]);
}
blockStatus[3] = vmeRead32(&TSp->adr24);
TSUNLOCK;
TSBase = (unsigned int)TSp;
if(pflag>0)
{
printf(" Registers (offset):\n");
printf(" TSBase (0x%08lx)\n",TSBase-tsA24Offset);
printf(" busy (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->busy) - TSBase, busy);
printf(" fiber (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->fiber) - TSBase, fiber);
printf(" hfbr_tiID[0] (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->hfbr_tiID[0]) - TSBase, hfbr_tiID[0]);
printf(" hfbr_tiID[1] (0x%04lx) = 0x%08x\n", (unsigned long)(&TSp->hfbr_tiID[1]) - TSBase, hfbr_tiID[1]);
printf(" master_tiID (0x%04lx) = 0x%08x\t", (unsigned long)(&TSp->master_tiID) - TSBase, master_tiID);
printf("\n");
}
printf("TS Port STATUS Summary\n");
printf(" Block Status\n");
printf("Port ROCID Connected TrigSrcEn Busy Status Ready / NeedAck\n");
printf("--------------------------------------------------------------------------------\n");
/* Master first */
/* Slot and Port number */
printf("L ");
/* Port Name */
printf("%5d ",
(master_tiID&TS_ID_CRATEID_MASK)>>8);
/* Connection Status */
printf("%s %s ",
"YES",
(trigsrc & TS_TRIGGER_LOOPBACK)?"ENABLED ":"DISABLED");
/* Busy Status */
printf("%s ",
(busy & TS_BUSY_MONITOR_LOOPBACK)?"BUSY":" ");
/* Block Status */
nblocksReady = (blockStatus[3] & TS_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[3] & TS_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
printf(" %3d / %3d",nblocksReady, nblocksNeedAck);
printf("\n");
/* Slaves last */
for(iport=1; iport<2; iport++)
{
/* Only continue of this port has been configured as a slave */
if((tsSlaveMask & (1<<(iport-1)))==0) continue;
/* Slot and Port number */
printf("%d ", iport);
/* Port Name */
printf("%5d ",
(hfbr_tiID[iport-1]&TS_ID_CRATEID_MASK)>>8);
/* Connection Status */
printf("%s %s ",
"YES",
(hfbr_tiID[iport-1] & TS_ID_TRIGSRC_ENABLE_MASK)?"ENABLED ":"DISABLED");
/* Busy Status */
printf("%s ",
(busy & TS_BUSY_MONITOR_FIBER_BUSY(iport))?"BUSY":" ");
/* Block Status */
ifiber=iport-1;
if( (ifiber % 2) == 0)
{
nblocksReady = blockStatus[ifiber/2] & TS_BLOCKSTATUS_NBLOCKS_READY0;
nblocksNeedAck = (blockStatus[ifiber/2] & TS_BLOCKSTATUS_NBLOCKS_NEEDACK0)>>8;
}
else
{
nblocksReady = (blockStatus[(ifiber-1)/2] & TS_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[(ifiber-1)/2] & TS_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
}
printf(" %3d / %3d",nblocksReady, nblocksNeedAck);
printf("\n");
slaveCount++;
}
printf("\n");
printf("Total Slaves Added = %d\n",slaveCount);
}
/**
* @ingroup Status
* @brief Get the trigger sources enabled bits of the selected port
*
* @param port
* - 0 - Self
* - 1-2 - Fiber port 1-2
*
* @return bitmask of rigger sources enabled if successful, otherwise ERROR
* bitmask
* - 0 - P0
* - 1 - Fiber 1
* - 2 - Loopback
* - 3 - TRG (FP)
* - 4 - VME
* - 5 - TS Inputs (FP)
* - 6 - TS (rev 2)
* - 7 - Internal Pulser
*
*/
int
tsGetPortTrigSrcEnabled(int port)
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((port<0) || (port>3))
{
printf("%s: ERROR: Invalid port (%d)\n",
__FUNCTION__,port);
}
TSLOCK;
if(port==0)
{
rval = (vmeRead32(&TSp->master_tiID) & TS_ID_TRIGSRC_ENABLE_MASK);
}
else
{
rval = (vmeRead32(&TSp->hfbr_tiID[port-1]) & TS_ID_TRIGSRC_ENABLE_MASK);
}
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Returns the mask of fiber channels that report a "connected"
* status from a TI has it's trigger source enabled.
*
* @return Trigger Source Enabled Mask
*/
int
tsGetTrigSrcEnabledFiberMask()
{
int rval=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
if(vmeRead32(&TSp->hfbr_tiID[0]) & TS_ID_TRIGSRC_ENABLE_MASK)
rval |= (1<<1);
if(vmeRead32(&TSp->hfbr_tiID[1]) & TS_ID_TRIGSRC_ENABLE_MASK)
rval |= (1<<2);
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Get the Firmware Version
*
* @return Firmware Version if successful, ERROR otherwise
*
*/
int
tsGetFirmwareVersion()
{
unsigned int rval=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
/* reset the VME_to_JTAG engine logic */
vmeWrite32(&TSp->reset,TS_RESET_JTAG);
/* Reset FPGA JTAG to "reset_idle" state */
vmeWrite32(&TSp->JTAGFPGABase[(0x003C)>>2],0);
/* enable the user_code readback */
vmeWrite32(&TSp->JTAGFPGABase[(0x092C)>>2],0x3c8);
/* shift in 32-bit to FPGA JTAG */
vmeWrite32(&TSp->JTAGFPGABase[(0x1F1C)>>2],0);
/* Readback the firmware version */
rval = vmeRead32(&TSp->JTAGFPGABase[(0x1F1C)>>2]);
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Reload the firmware on the FPGA
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsReload()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset,TS_RESET_JTAG);
vmeWrite32(&TSp->JTAGPROMBase[(0x3c)>>2],0);
vmeWrite32(&TSp->JTAGPROMBase[(0xf2c)>>2],0xEE);
TSUNLOCK;
printf ("%s: \n FPGA Re-Load ! \n",__FUNCTION__);
return OK;
}
/**
* @ingroup Status
* @brief Get the Module Serial Number
*
* @param rSN Pointer to string to pass Serial Number
*
* @return SerialNumber if successful, ERROR otherwise
*
*/
unsigned int
tsGetSerialNumber(char **rSN)
{
unsigned int rval=0;
char retSN[10];
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset,TS_RESET_JTAG); /* reset */
vmeWrite32(&TSp->JTAGPROMBase[(0x3c)>>2],0); /* Reset_idle */
vmeWrite32(&TSp->JTAGPROMBase[(0xf2c)>>2],0xFD); /* load the UserCode Enable */
vmeWrite32(&TSp->JTAGPROMBase[(0x1f1c)>>2],0); /* shift in 32-bit of data */
rval = vmeRead32(&TSp->JTAGPROMBase[(0x1f1c)>>2]);
TSUNLOCK;
if(rSN!=NULL)
{
sprintf(retSN,"TS-%d",rval&0xfff);
strcpy((char *)rSN,retSN);
}
printf("%s: TS Serial Number is %s (0x%08x)\n",
__FUNCTION__,retSN,rval);
return rval;
}
/**
* @ingroup Config
* @brief Resync the 250 MHz Clock
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsClockResync()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_AD9510_RESYNC);
TSUNLOCK;
printf ("%s: \n\t AD9510 ReSync ! \n",__FUNCTION__);
return OK;
}
/**
* @ingroup Config
* @brief Perform a soft reset of the TS
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsReset()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset,TS_RESET_SOFT);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the crate ID
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsSetCrateID(unsigned int crateID)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(crateID>0xff)
{
printf("%s: ERROR: Invalid crate id (0x%x)\n",__FUNCTION__,crateID);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->boardID,
(vmeRead32(&TSp->boardID) & ~TS_BOARDID_CRATEID_MASK) | crateID);
tsCrateID = crateID;
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the crate ID of the selected port
*
* @param port
* - 0 - Self
* - 1-2 - Fiber port 1-2
*
* @return port Crate ID if successful, ERROR otherwise
*
*/
int
tsGetCrateID(int port)
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((port<0) || (port>2))
{
printf("%s: ERROR: Invalid port (%d)\n",
__FUNCTION__,port);
}
TSLOCK;
if(port==0)
{
rval = (vmeRead32(&TSp->master_tiID) & TS_ID_CRATEID_MASK)>>8;
}
else
{
rval = (vmeRead32(&TSp->hfbr_tiID[port-1]) & TS_ID_CRATEID_MASK)>>8;
}
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the number of events per block
* @param blockLevel Number of events per block
* @return OK if successful, ERROR otherwise
*
*/
int
tsSetBlockLevel(int blockLevel)
{
return tsBroadcastNextBlockLevel(blockLevel);
}
/**
* @ingroup Config
* @brief Broadcast the next block level (to be changed at the end of
* the next sync event, or during a call to tsSyncReset(1).
*
* @see tsSyncReset(1)
* @param blockLevel block level to broadcats
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsBroadcastNextBlockLevel(int blockLevel)
{
unsigned int trigger=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if( (blockLevel>TS_BLOCKLEVEL_MASK) || (blockLevel==0) )
{
printf("%s: ERROR: Invalid Block Level (%d)\n",__FUNCTION__,blockLevel);
return ERROR;
}
TSLOCK;
trigger = vmeRead32(&TSp->trigger);
if(!(trigger & TS_TRIGGER_VME)) /* Turn on the VME trigger, if not enabled */
vmeWrite32(&TSp->trigger, TS_TRIGGER_VME | trigger);
vmeWrite32(&TSp->triggerCommand, TS_TRIGGERCOMMAND_SET_BLOCKLEVEL | blockLevel);
if(!(trigger & TS_TRIGGER_VME)) /* Turn off the VME trigger, if it was initially disabled */
vmeWrite32(&TSp->trigger, trigger);
TSUNLOCK;
tsGetNextBlockLevel();
return OK;
}
/**
* @ingroup Status
* @brief Get the block level that will be updated on the end of the block readout.
*
* @return Next Block Level if successful, ERROR otherwise
*
*/
int
tsGetNextBlockLevel()
{
unsigned int reg_bl=0;
int bl=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
reg_bl = vmeRead32(&TSp->blocklevel);
bl = (reg_bl & TS_BLOCKLEVEL_RECEIVED_MASK)>>24;
tsNextBlockLevel=bl;
tsBlockLevel = (reg_bl & TS_BLOCKLEVEL_CURRENT_MASK)>>16;
TSUNLOCK;
return bl;
}
/**
* @ingroup Status
* @brief Get the current block level
*
* @return Next Block Level if successful, ERROR otherwise
*
*/
int
tsGetCurrentBlockLevel()
{
unsigned int reg_bl=0;
int bl=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
reg_bl = vmeRead32(&TSp->blocklevel);
bl = (reg_bl & TS_BLOCKLEVEL_CURRENT_MASK)>>16;
tsBlockLevel = bl;
tsNextBlockLevel = (reg_bl & TS_BLOCKLEVEL_RECEIVED_MASK)>>24;
TSUNLOCK;
/* Change Bus Error block termination, based on blocklevel */
if(tsBlockLevel>2)
{
tsEnableBusError();
}
else
{
tsDisableBusError();
}
return bl;
}
/**
* @ingroup Config
* @brief Set TS to instantly change blocklevel when broadcast is received.
*
* @param enable Option to enable or disable this feature
* - 0: Disable
* !0: Enable
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsSetInstantBlockLevelChange(int enable)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
if(enable)
vmeWrite32(&TSp->vmeControl,
vmeRead32(&TSp->vmeControl) | TS_VMECONTROL_BLOCKLEVEL_UPDATE);
else
vmeWrite32(&TSp->vmeControl,
vmeRead32(&TSp->vmeControl) & ~TS_VMECONTROL_BLOCKLEVEL_UPDATE);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get Status of instant blocklevel change when broadcast is received.
*
* @return 1 if enabled, 0 if disabled , ERROR otherwise
*
*/
int
tsGetInstantBlockLevelChange()
{
int rval=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->vmeControl) & TS_VMECONTROL_BLOCKLEVEL_UPDATE)>>21;
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set which GTP inputs are enabled
* @param inputmask - MASK of which GTP inputs to enable
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsSetGTPInput(unsigned int inputmask)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->GTPtrigger,inputmask);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set which FP inputs are enabled
* @param inputmask - MASK of which FP inputs (A-D) to enable
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsSetFPInput(unsigned int inputmask)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpInput,inputmask);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the trigger source
*
* This routine will set a library variable to be set in the TS registers
* at a call to tsIntEnable.
*
* @param trig - integer indicating the trigger source
* - 5: Random
* - 6: GTP/Ext/GTP
*
* @return OK if successful, ERROR otherwise
*/
int
tsSetTriggerSource(int trig)
{
unsigned int trigenable=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if( (trig>7) || (trig<0) )
{
printf("%s: ERROR: Invalid Trigger Source (%d). Must be between 0 and 7.\n",
__FUNCTION__,trig);
return ERROR;
}
/* Set VME and Loopback by default */
trigenable = TS_TRIGGER_VME;
trigenable |= TS_TRIGGER_LOOPBACK;
switch(trig)
{
case 5:
trigenable |= TS_TRIGGER_PULSER;
break;
case 6:
trigenable |= TS_TRIGGER_ENABLE;
break;
}
tsTriggerSource = trigenable;
printf("%s: INFO: tsTriggerSource = 0x%x\n",__FUNCTION__,tsTriggerSource);
return OK;
}
/**
* @ingroup Config
* @brief Set trigger sources with specified trigmask
*
* This routine is for special use when tsSetTriggerSource(...) does
* not set all of the trigger sources that is required by the user.
*
* @param trigmask bits:
* - 0: P0
* - 1: HFBR #1
* - 2: TI Master Loopback
* - 3: Front Panel (TRG) Input
* - 4: VME Trigger
* - 5: Front Panel TS Inputs
* - 6: TS (rev 2) Input
* - 7: Random Trigger
* - 8: FP/Ext/GTP
* - 9: P2 Busy
*
* @return OK if successful, ERROR otherwise
*/
int
tsSetTriggerSourceMask(int trigmask)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
/* Check input mask */
if(trigmask>TS_TRIGGER_SOURCEMASK)
{
printf("%s: ERROR: Invalid trigger source mask (0x%x).\n",
__FUNCTION__,trigmask);
return ERROR;
}
tsTriggerSource = trigmask;
return OK;
}
/**
* @ingroup Config
* @brief Enable trigger sources set by
* tsSetTriggerSource(...) or
* tsSetTriggerSourceMask(...)
*
* @sa tsSetTriggerSource tsSetTriggerSourceMask(...)
*
* @return OK if successful, ERROR otherwise
*/
int
tsEnableTriggerSource()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsTriggerSource==0)
{
printf("%s: WARN: No Trigger Sources Enabled\n",__FUNCTION__);
}
TSLOCK;
vmeWrite32(&TSp->trigger, tsTriggerSource);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Disable trigger sources
*
* @param fflag
* - 0: Disable Triggers
* - >0: Disable Triggers and generate enough triggers to fill the current block
*
* @return OK if successful, ERROR otherwise
*/
int
tsDisableTriggerSource(int fflag)
{
unsigned short ntries = 1000;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->trigger,0);
TSUNLOCK;
if(fflag)
{
tsFillToEndBlock();
if(tsCurrentBlockFilled(ntries)==ERROR)
{
printf("%s: WARN: Last block not complete after %d tries!\n",
__FUNCTION__,ntries);
}
}
return OK;
}
/**
* @ingroup Config
* @brief Set the Sync source mask
*
* @param sync - MASK indicating the sync source
* - 0: P0
* - 1: HFBR1
* - 2: HFBR5
* - 3: Front Panel
* - 4: Loopback
*
* @return OK if successful, ERROR otherwise
*/
int
tsSetSyncSource(unsigned int sync)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(sync>TS_SYNC_SOURCEMASK)
{
printf("%s: ERROR: Invalid Sync Source Mask (%d).\n",
__FUNCTION__,sync);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->sync,sync);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the event format
*
* @param format - integer number indicating the event format
* - 0: 32 bit event number only
* - 1: 32 bit event number + 32 bit timestamp
* - 2: 32 bit event number + higher 16 bits of timestamp + higher 16 bits of eventnumber
* - 3: 32 bit event number + 32 bit timestamp + higher 16 bits of timestamp + higher 16 bits of eventnumber
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsSetEventFormat(int format)
{
unsigned int formatset=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if( (format>3) || (format<0) )
{
printf("%s: ERROR: Invalid Event Format (%d). Must be between 0 and 3.\n",
__FUNCTION__,format);
return ERROR;
}
TSLOCK;
/* preserve the bits we're not setting */
/* formatset = vmeRead32(&TSp->dataFormat) & (~TS_DATAFORMAT_WORDS_MASK); */
switch(format)
{
case 0:
break;
case 1:
formatset |= TS_DATAFORMAT_TIMING_WORD;
break;
case 2:
formatset |= TS_DATAFORMAT_HIGHERBITS_WORD;
break;
case 3:
formatset |= (TS_DATAFORMAT_TIMING_WORD | TS_DATAFORMAT_HIGHERBITS_WORD);
break;
}
vmeWrite32(&TSp->dataFormat,formatset);
printf("%s: 0x%08x\n",__FUNCTION__,vmeRead32(&TSp->dataFormat));
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set and enable the "software" trigger
*
* @param trigger trigger type 1 or 2 (playback trigger)
* @param nevents integer number of events to trigger
* @param period_inc period multiplier, depends on range (0-0x7FFF)
* @param range
* - 0: small period range (min: 120ns, increments of 120ns)
* - 1: large period range (min: 120ns, increments of 245.7us)
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsSoftTrig(int trigger, unsigned int nevents, unsigned int period_inc, int range)
{
unsigned int periodMax=(TS_FIXEDPULSER1_PERIOD_MASK>>16);
unsigned int reg=0;
int time=0;
if(TSp==NULL)
{
logMsg("\ntsSoftTrig: ERROR: TS not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if(trigger!=1 && trigger!=2)
{
logMsg("\ntsSoftTrig: ERROR: Invalid trigger type %d\n",trigger,2,3,4,5,6);
return ERROR;
}
if(nevents>TS_FIXEDPULSER1_NTRIGGERS_MASK)
{
logMsg("\ntsSoftTrig: ERROR: nevents (%d) must be less than %d\n",nevents,
TS_FIXEDPULSER1_NTRIGGERS_MASK,3,4,5,6);
return ERROR;
}
if(period_inc>periodMax)
{
logMsg("\ntsSoftTrig: ERROR: period_inc (%d) must be less than %d ns\n",
period_inc,periodMax,3,4,5,6);
return ERROR;
}
if( (range!=0) && (range!=1) )
{
logMsg("\ntsSoftTrig: ERROR: range must be 0 or 1\n",
periodMax,2,3,4,5,6);
return ERROR;
}
if(range==0)
time = 120+120*period_inc;
if(range==1)
time = 120+120*period_inc*2048;
logMsg("\ntsSoftTrig: INFO: Setting software trigger for %d nevents with period of %d\n",
nevents,time,3,4,5,6);
reg = (((range<<31)| (period_inc<<16))&0xffff0000) | ((nevents)&0xffff);
TSLOCK;
if(trigger==1)
{
vmeWrite32(&TSp->fixedPulser1, reg);
printf(" TS TEST 0x%x \n", reg);
}
else if(trigger==2)
{
vmeWrite32(&TSp->fixedPulser2, reg);
}
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the parameters of the random internal trigger
*
* @param trigger - Trigger Selection
* - 1: trig1
* - 2: trig2
* @param setting - frequency prescale from 500MHz
*
* @sa tsDisableRandomTrigger
* @return OK if successful, ERROR otherwise.
*
*/
int
tsSetRandomTrigger(int trigger, int setting)
{
double rate;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(trigger!=1 && trigger!=2)
{
logMsg("\ntsSetRandomTrigger: ERROR: Invalid trigger type %d\n",trigger,2,3,4,5,6);
return ERROR;
}
if(setting>TS_RANDOMPULSER_TRIG1_RATE_MASK)
{
printf("%s: ERROR: setting (%d) must be less than %d\n",
__FUNCTION__,setting,TS_RANDOMPULSER_TRIG1_RATE_MASK);
return ERROR;
}
if(setting>0)
rate = ((double)500000) / ((double) (2<<(setting-1)));
else
rate = ((double)500000);
printf("%s: Enabling random trigger (%d) at rate (kHz) = %.2f\n",
__FUNCTION__, trigger, rate);
TSLOCK;
if(trigger==1)
vmeWrite32(&TSp->randomPulser,
setting | (setting<<4) | TS_RANDOMPULSER_TRIG1_ENABLE );
else if (trigger==2)
vmeWrite32(&TSp->randomPulser,
(setting | (setting<<4))<<8 | TS_RANDOMPULSER_TRIG2_ENABLE );
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Disable random trigger generation
* @sa tsSetRandomTrigger
* @return OK if successful, ERROR otherwise.
*/
int
tsDisableRandomTrigger()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->randomPulser,0);
TSUNLOCK;
return OK;
}
/**
* @ingroup Readout
* @brief Read a block of events from the TI
*
* @param data - local memory address to place data
* @param nwrds - Max number of words to transfer
* @param rflag - Readout Flag
* - 0 - programmed I/O from the specified board
* - 1 - DMA transfer using Universe/Tempe DMA Engine
* (DMA VME transfer Mode must be setup prior)
*
* @return Number of words transferred to data if successful, ERROR otherwise
*
*/
int
tsReadBlock(volatile unsigned int *data, int nwrds, int rflag)
{
int ii, dummy=0;
int dCnt, retVal, xferCount;
volatile unsigned int *laddr;
unsigned int vmeAdr, val;
if(TSp==NULL)
{
logMsg("\ntsReadBlock: ERROR: TS not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if(TSpd==NULL)
{
logMsg("\ntsReadBlock: ERROR: TS A32 not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if(data==NULL)
{
logMsg("\ntsReadBlock: ERROR: Invalid Destination address\n",0,0,0,0,0,0);
return(ERROR);
}
TSLOCK;
if(rflag >= 1)
{ /* Block transfer */
if(tsBusError==0)
{
logMsg("tsReadBlock: WARN: Bus Error Block Termination was disabled. Re-enabling\n",
1,2,3,4,5,6);
TSUNLOCK;
tsEnableBusError();
TSLOCK;
}
/* Assume that the DMA programming is already setup.
Don't Bother checking if there is valid data - that should be done prior
to calling the read routine */
/* Check for 8 byte boundary for address - insert dummy word (Slot 0 FADC Dummy DATA)*/
if((unsigned long) (data)&0x7)
{
#ifdef VXWORKS
*data = (TS_DATAFORMAT_DATA_TYPE_WORD) | (TS_DATAFORMAT_FILLER_WORD_TYPE) | (tsSlotNumber<<22);
#else
*data = LSWAP((TS_DATAFORMAT_DATA_TYPE_WORD) | (TS_DATAFORMAT_FILLER_WORD_TYPE) | (tsSlotNumber<<22));
#endif
dummy = 1;
laddr = (data + 1);
}
else
{
dummy = 0;
laddr = data;
}
vmeAdr = ((unsigned long)(TSpd) - tsA32Offset);
#ifdef VXWORKS
retVal = sysVmeDmaSend((UINT32)laddr, vmeAdr, (nwrds<<2), 0);
#else
retVal = vmeDmaSend((unsigned long)laddr, vmeAdr, (nwrds<<2));
#endif
if(retVal != 0)
{
logMsg("\ntsReadBlock: ERROR in DMA transfer Initialization 0x%x\n",retVal,0,0,0,0,0);
TSUNLOCK;
return(retVal);
}
/* Wait until Done or Error */
#ifdef VXWORKS
retVal = sysVmeDmaDone(10000,1);
#else
retVal = vmeDmaDone();
#endif
if(retVal > 0)
{
#ifdef VXWORKS
xferCount = (nwrds - (retVal>>2) + dummy); /* Number of longwords transfered */
#else
xferCount = ((retVal>>2) + dummy); /* Number of longwords transfered */
#endif
TSUNLOCK;
return(xferCount);
}
else if (retVal == 0)
{
#ifdef VXWORKS
logMsg("\ntsReadBlock: WARN: DMA transfer terminated by word count 0x%x\n",
nwrds,0,0,0,0,0);
#else
logMsg("\ntsReadBlock: WARN: DMA transfer returned zero word count 0x%x\n",
nwrds,0,0,0,0,0,0);
#endif
TSUNLOCK;
return(nwrds);
}
else
{ /* Error in DMA */
#ifdef VXWORKS
logMsg("\ntsReadBlock: ERROR: sysVmeDmaDone returned an Error\n",
0,0,0,0,0,0);
#else
logMsg("\ntsReadBlock: ERROR: vmeDmaDone returned an Error\n",
0,0,0,0,0,0);
#endif
TSUNLOCK;
return(retVal>>2);
}
}
else
{ /* Programmed IO */
if(tsBusError==1)
{
logMsg("tsReadBlock: WARN: Bus Error Block Termination was enabled. Disabling\n",
1,2,3,4,5,6);
TSUNLOCK;
tsDisableBusError();
TSLOCK;
}
dCnt = 0;
ii=0;
while(ii2)
{ /* Use DMA */
rflag = 1;
}
else
{ /* Use programmed I/O (Single cycle reads) */
rflag = 0;
}
/* Obtain the trigger bank by just making a call the tiReadBlock */
rval = tsReadBlock(data, nwrds, rflag);
if(rval < 0)
{
/* Error occurred */
return ERROR;
}
else if (rval == 0)
{
/* No data returned */
return 0;
}
/* Work down to find index of block header */
while(iword>27) == TS_DATAFORMAT_TYPE_BLOCK_HEADER)
{
iblkhead = iword;
break;
}
}
iword++;
}
/* Check if the index is valid */
if(iblkhead == -1)
{
logMsg("tsReadTriggerBlock: ERROR: Failed to find TS Block Header\n",
1,2,3,4,5,6);
return ERROR;
}
if(iblkhead != 0)
{
logMsg("tsReadTriggerBlock: WARN: Invalid index (%d) for the TS Block header.\n",
iblkhead,2,3,4,5,6);
}
/* Work up to find index of block trailer */
iword=rval-1;
while(iword>=0)
{
word = data[iword];
#ifndef VXWORKS
word = LSWAP(word);
#endif
if(word & TS_DATAFORMAT_DATA_TYPE_WORD)
{
if(((word & TS_DATAFORMAT_TYPE_MASK)>>27) == TS_DATAFORMAT_TYPE_BLOCK_TRAILER)
{
#ifdef CDEBUG
printf("%s: block trailer? 0x%08x\n",
__FUNCTION__,word);
#endif
iblktrl = iword;
break;
}
}
iword--;
}
/* Check if the index is valid */
if(iblktrl == -1)
{
logMsg("tsReadTriggerBlock: ERROR: Failed to find TS Block Trailer\n",
1,2,3,4,5,6);
return ERROR;
}
/* Get the block trailer, and check the number of words contained in it */
word = data[iblktrl];
#ifndef VXWORKS
word = LSWAP(word);
#endif
if((iblktrl - iblkhead + 1) != (word & 0x3fffff))
{
logMsg("tsReadTriggerBlock: Number of words inconsistent (index count = %d, block trailer count = %d\n",
(iblktrl - iblkhead + 1), word & 0x3fffff,3,4,5,6);
return ERROR;
}
/* Modify the total words returned */
rval = iblktrl - iblkhead;
/* Write in the Trigger Bank Length */
#ifdef VXWORKS
data[iblkhead] = rval-1;
#else
data[iblkhead] = LSWAP(rval-1);
#endif
if(tsSwapTriggerBlock==1)
{
for(iword=iblkhead; iwordScalers1);
scalers[1] = (struct ScalerStruct *)(&TSp->Scalers2);
scalers[2] = (struct ScalerStruct *)(&TSp->Scalers3);
scalers[3] = (struct ScalerStruct *)(&TSp->Scalers4);
TSLOCK;
switch(choice)
{
case 1: /* GTP */
banks = 8;
for(iscal=0; iscal<4; iscal++)
{
for(ichan=0; ichanGTP[ichan]);
nwrds++;
}
}
break;
case 2: /* FP */
banks = 4;
for(iscal=0; iscal<4; iscal++)
{
for(ichan=0; ichanfp[ichan]);
nwrds++;
}
}
break;
case 3: /* Gen */
banks = 8;
for(iscal=0; iscal<4; iscal++)
{
for(ichan=0; ichangen[ichan]);
nwrds++;
}
}
break;
}
TSUNLOCK;
return nwrds;
}
/**
* @ingroup Readout
* @brief Print input scalers to standard out
*
* @param choice
* - 1-4: Scaler set (1-4)
*
* @return Number of words transferred to data if successful, ERROR otherwise
*
*/
int
tsPrintScalers(int choice)
{
int ichan=0, nwrds=0;
volatile unsigned int data[64];
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
switch(choice)
{
case 1: /* GTP */
printf("GTP Scalers:\n");
break;
case 2: /* FP */
printf("FP Scalers:\n");
break;
case 3: /* Ext */
printf("Ext Scalers:\n");
break;
}
nwrds = tsReadScalers(data,choice);
for(ichan=0; ichanTS_BUSY_SOURCEMASK)
{
printf("%s: ERROR: Invalid value for sourcemask (0x%x)\n",
__FUNCTION__, sourcemask);
return ERROR;
}
if(sourcemask & TS_BUSY_P2_TRIGGER_INPUT)
{
printf("%s: ERROR: Do not use this routine to set P2 Busy as a trigger input.\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
if(rFlag)
{
/* Read in the previous value , resetting previous BUSYs*/
busybits = vmeRead32(&TSp->busy) & ~(TS_BUSY_SOURCEMASK);
}
else
{
/* Read in the previous value , keeping previous BUSYs*/
busybits = vmeRead32(&TSp->busy);
}
busybits |= sourcemask;
vmeWrite32(&TSp->busy, busybits);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Enable Bus Errors to terminate Block Reads
* @sa tsDisableBusError
* @return OK if successful, otherwise ERROR
*/
void
tsEnableBusError()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->vmeControl,
vmeRead32(&TSp->vmeControl) | (TS_VMECONTROL_BERR) );
tsBusError=1;
TSUNLOCK;
}
/**
* @ingroup Config
* @brief Disable Bus Errors to terminate Block Reads
* @sa tsEnableBusError
* @return OK if successful, otherwise ERROR
*/
void
tsDisableBusError()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->vmeControl,
vmeRead32(&TSp->vmeControl) & ~(TS_VMECONTROL_BERR) );
tsBusError=0;
TSUNLOCK;
}
/**
* @ingroup Deprec
* @brief Routine to return the VME slot, provided the VXS payload port
* @param payloadport Payload port
* @return Vme Slot
*/
int
tsPayloadPort2VMESlot(int payloadport)
{
int rval=0;
int islot;
if(payloadport<1 || payloadport>18)
{
printf("%s: ERROR: Invalid payloadport %d\n",
__FUNCTION__,payloadport);
return ERROR;
}
for(islot=1;islotMAX_VME_SLOTS)
{
printf("%s: ERROR: Invalid VME slot %d\n",
__FUNCTION__,vmeslot);
return ERROR;
}
rval = (int)PayloadPort[vmeslot];
if(rval==0)
{
printf("%s: ERROR: Unable to find Payload Port from VME Slot %d\n",
__FUNCTION__,vmeslot);
rval=ERROR;
}
return rval;
}
/**
* @ingroup Config
* @brief Set the prescale factor for the external trigger
*
* @param prescale Factor for prescale.
* Max {prescale} available is 65535
*
* @return OK if successful, otherwise ERROR.
*/
int
tsSetPrescale(int prescale)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(prescale<0 || prescale>0xffff)
{
printf("%s: ERROR: Invalid prescale (%d). Must be between 0 and 65535.",
__FUNCTION__,prescale);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->trig1Prescale, prescale);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the current prescale factor
* @return Current prescale factor, otherwise ERROR.
*/
int
tsGetPrescale()
{
int rval;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->trig1Prescale);
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the prescale for specified type and channel
* @param type Type of input
* - 1: GTP
* - 2: FP
* @param chan Channel of specified type
* @return Current prescale factor, otherwise ERROR.
*/
int
tsSetTriggerPrescale(int type, int chan, unsigned int prescale)
{
int rval=OK;
int bank=0,bitshift=0,chanmask=0xFFFF;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(type<1 || type>2)
{
printf("%s: ERROR: Invalid Trigger Prescale type %d\n",
__FUNCTION__,type);
return ERROR;
}
if(prescale>0xF)
{
printf("%s: ERROR: Invalid Trigger Prescale value 0x%x\n",
__FUNCTION__,prescale);
return ERROR;
}
TSLOCK;
switch(type)
{
case 1: /* GTP */
if(chan>32)
{
printf("%s: ERROR: Invalid GTP Prescale Channel %d\n",
__FUNCTION__,chan);
rval = ERROR;
}
bank = (int)(chan/8);
bitshift = (4*(int)(chan%8));
chanmask = (0XF)<GTPprescale[bank],
(vmeRead32(&TSp->GTPprescale[bank]) & ~chanmask) |
(prescale & chanmask));
break;
case 2: /* FP */
if(chan>32)
{
printf("%s: ERROR: Invalid FP Prescale Channel %d\n",
__FUNCTION__,chan);
rval = ERROR;
}
bank = (int)(chan/8);
bitshift = (4*(int)(chan%8));
chanmask = (0XF)<fpInputPrescale[bank],
(vmeRead32(&TSp->fpInputPrescale[bank]) & ~chanmask) |
(prescale & chanmask));
break;
}
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief FIXME: This is not quite right
*
*/
unsigned int
tsGetTriggerPrescaleMask(int type, int bank)
{
unsigned int rval=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(type<1 || type>2)
{
printf("%s: ERROR: Invalid Trigger Prescale type %d\n",
__FUNCTION__,type);
return ERROR;
}
TSLOCK;
switch(type)
{
case 1:
if(bank>3)
{
printf("%s: ERROR: Invalid GTP Trigger Prescale Bank %d\n",
__FUNCTION__,bank);
rval = ERROR;
}
else
{
rval = vmeRead32(&TSp->GTPprescale[bank]);
}
break;
case 2:
if(bank>3)
{
printf("%s: ERROR: Invalid FP Trigger Prescale Bank %d\n",
__FUNCTION__,bank);
rval = ERROR;
}
else
{
rval = vmeRead32(&TSp->fpInputPrescale[bank]);
}
break;
}
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the characteristics of a specified trigger
*
* @param trigger
* - 1: set for trigger 1
* - 2: set for trigger 2 (playback trigger)
* @param delay delay in units of 4ns
* @param width pulse width in units of 4ns
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetTriggerPulse(int trigger, int delay, int width)
{
unsigned int rval=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(trigger<1 || trigger>2)
{
printf("%s: ERROR: Invalid trigger (%d). Must be 1 or 2.\n",
__FUNCTION__,trigger);
return ERROR;
}
if(delay<0 || delay>TS_TRIGDELAY_TRIG1_DELAY_MASK)
{
printf("%s: ERROR: Invalid delay (%d). Must be less than %d\n",
__FUNCTION__,delay,TS_TRIGDELAY_TRIG1_DELAY_MASK);
return ERROR;
}
if(width<0 || width>TS_TRIGDELAY_TRIG1_WIDTH_MASK)
{
printf("%s: ERROR: Invalid width (%d). Must be less than %d\n",
__FUNCTION__,width,TS_TRIGDELAY_TRIG1_WIDTH_MASK);
}
TSLOCK;
if(trigger==1)
{
rval = vmeRead32(&TSp->trigDelay) &
~(TS_TRIGDELAY_TRIG1_DELAY_MASK | TS_TRIGDELAY_TRIG1_WIDTH_MASK) ;
rval |= ( (delay) | (width<<8) );
vmeWrite32(&TSp->trigDelay, rval);
}
if(trigger==2)
{
rval = vmeRead32(&TSp->trigDelay) &
~(TS_TRIGDELAY_TRIG2_DELAY_MASK | TS_TRIGDELAY_TRIG2_WIDTH_MASK) ;
rval |= ( (delay<<16) | (width<<24) );
vmeWrite32(&TSp->trigDelay, rval);
}
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the delay time and width of the Sync signal
*
* @param delay the delay (latency) set in units of 4ns.
* @param width the width set in units of 4ns.
* @param twidth if this is non-zero, set width in units of 32ns.
*
*/
void
tsSetSyncDelayWidth(unsigned int delay, unsigned int width, int widthstep)
{
int twidth=0, tdelay=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
if(delay>TS_SYNCDELAY_MASK)
{
printf("%s: ERROR: Invalid delay (%d)\n",__FUNCTION__,delay);
return;
}
if(width>TS_SYNCWIDTH_MASK)
{
printf("%s: WARN: Invalid width (%d).\n",__FUNCTION__,width);
return;
}
if(widthstep)
width |= TS_SYNCWIDTH_LONGWIDTH_ENABLE;
tdelay = delay*4;
if(widthstep)
twidth = (width&TS_SYNCWIDTH_MASK)*32;
else
twidth = width*4;
printf("%s: Setting Sync delay = %d (ns) width = %d (ns)\n",
__FUNCTION__,tdelay,twidth);
TSLOCK;
vmeWrite32(&TSp->syncDelay,delay);
vmeWrite32(&TSp->syncWidth,width);
TSUNLOCK;
}
/**
* @ingroup Config
* @brief Reset the trigger link.
*/
void
tsTrigLinkReset()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_TRIGGERLINK_DISABLE);
taskDelay(1);
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_TRIGGERLINK_DISABLE);
taskDelay(1);
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_TRIGGERLINK_ENABLE);
taskDelay(1);
TSUNLOCK;
printf ("%s: Trigger Data Link was reset.\n",__FUNCTION__);
}
/**
* @ingroup Config
* @brief Disable the trigger link.
*/
void
tsTrigLinkDisable()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_TRIGGERLINK_DISABLE);
taskDelay(1);
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_TRIGGERLINK_DISABLE);
taskDelay(1);
TSUNLOCK;
printf ("%s: Trigger Data Link was Disabled.\n",__FUNCTION__);
}
/**
* @ingroup Config
* @brief Set type of SyncReset to send to TI Slaves
*
* @param type Sync Reset Type
* - 0: User programmed width in each TI
* - !0: Fixed 4 microsecond width in each TI
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetSyncResetType(int type)
{
if(type)
tsSyncResetType=TS_SYNCCOMMAND_SYNCRESET_4US;
else
tsSyncResetType=TS_SYNCCOMMAND_SYNCRESET;
return OK;
}
/**
* @ingroup Config
* @brief Generate a Sync Reset signal.
*
* @param blflag Option to change block level, after SyncReset issued
* - 0: Do not change block level
* - >0: Broadcast block level to all connected slaves (including self)
* BlockLevel broadcasted will be set to library value
* (Set with tsSetBlockLevel)
*
*/
void
tsSyncReset(int blflag)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,tsSyncResetType);
taskDelay(1);
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_RESET_EVNUM);
taskDelay(1);
TSUNLOCK;
if(blflag) /* Set the block level from "Next" to Current */
{
printf("%s: INFO: Setting Block Level to %d\n",
__FUNCTION__,tsNextBlockLevel);
tsBroadcastNextBlockLevel(tsNextBlockLevel);
}
}
/**
* @ingroup Config
* @brief Generate a Sync Reset Resync signal.
*
* This type of Sync Reset will NOT reset event numbers
*
*/
void
tsSyncResetResync()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,tsSyncResetType);
taskDelay(1);
TSUNLOCK;
}
/**
* @ingroup Config
* @brief Generate a Clock Reset signal. This signal is sent to the loopback and
* all configured TI Slaves.
*
*/
void
tsClockReset()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_CLK250_RESYNC);
TSUNLOCK;
}
/**
* @ingroup Config
* @brief Control level of the SyncReset signal
* @sa tsSetUserSyncResetReceive
* @param enable
* - >0: High
* - 0: Low
*/
void
tsUserSyncReset(int enable)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
if(enable)
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_SYNCRESET_HIGH);
else
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_SYNCRESET_LOW);
taskDelay(2);
TSUNLOCK;
printf("%s: User Sync Reset ",__FUNCTION__);
if(enable)
printf("HIGH\n");
else
printf("LOW\n");
}
/**
* @ingroup Config
* @brief Reset the registers that record the triggers enabled status of TI Slaves.
*
*/
void
tsTriggerReadyReset()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->syncCommand,TS_SYNCCOMMAND_TRIGGER_READY_RESET);
TSUNLOCK;
}
/**
* @ingroup Config
* @brief Routine to set the A32 Base
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetAdr32(unsigned int a32base)
{
unsigned long laddr=0;
int res=0,a32Enabled=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(a32base<0x00800000)
{
printf("%s: ERROR: a32base out of range (0x%08x)\n",
__FUNCTION__,a32base);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->adr32,
(a32base & TS_ADR32_BASE_MASK) );
vmeWrite32(&TSp->vmeControl,
vmeRead32(&TSp->vmeControl) | TS_VMECONTROL_A32);
a32Enabled = vmeRead32(&TSp->vmeControl)&(TS_VMECONTROL_A32);
if(!a32Enabled)
{
printf("%s: ERROR: Failed to enable A32 Address\n",__FUNCTION__);
TSUNLOCK;
return ERROR;
}
#ifdef VXWORKS
res = sysBusToLocalAdrs(0x09,(char *)a32base,(char **)&laddr);
if (res != 0)
{
printf("%s: ERROR in sysBusToLocalAdrs(0x09,0x%x,&laddr) \n",
__FUNCTION__,a32base);
TSUNLOCK;
return(ERROR);
}
#else
res = vmeBusToLocalAdrs(0x09,(char *)(unsigned long)a32base,(char **)&laddr);
if (res != 0)
{
printf("%s: ERROR in vmeBusToLocalAdrs(0x09,0x%x,&laddr) \n",
__FUNCTION__,a32base);
TSUNLOCK;
return(ERROR);
}
#endif
tsA32Base = a32base;
tsA32Offset = laddr - tsA32Base;
TSpd = (unsigned int *)(laddr); /* Set a pointer to the FIFO */
TSUNLOCK;
printf("%s: A32 Base address set to 0x%08x\n",
__FUNCTION__,tsA32Base);
return OK;
}
/**
* @ingroup Config
* @brief Reset the L1A counter, as incremented by the TS.
*
* @return OK if successful, otherwise ERROR
*/
int
tsResetEventCounter()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset, TS_RESET_RESET_L1A_NUMBER);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Returns the event counter (48 bit)
*
* @return Number of accepted events if successful, otherwise ERROR
*/
unsigned long long int
tsGetEventCounter()
{
unsigned long long int rval=0;
unsigned int lo=0, hi=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
lo = vmeRead32(&TSp->eventNumber_lo);
hi = (vmeRead32(&TSp->eventNumber_hi) & TS_EVENTNUMBER_HI_MASK)>>16;
rval = lo | ((unsigned long long)hi<<32);
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the block number at which triggers will be disabled automatically
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetBlockLimit(unsigned int limit)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->blocklimit,limit);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Returns the value that is currently programmed as the block limit
*
* @return Current Block Limit if successful, otherwise ERROR
*/
unsigned int
tsGetBlockLimit()
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->blocklimit);
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Get the current status of the block limit
*
* @return 1 if block limit has been reached, 0 if not, otherwise ERROR;
*
*/
int
tsGetBlockLimitStatus()
{
unsigned int reg=0, rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
reg = vmeRead32(&TSp->blockBuffer) & TS_BLOCKBUFFER_BUSY_ON_BLOCKLIMIT;
if(reg)
rval = 1;
else
rval = 0;
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set whether or not the latched pattern of GTP Inputs in block readout
*
* @param enable
* - 0: Disable
* - >0: Enable
*
* @return OK if successful, otherwise ERROR
*
*/
int
tsSetGTPInputReadout(int enable)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
if(enable)
vmeWrite32(&TSp->dataFormat,
vmeRead32(&TSp->dataFormat) | TS_DATAFORMAT_GTPINPUT_READOUT);
else
vmeWrite32(&TSp->dataFormat,
vmeRead32(&TSp->dataFormat) & ~TS_DATAFORMAT_GTPINPUT_READOUT);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set whether or not the latched pattern of FP Inputs in block readout
*
* @param enable
* - 0: Disable
* - >0: Enable
*
* @return OK if successful, otherwise ERROR
*
*/
int
tsSetFPInputReadout(int enable)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
if(enable)
vmeWrite32(&TSp->dataFormat,
vmeRead32(&TSp->dataFormat) | TS_DATAFORMAT_FPINPUT_READOUT);
else
vmeWrite32(&TSp->dataFormat,
vmeRead32(&TSp->dataFormat) & ~TS_DATAFORMAT_FPINPUT_READOUT);
TSUNLOCK;
return OK;
}
/*************************************************************
TS Interrupt/Polling routines
*************************************************************/
/**
* @ingroup Status
* @brief Return current readout count
*/
unsigned int
tsGetIntCount()
{
return(tsIntCount);
}
/*************************************************************
Interrupt/Polling routines
*************************************************************/
/*******************************************************************************
*
* tsInt
* - Default interrupt handler
* Handles the TS interrupt. Calls a user defined routine,
* if it was connected with tsIntConnect()
*
*/
static void
tsInt(void)
{
tsIntCount++;
INTLOCK;
if (tsIntRoutine != NULL) /* call user routine */
(*tsIntRoutine) (tsIntArg);
/* Acknowledge trigger */
if(tsDoAck==1)
{
tsIntAck();
}
INTUNLOCK;
}
/*******************************************************************************
*
* tsPoll
* - Default Polling Server Thread
* Handles the polling of latched triggers. Calls a user
* defined routine if was connected with tsIntConnect.
*
*/
#ifndef VXWORKS
static void
tsPoll(void)
{
int tsdata;
int policy=0;
struct sched_param sp;
/* Set scheduler and priority for this thread */
policy=SCHED_FIFO;
sp.sched_priority=40;
printf("%s: Entering polling loop...\n",__FUNCTION__);
pthread_setschedparam(pthread_self(),policy,&sp);
pthread_getschedparam(pthread_self(),&policy,&sp);
printf ("%s: INFO: Running at %s/%d\n",__FUNCTION__,
(policy == SCHED_FIFO ? "FIFO"
: (policy == SCHED_RR ? "RR"
: (policy == SCHED_OTHER ? "OTHER"
: "unknown"))), sp.sched_priority);
prctl(PR_SET_NAME,"tsPoll");
while(1)
{
pthread_testcancel();
/* If still need Ack, don't test the Trigger Status */
if(tsNeedAck>0)
{
continue;
}
tsdata = 0;
tsdata = tsBReady();
if(tsdata == ERROR)
{
printf("%s: ERROR: tsIntPoll returned ERROR.\n",__FUNCTION__);
break;
}
if(tsdata && tsIntRunning)
{
INTLOCK;
tsDaqCount = tsdata;
tsIntCount++;
if (tsIntRoutine != NULL) /* call user routine */
(*tsIntRoutine) (tsIntArg);
/* Write to TS to Acknowledge Interrupt */
if(tsDoAck==1)
{
tsIntAck();
}
INTUNLOCK;
}
}
printf("%s: Read ERROR: Exiting Thread\n",__FUNCTION__);
pthread_exit(0);
}
#endif
/*******************************************************************************
*
* tsStartPollingThread
* - Routine that launches tsPoll in its own thread
*
*/
#ifndef VXWORKS
static void
tsStartPollingThread(void)
{
int pts_status;
pts_status =
pthread_create(&tspollthread,
NULL,
(void*(*)(void *)) tsPoll,
(void *)NULL);
if(pts_status!=0)
{
printf("%s: ERROR: TS Polling Thread could not be started.\n",
__FUNCTION__);
printf("\t pthread_create returned: %d\n",pts_status);
}
}
#endif
/**
* @ingroup IntPoll
* @brief Connect a user routine to the TS Interrupt or
* latched trigger, if polling.
*
* @param vector VME Interrupt Vector
* @param routine Routine to call if block is available
* @param arg argument to pass to routine
*
* @return OK if successful, otherwise ERROR
*/
int
tsIntConnect(unsigned int vector, VOIDFUNCPTR routine, unsigned int arg)
{
#ifndef VXWORKS
int status;
#endif
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return(ERROR);
}
#ifdef VXWORKS
/* Disconnect any current interrupts */
if((intDisconnect(tsIntVec) !=0))
printf("%s: Error disconnecting Interrupt\n",__FUNCTION__);
#endif
tsResetEventCounter();
tsIntCount = 0;
tsAckCount = 0;
tsDoAck = 1;
/* Set Vector and Level */
if((vector < 0xFF)&&(vector > 0x40))
{
tsIntVec = vector;
}
else
{
tsIntVec = TS_INT_VEC;
}
TSLOCK;
vmeWrite32(&TSp->intsetup, (tsIntLevel<<8) | tsIntVec );
TSUNLOCK;
switch (tsReadoutMode)
{
case TS_READOUT_EXT_POLL:
break;
case TS_READOUT_EXT_INT:
#ifdef VXWORKS
intConnect(INUM_TO_IVEC(tsIntVec),tsInt,arg);
#else
status = vmeIntConnect (tsIntVec, tsIntLevel,
tsInt,arg);
if (status != OK)
{
printf("%s: vmeIntConnect failed with status = 0x%08x\n",
__FUNCTION__,status);
return(ERROR);
}
#endif
break;
default:
printf("%s: ERROR: TS Mode not defined (%d)\n",
__FUNCTION__,tsReadoutMode);
return ERROR;
}
printf("%s: INFO: Interrupt Vector = 0x%x Level = %d\n",
__FUNCTION__,tsIntVec,tsIntLevel);
if(routine)
{
tsIntRoutine = routine;
tsIntArg = arg;
}
else
{
tsIntRoutine = NULL;
tsIntArg = 0;
}
return(OK);
}
/**
* @ingroup IntPoll
* @brief Disable interrupts or kill the polling service thread
*
*
* @return OK if successful, otherwise ERROR
*/
int
tsIntDisconnect()
{
#ifndef VXWORKS
int status;
void *res;
#endif
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsIntRunning)
{
logMsg("tsIntDisconnect: ERROR: TS is Enabled - Call tsIntDisable() first\n",
1,2,3,4,5,6);
return ERROR;
}
INTLOCK;
switch (tsReadoutMode)
{
case TS_READOUT_EXT_INT:
#ifdef VXWORKS
/* Disconnect any current interrupts */
sysIntDisable(tsIntLevel);
if((intDisconnect(tsIntVec) !=0))
printf("%s: Error disconnecting Interrupt\n",__FUNCTION__);
#else
status = vmeIntDisconnect(tsIntLevel);
if (status != OK)
{
printf("vmeIntDisconnect failed\n");
}
#endif
break;
case TS_READOUT_EXT_POLL:
#ifndef VXWORKS
if(tspollthread)
{
if(pthread_cancel(tspollthread)<0)
perror("pthread_cancel");
if(pthread_join(tspollthread,&res)<0)
perror("pthread_join");
if (res == PTHREAD_CANCELED)
printf("%s: Polling thread canceled\n",__FUNCTION__);
else
printf("%s: ERROR: Polling thread NOT canceled\n",__FUNCTION__);
}
#endif
break;
default:
break;
}
INTUNLOCK;
printf("%s: Disconnected\n",__FUNCTION__);
return OK;
}
/**
* @ingroup IntPoll
* @brief Connect a user routine to be executed instead of the default
* TS interrupt/trigger latching acknowledge prescription
*
* @param routine Routine to call
* @param arg argument to pass to routine
* @return OK if successful, otherwise ERROR
*/
int
tsAckConnect(VOIDFUNCPTR routine, unsigned int arg)
{
if(routine)
{
tsAckRoutine = routine;
tsAckArg = arg;
}
else
{
printf("%s: WARN: routine undefined.\n",__FUNCTION__);
tsAckRoutine = NULL;
tsAckArg = 0;
return ERROR;
}
return OK;
}
/**
* @ingroup IntPoll
* @brief Acknowledge an interrupt or latched trigger. This "should" effectively
* release the "Busy" state of the TS.
*
* Execute a user defined routine, if it is defined. Otherwise, use
* a default prescription.
*/
void
tsIntAck()
{
int resetbits=0;
if(TSp == NULL) {
logMsg("tsIntAck: ERROR: TS not initialized\n",0,0,0,0,0,0);
return;
}
if (tsAckRoutine != NULL)
{
/* Execute user defined Acknowlege, if it was defined */
TSLOCK;
(*tsAckRoutine) (tsAckArg);
TSUNLOCK;
}
else
{
TSLOCK;
tsDoAck = 1;
tsAckCount++;
resetbits = TS_RESET_BUSYACK;
if(tsDoSyncResetRequest)
{
resetbits |= TS_RESET_SYNCRESET_REQUEST;
tsDoSyncResetRequest=0;
}
vmeWrite32(&TSp->reset,resetbits);
TSUNLOCK;
}
}
/**
* @ingroup IntPoll
* @brief Enable interrupts or latching triggers (depending on set TS mode)
*
* @param iflag if = 1, trigger counter will be reset
*
* @return OK if successful, otherwise ERROR
*/
int
tsIntEnable(int iflag)
{
#ifdef VXWORKS
int lock_key=0;
#endif
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return(-1);
}
if(iflag == 1)
{
tsResetEventCounter();
tsIntCount = 0;
tsAckCount = 0;
}
TSLOCK;
tsIntRunning = 1;
tsDoAck = 1;
tsNeedAck = 0;
switch (tsReadoutMode)
{
#ifndef VXWORKS
case TS_READOUT_EXT_POLL:
tsStartPollingThread();
break;
#endif
case TS_READOUT_EXT_INT:
#ifdef VXWORKS
lock_key = intLock();
sysIntEnable(tsIntLevel);
#endif
vmeWrite32(&TSp->intsetup,
vmeRead32(&TSp->intsetup) | TS_INTSETUP_ENABLE );
break;
default:
tsIntRunning = 0;
#ifdef VXWORKS
if(lock_key)
intUnlock(lock_key);
#endif
printf("%s: ERROR: TS Readout Mode not defined %d\n",
__FUNCTION__,tsReadoutMode);
TSUNLOCK;
return(ERROR);
}
TSUNLOCK; /* Locks performed in tsEnableTriggerSource() */
taskDelay(30);
tsEnableTriggerSource();
#ifdef VXWORKS
if(lock_key)
intUnlock(lock_key);
#endif
return(OK);
}
/**
* @ingroup IntPoll
* @brief Disable interrupts or latching triggers
*
*/
void
tsIntDisable()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
tsDisableTriggerSource(0);
TSLOCK;
vmeWrite32(&TSp->intsetup,
vmeRead32(&TSp->intsetup) & ~(TS_INTSETUP_ENABLE));
tsIntRunning = 0;
TSUNLOCK;
}
/**
* @ingroup Readout
* @brief Returns the number of Blocks available for readout
*
* @return Number of blocks available for readout if successful, otherwise ERROR
*
*/
unsigned int
tsBReady()
{
unsigned int blockBuffer=0, readyInt=0, rval=0;
if(TSp == NULL)
{
logMsg("tsBReady: ERROR: TS not initialized\n",1,2,3,4,5,6);
return 0;
}
TSLOCK;
blockBuffer = vmeRead32(&TSp->blockBuffer);
rval = (blockBuffer&TS_BLOCKBUFFER_BLOCKS_READY_MASK)>>8;
readyInt = (blockBuffer&TS_BLOCKBUFFER_BREADY_INT_MASK)>>24;
tsSyncEventReceived = (blockBuffer&TS_BLOCKBUFFER_SYNCEVENT)>>31;
if( (readyInt==1) && (tsSyncEventReceived) )
tsSyncEventFlag = 1;
else
tsSyncEventFlag = 0;
TSUNLOCK;
return rval;
}
/**
* @ingroup Readout
* @brief Return the value of the Synchronization flag, obtained from tsBReady.
* i.e. Return the value of the SyncFlag for the current readout block.
*
* @sa tsBReady
* @return
* - 1: if current readout block contains a Sync Event.
* - 0: Otherwise
*
*/
int
tsGetSyncEventFlag()
{
int rval=0;
TSLOCK;
rval = tsSyncEventFlag;
TSUNLOCK;
return rval;
}
/**
* @ingroup Readout
* @brief Return the value of whether or not the sync event has been received
*
* @return
* - 1: if sync event received
* - 0: Otherwise
*
*/
int
tsGetSyncEventReceived()
{
int rval=0;
TSLOCK;
rval = tsSyncEventReceived;
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the block buffer level for the number of blocks in the system
* that need to be read out.
*
* If this buffer level is full, the TI will go BUSY.
* The BUSY is released as soon as the number of buffers in the system
* drops below this level.
*
* @param level
* - 0: No Buffer Limit - Pipeline mode
* - 1: One Block Limit - "ROC LOCK" mode
* - 2-65535: "Buffered" mode.
*
* @return OK if successful, otherwise ERROR
*
*/
int
tsSetBlockBufferLevel(unsigned int level)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(level>TS_BLOCKBUFFER_BUFFERLEVEL_MASK)
{
printf("%s: ERROR: Invalid value for level (%d)\n",
__FUNCTION__,level);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->blockBuffer, level);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set (or unset) high level for the user controllable output ports on the front panel.
*
* @param set1 OUT #3
* @param set2 OUT #4
* @param set3 OUT #5
* @param set4 OUT #6
* @param set5 OUT #11
* @param set6 OUT #12
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetOutputPort(unsigned int set1, unsigned int set2, unsigned int set3,
unsigned int set4, unsigned int set5, unsigned int set6)
{
unsigned int bits=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(set1)
bits |= TS_OUTPUT_FP_1;
if(set2)
bits |= TS_OUTPUT_FP_2;
if(set3)
bits |= TS_OUTPUT_FP_3;
if(set4)
bits |= TS_OUTPUT_FP_4;
if(set5)
bits |= TS_OUTPUT_FP_5;
if(set6)
bits |= TS_OUTPUT_FP_6;
TSLOCK;
vmeWrite32(&TSp->output, bits);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the clock to the specified source.
*
* @param source
* - 0: Onboard clock
* - 1: External clock (FP input)
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetClockSource(unsigned int source)
{
unsigned int clkset=0;
char sClock[20] = "";
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
switch(source)
{
case 0: /* ONBOARD */
clkset = TS_CLOCK_INTERNAL;
sprintf(sClock,"ONBOARD (%d)",source);
break;
case 1: /* EXTERNAL (FP) */
clkset = TS_CLOCK_EXTERNAL;
sprintf(sClock,"EXTERNAL (%d)",source);
break;
default:
printf("%s: ERROR: Invalid Clock Souce (%d)\n",__FUNCTION__,source);
return ERROR;
}
printf("%s: Setting clock source to %s\n",__FUNCTION__,sClock);
TSLOCK;
vmeWrite32(&TSp->clock, clkset);
/* Reset DCM (Digital Clock Manager) - 250/200MHz */
vmeWrite32(&TSp->reset,TS_RESET_CLK250);
taskDelay(1);
/* Reset DCM (Digital Clock Manager) - 125MHz */
vmeWrite32(&TSp->reset,TS_RESET_CLK125);
taskDelay(1);
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Reset the IO Delay on the TS
*
*/
void
tsResetIODelay()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeWrite32(&TSp->reset,TS_RESET_IODELAY);
taskDelay(10);
TSUNLOCK;
}
/**
* @ingroup Config
* @brief Reset the configuration of TI Slaves on the TS.
* This routine removes all slaves and resets the fiber port busy's.
*
* @return OK if successful, ERROR otherwise
*
*/
int
tsResetSlaveConfig()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
tsSlaveMask = 0;
vmeWrite32(&TSp->busy, (vmeRead32(&TSp->busy) & ~TS_BUSY_HFBR_MASK));
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Add and configurate a TI Slave.
*
* This routine should be used by the TS to configure
* HFBR port and BUSY sources.
*
* @param fiber The fiber port of the TS that is connected to the slave
*
* @return OK if successful, otherwise ERROR
*/
int
tsAddSlave(unsigned int fiber)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((fiber<1) || (fiber>2) )
{
printf("%s: ERROR: Invalid value for fiber (%d)\n",
__FUNCTION__,fiber);
return ERROR;
}
/* Add this slave to the global slave mask */
tsSlaveMask |= (1<<(fiber-1));
/* Add this fiber as a busy source */
switch(fiber)
{
case 1:
if(tsSetBusySource(TS_BUSY_TI_A,0)!=OK)
return ERROR;
break;
case 2:
default:
if(tsSetBusySource(TS_BUSY_TI_B,0)!=OK)
return ERROR;
}
return OK;
}
/**
* @ingroup Config
* @brief Remove a TI Slave for the TS.
* @param fiber The fiber port of the TS to remove.
*
* @return OK if successful, otherwise ERROR
*/
int
tsRemoveSlave(unsigned int fiber)
{
unsigned int busybits;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((fiber<1) || (fiber>2) )
{
printf("%s: ERROR: Invalid value for fiber (%d)\n",
__FUNCTION__,fiber);
return ERROR;
}
/* Remove this slave to the global slave mask */
tsSlaveMask &= ~(1<<(fiber-1));
/* Remove this fiber as a busy source (use first fiber macro as the base) */
TSLOCK;
/* Read in previous values, keeping current busy's */
busybits = vmeRead32(&TSp->busy);
/* Turn off busy to the fiber in question */
busybits &= ~(1<<(TS_BUSY_TI_A-1+fiber));
/* Write the new mask */
vmeWrite32(&TSp->busy, busybits);
TSUNLOCK;
/* Keep the fiber enabled: No call to tdEnableFiber(..) */
return OK;
}
/**
* @ingroup Config
* @brief Set the value for a specified trigger rule.
*
* @param rule the number of triggers within some time period..
* e.g. rule=1: No more than ONE trigger within the
* specified time period
*
* @param value the specified time period (in steps of timestep)
* @param timestep
* - 0: 16ns
* - 1: 500ns
*
* @return OK if successful, otherwise ERROR.
*
*/
int
tsSetTriggerHoldoff(int rule, unsigned int value, int timestep)
{
unsigned int wval=0, rval=0;
unsigned int maxvalue=0x3f;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if( (rule<1) || (rule>5) )
{
printf("%s: ERROR: Invalid value for rule (%d). Must be 1-4\n",
__FUNCTION__,rule);
return ERROR;
}
if(value>maxvalue)
{
printf("%s: ERROR: Invalid value (%d). Must be less than %d.\n",
__FUNCTION__,value,maxvalue);
return ERROR;
}
if(timestep)
value |= (1<<7);
/* Read the previous values */
TSLOCK;
rval = vmeRead32(&TSp->triggerRule);
switch(rule)
{
case 1:
wval = value | (rval & ~TS_TRIGGERRULE_RULE1_MASK);
break;
case 2:
wval = (value<<8) | (rval & ~TS_TRIGGERRULE_RULE2_MASK);
break;
case 3:
wval = (value<<16) | (rval & ~TS_TRIGGERRULE_RULE3_MASK);
break;
case 4:
wval = (value<<24) | (rval & ~TS_TRIGGERRULE_RULE4_MASK);
break;
}
vmeWrite32(&TSp->triggerRule,wval);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the value for a specified trigger rule.
*
* @param rule the number of triggers within some time period..
* e.g. rule=1: No more than ONE trigger within the
* specified time period
*
* @return If successful, returns the value (in steps of 16ns)
* for the specified rule. ERROR, otherwise.
*
*/
int
tsGetTriggerHoldoff(int rule)
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(rule<1 || rule>5)
{
printf("%s: ERROR: Invalid value for rule (%d). Must be 1 or 2.\n",
__FUNCTION__,rule);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->triggerRule);
TSUNLOCK;
switch(rule)
{
case 1:
rval = (rval & TS_TRIGGERRULE_RULE1_MASK);
break;
case 2:
rval = (rval & TS_TRIGGERRULE_RULE2_MASK)>>8;
break;
case 3:
rval = (rval & TS_TRIGGERRULE_RULE3_MASK)>>16;
break;
case 4:
rval = (rval & TS_TRIGGERRULE_RULE4_MASK)>>24;
break;
}
return rval;
}
/**
* @ingroup Config
* @brief Set the value for the minimum time of specified trigger rule.
*
* @param rule the number of triggers within some time period..
* e.g. rule=1: No more than ONE trigger within the
* specified time period
*
* @param value the specified time period (in steps of timestep)
*
* rule
* 2 3 4
* ----- ------ ------
* 16ns 480ns 480ns
*
*
* @return OK if successful, otherwise ERROR.
*
*/
int
tsSetTriggerHoldoffMin(int rule, unsigned int value)
{
unsigned int mask=0, enable=0, shift=0;
if(TSp == NULL)
{
printf("%s: ERROR: TI not initialized\n",__FUNCTION__);
return ERROR;
}
if(rule<2 || rule>5)
{
printf("%s: ERROR: Invalid rule (%d). Must be 2-4.\n",
__FUNCTION__,rule);
return ERROR;
}
if(value > 0x7f)
{
printf("%s: ERROR: Invalid value (%d). Must be less than %d.\n",
__FUNCTION__,value,0x7f);
return ERROR;
}
switch(rule)
{
case 2:
mask = ~(TS_TRIGGERRULEMIN_MIN2_MASK | TS_TRIGGERRULEMIN_MIN2_EN);
enable = TS_TRIGGERRULEMIN_MIN2_EN;
shift = 8;
break;
case 3:
mask = ~(TS_TRIGGERRULEMIN_MIN3_MASK | TS_TRIGGERRULEMIN_MIN3_EN);
enable = TS_TRIGGERRULEMIN_MIN3_EN;
shift = 16;
break;
case 4:
mask = ~(TS_TRIGGERRULEMIN_MIN4_MASK | TS_TRIGGERRULEMIN_MIN4_EN);
enable = TS_TRIGGERRULEMIN_MIN4_EN;
shift = 24;
break;
}
TSLOCK;
vmeWrite32(&TSp->part1.triggerRuleMin,
(vmeRead32(&TSp->part1.triggerRuleMin) & mask) |
enable |
(value << shift) );
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the value for a specified trigger rule minimum busy.
*
* @param rule the number of triggers within some time period..
* e.g. rule=1: No more than ONE trigger within the
* specified time period
*
* @param pflag if not 0, print the setting to standard out.
*
* @return If successful, returns the value
* (in steps of 16ns for rule 2, 480ns otherwise)
* for the specified rule. ERROR, otherwise.
*
*/
int
tsGetTriggerHoldoffMin(int rule, int pflag)
{
int rval=0;
unsigned int mask=0, enable=0, shift=0;
if(TSp == NULL)
{
printf("%s: ERROR: TI not initialized\n",__FUNCTION__);
return ERROR;
}
if(rule<2 || rule>5)
{
printf("%s: ERROR: Invalid rule (%d). Must be 2-4.\n",
__FUNCTION__,rule);
return ERROR;
}
switch(rule)
{
case 2:
mask = TS_TRIGGERRULEMIN_MIN2_MASK;
enable = TS_TRIGGERRULEMIN_MIN2_EN;
shift = 8;
break;
case 3:
mask = TS_TRIGGERRULEMIN_MIN3_MASK;
enable = TS_TRIGGERRULEMIN_MIN3_EN;
shift = 16;
break;
case 4:
mask = TS_TRIGGERRULEMIN_MIN4_MASK;
enable = TS_TRIGGERRULEMIN_MIN4_EN;
shift = 24;
break;
}
TSLOCK;
rval = (vmeRead32(&TSp->part1.triggerRuleMin) & mask)>>shift;
TSUNLOCK;
if(pflag)
{
printf("%s: Trigger rule %d minimum busy = %d - %s\n",
__FUNCTION__,rule,
rval & 0x7f,
(rval & (1<<7))?"ENABLED":"DISABLED");
}
return rval & ~(1<<8);
}
/**
* @ingroup Config
* @brief Configure trigger table to be loaded with a user provided array.
*
* @param itable Input Table (8x256 Array of 4byte words)
*
* @return OK if successful, otherwise ERROR
*/
int
tsTriggerTableConfig(unsigned int **itable)
{
int imem=0, ielement=0;
if(itable==NULL)
{
printf("%s: ERROR: Invalid input table address\n",
__FUNCTION__);
return ERROR;
}
for(imem=0; imem<8; imem++)
for(ielement=0; ielement<256; ielement++)
tsTrigPatternData[imem][ielement] = itable[imem][ielement];
return OK;
}
/**
* @ingroup Config
* @brief Get the current trigger table stored in local memory (not necessarily on TS).
*
* @param otable Output Table (8x256 Array of 4byte words, user must allocate memory)
*
* @return OK if successful, otherwise ERROR
*/
int
tsGetTriggerTable(unsigned int **otable)
{
int imem=0, ielement=0;
if(otable==NULL)
{
printf("%s: ERROR: Invalid output table address\n",
__FUNCTION__);
return ERROR;
}
for(imem=0; imem<8; imem++)
for(ielement=0; ielement<16; ielement++)
otable[imem][ielement] = tsTrigPatternData[imem][ielement];
return OK;
}
/**
* @ingroup Config
* @brief Configure trigger table to be loaded with a predefined
* trigger table (mapping GTP and FP inputs to trigger types).
*
*/
void
tsTriggerTableDefault()
{
unsigned int imem=0, iword=0;
/* Fill in the single bit patterns with "single trigger" patterns */
for (imem=0; imem<8; imem++) /* 0-3: GTP tables, 4-7: FP Tables */
{
/* Start by initializing all bit patterns to their numerical event types,
and setting them all to be "multiple trigger" patterns */
for (iword=0; iword<256; iword++)
{
/* set bit(8) to 1 (hw trig1), and bit(11:10) to 3 for multi-bit trigger */
tsTrigPatternData[imem][iword] = 0xD00 + iword;
}
/* Zero inputs, No triggers */
tsTrigPatternData[imem][0] = 0;
for (iword=0; iword<8; iword++)
{
/* set bit(8) to 1 (hw trig1), and bit(10) to 1 for single-bit trigger */
tsTrigPatternData[imem][((1<2) || (inputType<0))
{
printf("%s: ERROR: Invalid inputType (%d)\n",
__FUNCTION__, inputType);
return ERROR;
}
if(hwTrig>3)
{
printf("%s: ERROR: Invalid hwTrig (%d)\n",
__FUNCTION__, hwTrig);
return ERROR;
}
if(evType>0xFF)
{
printf("%s: ERROR: Invalid evType (%d)\n",
__FUNCTION__, evType);
return ERROR;
}
/* Find the first non-zero pattern subgroup */
for(ibyte=0; ibyte<4; ibyte++)
{
pattern = (trigMask>>(ibyte*8)) & 0xFF;
if(pattern==0)
continue;
else if(foundPattern==1)
{
printf("%s: WARN: Pattern 0x%02x for %s subgroup %s ignored.\n",
__FUNCTION__,pattern, (inputType==0)?"GTP":"FP", subgroup[ibyte]);
printf(" Pattern was already found in provided trigMask (0x%08x).\n",
trigMask);
continue;
}
else
{
mem = ibyte + inputType*4;
/* Write this as a single trigger, so that the event Type is preserved */
tsTrigPatternData[mem][pattern] = (1<<10) | (hwTrig<<8) | evType;
foundPattern=1;
}
}
return OK;
}
/**
* @ingroup Config
* @brief Set the trigger type for the specified special trigger
*
* @param trigOpt Trigger Option
* 0: Software (default = 253)
* 1: Pulser (default = 254)
* 2: Multiple GTP or FP Hits (default = 250)
* 3: Combined GTP and FP Hits (default = 251)
*
* @param evType Event Type
* - Must be 1-255
*
* @return OK if successful, otherwise ERROR
*/
int
tsDefineSpecialEventType(int trigOpt, int evType)
{
unsigned int reg=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((trigOpt<0) || (trigOpt>3))
{
printf("%s: ERROR: Invalid trigOpt (%d)\n",
__FUNCTION__,trigOpt);
return ERROR;
}
if((evType<0) || (evType>0xFF))
{
printf("%s: ERROR: Invalid evType (%d)\n",
__FUNCTION__,evType);
return ERROR;
}
TSLOCK;
reg = vmeRead32(&TSp->specialEvTypes);
switch(trigOpt)
{
case 0: /* Software */
reg = (reg &~ TS_SPECIALEVTYPES_VME_MASK) | (evType<<16);
break;
case 1: /* Pulser */
reg = (reg &~ TS_SPECIALEVTYPES_PULSER_MASK) | (evType<<24);
break;
case 2: /* Multiple GTP or FP */
reg = (reg &~ TS_SPECIALEVTYPES_MULT_GTP_OR_FP_MASK) | (evType<<0);
break;
case 3: /* Combined GTP and FP */
reg = (reg &~ TS_SPECIALEVTYPES_GTP_AND_FP_MASK) | (evType<<8);
break;
}
vmeWrite32(&TSp->specialEvTypes, reg);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the trigger type for the specified special trigger
*
* @param trigOpt Trigger Option
* 0: Software (default = 253)
* 1: Pulser (default = 254)
* 2: Multiple GTP or FP Hits (default = 250)
* 3: Combined GTP and FP Hits (default = 251)
*
* @return Event Type if successful, otherwise ERROR
*/
int
tsGetSpecialEventType(int trigOpt)
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((trigOpt<0) || (trigOpt>3))
{
printf("%s: ERROR: Invalid trigOpt (%d)\n",
__FUNCTION__,trigOpt);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->specialEvTypes);
switch(trigOpt)
{
case 0: /* Software */
rval = (rval & TS_SPECIALEVTYPES_VME_MASK)>>16;
break;
case 1: /* Pulser */
rval = (rval & TS_SPECIALEVTYPES_PULSER_MASK)>>24;
break;
case 2: /* Multiple GTP or FP */
rval = (rval & TS_SPECIALEVTYPES_MULT_GTP_OR_FP_MASK);
break;
case 3: /* Combined GTP and FP */
rval = (rval & TS_SPECIALEVTYPES_GTP_AND_FP_MASK)>>8;
break;
}
TSUNLOCK;
return rval;
}
static void
SBRAMLoad(volatile unsigned int *reg, unsigned int *Wdata)
{
unsigned int i;
TSLOCK;
/* Reset the write address first */
vmeWrite32(&TSp->reset,TS_RESET_RAM_WRITE);
taskDelay(1);
for (i=0; i<256; i++)
{
vmeWrite32(reg, Wdata[i]);
}
TSUNLOCK;
}
static void
STRGTableLoad()
{
int imem=0;
for (imem=0; imem<8; imem++)
{
if(imem<4) /* GTP Table Load */
SBRAMLoad(&TSp->GTPTriggerTable[imem], (unsigned int*)&tsTrigPatternData[imem]);
else /* FP Table Load */
SBRAMLoad(&TSp->FPTriggerTable[imem-4], (unsigned int*)&tsTrigPatternData[imem]);
}
}
static void
STRGSubTableLoad()
{
unsigned int MemData[256];
unsigned int its, iword;
/* loop over the four TS partitions */
for (its=0; its<4; its++)
{
/* initialize the data buffer */
for (iword=0; iword<256; iword++)
{
/* set bit(8) to 1, and bit(9) to 1 for multi-bit trigger */
MemData[iword] = 0xF0a;
}
/* initialize the proper word */
MemData[0] = 0;
for (iword=0; iword<8; iword++)
{
/* set bit(8) to 1 */
MemData[((1<PartTrigTable[its].GTPTriggerTable, (unsigned int*)&MemData);
/* load the EXT TSpartition input table */
SBRAMLoad(&TSp->PartTrigTable[its].FPTriggerTable, (unsigned int*)&MemData);
}
}
/**
* @ingroup Config
* @brief Load up the default trigger lookup table for the TS
*
* @return OK if successful, otherwise ERROR
*/
int
tsLoadTriggerTable()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
STRGTableLoad();
printf("%s: Loaded.\n",__FUNCTION__);
return OK;
}
/**
* @ingroup Status
* @brief Print trigger table to standard out.
*
* @param inputType Input Type
* 0: GTP
* 1: FP
* @param subGroup Each input type is grouped into 8 channels.
* 0: 1-8
* 1: 9-16
* 2: 17-24
* 3: 25-32
* @param showbits Show trigger bit pattern, instead of hex
*
*/
void
tsPrintTriggerTable(int inputType, int subGroup, int showbits)
{
int ielement=0, ipattern=0, multi1=0, multi2=0;
int hwTrig1=0, evType1=0, hwTrig2=0, evType2=0;
const char* input[2] =
{
"GTP", " FP"
};
const char *subgroup[4] =
{
" 1- 8",
" 9-16",
"17-24",
"25-32"
};
if((inputType>2) || (inputType<0))
{
printf("%s: ERROR: Invalid inputType (%d)\n",
__FUNCTION__, inputType);
return;
}
if((subGroup>3) || (subGroup<0))
{
printf("%s: ERROR: Invalid subGroup (%d)\n",
__FUNCTION__, inputType);
return;
}
for(ielement = 0; ielement<256; ielement+=16)
{
if(showbits)
{
printf("--------%s INPUT------ --------%s INPUT------\n"
,input[inputType], input[inputType]);
printf("%2d %2d %2d %2d %2d %2d %2d %2d HW evType %2d %2d %2d %2d %2d %2d %2d %2d HW evType\n",
subGroup*8+1,
subGroup*8+2,
subGroup*8+3,
subGroup*8+4,
subGroup*8+5,
subGroup*8+6,
subGroup*8+7,
subGroup*8+8,
subGroup*8+1,
subGroup*8+2,
subGroup*8+3,
subGroup*8+4,
subGroup*8+5,
subGroup*8+6,
subGroup*8+7,
subGroup*8+8);
}
else
{
printf("%s Pattern %s Pattern\n"
,input[inputType],input[inputType]);
printf(" %s HW evType %s HW evType\n"
,subgroup[subGroup],subgroup[subGroup]);
}
for(ipattern=ielement; ipattern>8;
evType1 = (tsTrigPatternData[inputType*4+subGroup][ipattern]) & 0xFF;
multi1 = ((tsTrigPatternData[inputType*4+subGroup][ipattern]) & 0xC00)==0xC00;
if(multi1)
evType1 = 250;
hwTrig2 = ((tsTrigPatternData[inputType*4+subGroup][ipattern+8]) & 0x300)>>8;
evType2 = (tsTrigPatternData[inputType*4+subGroup][ipattern+8]) & 0xFF;
multi2 = ((tsTrigPatternData[inputType*4+subGroup][ipattern+8]) & 0xC00)==0xC00;
if(multi2)
evType2 = 250;
if(showbits)
{
printf(" %d %d %d %d %d %d %d %d %d %3d %d %d %d %d %d %d %d %d %d %3d\n",
((ipattern) & (1<<0))?1:0,
((ipattern) & (1<<1))?1:0,
((ipattern) & (1<<2))?1:0,
((ipattern) & (1<<3))?1:0,
((ipattern) & (1<<4))?1:0,
((ipattern) & (1<<5))?1:0,
((ipattern) & (1<<6))?1:0,
((ipattern) & (1<<7))?1:0,
hwTrig1, evType1,
((ipattern+8) & (1<<0))?1:0,
((ipattern+8) & (1<<1))?1:0,
((ipattern+8) & (1<<2))?1:0,
((ipattern+8) & (1<<3))?1:0,
((ipattern+8) & (1<<4))?1:0,
((ipattern+8) & (1<<5))?1:0,
((ipattern+8) & (1<<6))?1:0,
((ipattern) & (1<<7))?1:0,
hwTrig2, evType2);
}
else
{
printf(" 0x%02x %d %3d 0x%02x %d %3d\n",
ipattern,hwTrig1, evType1,
ipattern+8,hwTrig2, evType2);
}
}
printf("\n");
}
}
/**
* @ingroup Config
* @brief Latch the Busy and Live Timers.
*
* This routine should be called prior to a call to tsGetLiveTime and tsGetBusyTime
*
* @sa tsGetLiveTime
* @sa tsGetBusyTime
*
* @return OK if successful, otherwise ERROR
*/
int
tsLatchTimers()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset, TS_RESET_LATCH_TIMERS);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Return the current "live" time of the module
*
* @returns The current live time in units of 7.68 us
*
*/
unsigned int
tsGetLiveTime()
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->livetime);
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Return the current "busy" time of the module
*
* @returns The current live time in units of 7.68 us
*
*/
unsigned int
tsGetBusyTime()
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->busytime);
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Calculate the live time (percentage) from the live and busy time scalers
*
* @param sflag if > 0, then returns the integrated live time
*
* @return live time as a 3 digit integer % (e.g. 987 = 98.7%)
*
*/
int
tsLive(int sflag)
{
int rval=0;
float fval=0;
unsigned int newBusy=0, newLive=0, newTotal=0;
unsigned int live=0, total=0;
static unsigned int oldLive=0, oldTotal=0;
static unsigned int init_check = 0;
if(TSp == NULL)
{
if(init_check == 0){
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
init_check ++;
}
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset,TS_RESET_LATCH_TIMERS);
newLive = vmeRead32(&TSp->livetime);
newBusy = vmeRead32(&TSp->busytime);
newTotal = newLive+newBusy;
if((sflag==0) && (oldTotal0)
fval = 1000*(((float) live)/((float) total));
rval = (int) fval;
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Show block Status of specified fiber
* @param fiber Fiber port to show
* @param pflag Whether or not to print to standard out
* @return 0
*/
unsigned int
tsBlockStatus(int fiber, int pflag)
{
unsigned int rval=0;
char name[50];
unsigned int nblocksReady, nblocksNeedAck;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(fiber>2)
{
printf("%s: ERROR: Invalid value (%d) for fiber\n",__FUNCTION__,fiber);
return ERROR;
}
switch(fiber)
{
case 0:
rval = (vmeRead32(&TSp->adr24) & 0xFFFF0000)>>16;
break;
case 1:
rval = (vmeRead32(&TSp->blockStatus[(fiber-1)/2]) & 0xFFFF);
break;
case 2:
rval = ( vmeRead32(&TSp->blockStatus[(fiber/2)-1]) & 0xFFFF0000 )>>16;
break;
}
if(pflag)
{
nblocksReady = rval & TS_BLOCKSTATUS_NBLOCKS_READY0;
nblocksNeedAck = (rval & TS_BLOCKSTATUS_NBLOCKS_NEEDACK0)>>8;
if(fiber==0)
sprintf(name,"Loopback");
else
sprintf(name,"Fiber %d",fiber);
printf("%s: %s : Blocks ready / need acknowledge: %d / %d\n",
__FUNCTION__, name,
nblocksReady, nblocksNeedAck);
}
return rval;
}
/**
* @ingroup Status
* @brief Returns the bits that are contributing to the current busy state
*
*/
int
tsGetBusyStatus(int pflag)
{
unsigned int busy=0, setbusy=0, isbusy=0, easybusy=0;
int busyFound=0;
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
busy = vmeRead32(&TSp->busy);
TSUNLOCK;
isbusy = (busy&TS_BUSY_MONITOR_MASK)>>16;
setbusy = (busy&TS_BUSY_SOURCEMASK);
/* These are the "easy" bits... i.e. one to one */
easybusy = isbusy & setbusy;
if(easybusy) busyFound=1;
rval = easybusy;
if(pflag)
{
printf("%s: TS Busy from:\n",__FUNCTION__);
if(easybusy & TS_BUSY_SWA)
printf(" Switch Slot A\n");
if(easybusy & TS_BUSY_SWB)
printf(" Switch Slot A\n");
if(easybusy & TS_BUSY_P2)
printf(" P2 Input\n");
if(easybusy & TS_BUSY_FP_FTDC)
printf(" Front Panel TDC\n");
if(easybusy & TS_BUSY_FP_FADC)
printf(" Front Panel ADC\n");
if(easybusy & TS_BUSY_FP)
printf(" Front Panel\n");
if(easybusy & TS_BUSY_LOOPBACK)
printf(" Loopback (Block buffer level)\n");
if(easybusy & TS_BUSY_TI_A)
printf(" Fiber 1 (Block buffer level)\n");
if(easybusy & TS_BUSY_TI_B)
printf(" Fiber 2 (Block buffer level)\n");
if(easybusy & TS_BUSY_INT)
printf(" Too many available unread blocks\n");
}
/* These are the more detailed bits */
isbusy = isbusy<<16;
if((setbusy & TS_BUSY_LOOPBACK) && (isbusy & TS_BUSY_MONITOR_TS))
{
rval |= TS_BUSY_MONITOR_TS;
if(pflag)
printf(" TS (data buffer, etc)\n");
busyFound=1;
}
if((setbusy & TS_BUSY_TI_A) && (isbusy & TS_BUSY_MONITOR_TI_A))
{
rval |= TS_BUSY_MONITOR_TI_A;
if(pflag)
printf(" Fiber 1 (crate busy)\n");
busyFound=1;
}
if((setbusy & TS_BUSY_TI_B) && (isbusy & TS_BUSY_MONITOR_TI_B))
{
rval |= TS_BUSY_MONITOR_TI_B;
if(pflag)
printf(" Fiber 2 (crate busy)\n");
busyFound=1;
}
if(pflag)
if(!busyFound)
printf(" No Sources\n");
return rval;
}
/**
* @ingroup Config
* @brief Set the value of the syncronization event interval
*
*
* @param blk_interval
* Sync Event will occur in the last event of the set blk_interval (number of blocks)
*
* @return OK if successful, otherwise ERROR
*/
int
tsSetSyncEventInterval(int blk_interval)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(blk_interval>TS_SYNCEVENTCTRL_NBLOCKS_MASK)
{
printf("%s: WARN: Value for blk_interval (%d) too large. Setting to %d\n",
__FUNCTION__,blk_interval,TS_SYNCEVENTCTRL_NBLOCKS_MASK);
blk_interval = TS_SYNCEVENTCTRL_NBLOCKS_MASK;
}
TSLOCK;
vmeWrite32(&TSp->syncEventCtrl, blk_interval);
TSUNLOCK;
return OK;
}
/**
* @ingroup Readout
* @brief Force a sync event (type = 0).
* @return OK if successful, otherwise ERROR
*/
int
tsForceSyncEvent()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset, TS_RESET_FORCE_SYNCEVENT);
TSUNLOCK;
return OK;
}
/**
* @ingroup Readout
* @brief Sync Reset Request is sent to TI-Master or TS.
*
* This option is available for multicrate systems when the
* synchronization is suspect. It should be exercised only during
* "sync events" where the requested sync reset will immediately
* follow all ROCs concluding their readout.
*
* @return OK if successful, otherwise ERROR
*/
int
tsSyncResetRequest()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
tsDoSyncResetRequest=1;
TSUNLOCK;
return OK;
}
/**
* @ingroup Readout
* @brief Determine if a TI has requested a Sync Reset
*
* @return 1 if requested received, 0 if not, otherwise ERROR
*/
int
tsGetSyncResetRequest()
{
int request=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
request = (vmeRead32(&TSp->blockBuffer) & TS_BLOCKBUFFER_SYNCRESET_REQUESTED)>>30;
TSUNLOCK;
return request;
}
/**
* @ingroup Readout
* @brief Generate non-physics triggers until the current block is filled.
* This feature is useful for "end of run" situations.
*
* @return OK if successful, otherwise ERROR
*/
int
tsFillToEndBlock()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset, TS_RESET_FILL_TO_END_BLOCK);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Poll the TS to determine status of current block, for specified number of times.
* Return immediately when block has been filed, or when timeout has occurred.
*
* @param npoll Number of times to poll TS, before timeout declared
*
* @return OK if Block Is Filled, otherwise ERROR
*/
int
tsCurrentBlockFilled(unsigned short npoll)
{
int rval=OK, ipoll=0;
unsigned int bl, nevents;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
bl = tsGetCurrentBlockLevel();
TSLOCK;
for(ipoll=0; ipollnblocks) & TS_NBLOCKS_EVENTS_IN_BLOCK_MASK)>>24;
if(nevents==bl)
break;
}
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Reset the MGT
* @return OK if successful, otherwise ERROR
*/
int
tsResetMGT()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->reset, TS_RESET_MGT);
TSUNLOCK;
taskDelay(1);
return OK;
}
/**
* @ingroup Status
* @brief Get the input delay for teh specified front panel input (0-31)
* @param chan Front Panel Input Channel (0-31)
* @return Channel delay (units of 4ns) if successful, otherwise ERROR
*/
int
tsGetFPDelay(int chan)
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((chan<0) || (chan>31))
{
printf("%s: ERROR: Invalid chan (%d)\n",__FUNCTION__,
chan);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpDelay[chan/3]) & TS_FPDELAY_MASK(chan))>>(10*(chan%3));
TSUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Print Front Panel Channel Delays to Standard Out
* @return OK if successful, otherwise ERROR
*/
int
tsPrintFPDelay()
{
unsigned int reg[11];
int ireg=0, ichan=0, delay=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
for(ireg=0; ireg<11; ireg++)
reg[ireg] = vmeRead32(&TSp->fpDelay[ireg]);
TSUNLOCK;
printf("%s: Front panel delays:", __FUNCTION__);
for(ichan=0;ichan<31;ichan++)
{
delay = (reg[ichan / 3] & TS_FPDELAY_MASK(ichan))>>(10*(ichan%3));
if((ichan%4)==0)
{
printf("\n");
}
printf("Chan %2d: %5d ",ichan,delay);
}
printf("\n");
return OK;
}
/**
* @ingroup Config
* @brief Enable/Disable the FPGA drive to the TSIO.
* @param enable Enable/Disable
* 0: Disable
* >0: Enable
* @return OK if successful, otherwise ERROR
*/
int
tsSetTSIODrive(int enable)
{
unsigned int reg=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
reg = vmeRead32(&TSp->vmeControl);
if(enable)
{
vmeWrite32(&TSp->vmeControl, reg | TS_VMECONTROL_DRIVE_TSIO_EN);
}
else
{
vmeWrite32(&TSp->vmeControl, reg & ~TS_VMECONTROL_DRIVE_TSIO_EN);
}
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Return the Enable/Disable status the FPGA drive to the TSIO.
* @return 1 if enabled, 0 if disabled, otherwise ERROR
*/
int
tsGetTSIODrive()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->vmeControl) & TS_VMECONTROL_DRIVE_TSIO_EN)>>20;
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Return the Firmware Version that is Supported by the Library
* @return Firmware Version
*/
int
tsGetDriverSupportedVersion()
{
return TS_SUPPORTED_FIRMWARE;
}
/**
* @ingroup Readout
* @brief Readout input scalers
*
* @param data - local memory address to place scaler data
*
* @return Number of words transferred to data if successful, ERROR otherwise
*
*/
int
tsReadScalersMon(volatile unsigned int *data)
{
int iscal = 0, ichan = 0;
int banks = 0;
int nwrds = 0;
volatile struct ScalerStruct *scalers[4];
if(TSp==NULL)
{
logMsg("\ntsReadScalers: ERROR: TS not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if(data==NULL)
{
logMsg("\ntsReadScalers: ERROR: Invalid Destination address\n",0,0,0,0,0,0);
return(ERROR);
}
scalers[0] = (struct ScalerStruct *)(&TSp->Scalers1);
scalers[1] = (struct ScalerStruct *)(&TSp->Scalers2);
scalers[2] = (struct ScalerStruct *)(&TSp->Scalers3);
scalers[3] = (struct ScalerStruct *)(&TSp->Scalers4);
TSLOCK;
/* Latch Timers */
vmeWrite32(&TSp->reset, TS_RESET_LATCH_TIMERS);
/* GTP */
banks = 8;
for(iscal = 0; iscal < 4; iscal++){
for(ichan = 0; ichan < banks; ichan++){
data[nwrds] = vmeRead32(&scalers[iscal]->GTP[ichan]);
nwrds++;
}
}
/* Gen */
banks = 8;
for(iscal = 0; iscal < 4; iscal++){
for(ichan=0; ichangen[ichan]);
nwrds++;
}
}
/* LiveTime */
data[64] = vmeRead32(&TSp->livetime);
nwrds++;
/* BusyTime */
data[65] = vmeRead32(&TSp->busytime);
nwrds++;
TSUNLOCK;
return nwrds;
}
/**
* @ingroup Config
* @brief Set the trigger coincidence window
* @param size Size of the coincidence window in units of 4ns
* @return OK if successful, otherwise ERROR
*/
int
tsSetTrigCoinWindow(unsigned int size)
{
unsigned int maxvalue = 0xFF;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if( (size > maxvalue) || (size == 0) )
{
printf("%s: ERROR: Invalid window size (%d). Must be less than %d.\n",
__FUNCTION__,size,maxvalue);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->triggerWindow,
(vmeRead32(&TSp->triggerWindow) &~ TS_TRIGGERWINDOW_COINC_MASK)
| size);
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the trigger coincidence window
* @return Size of the coincidence window in units of 4ns if successful,
* otherwise ERROR
*/
int
tsGetTrigCoinWindow()
{
unsigned int rval = 0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->triggerWindow) & TS_TRIGGERWINDOW_COINC_MASK;
TSUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the trigger inhibit window
* @param size Size of the inhibit window in units of 4ns
* @return OK if successful, otherwise ERROR
*/
int
tsSetTrigInhibitWindow(unsigned int size)
{
unsigned int maxvalue = 0xFF;
if( (size > maxvalue) || (size == 0) )
{
printf("%s: ERROR: Invalid inhibit window size (%d). Must be less than %d.\n",
__FUNCTION__,size,maxvalue);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->triggerWindow,
(vmeRead32(&TSp->triggerWindow) &~ TS_TRIGGERWINDOW_INHIBIT_MASK)
| (size<<8));
TSUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the trigger inhibit window
* @return Size of the inhibit window in units of 4ns if successful,
* otherwise ERROR
*/
int
tsGetTrigInhibitWindow()
{
unsigned int rval = 0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->triggerWindow) & TS_TRIGGERWINDOW_INHIBIT_MASK)>>8;
TSUNLOCK;
return rval;
}
/*************************************************************
TS Partition routines
*************************************************************/
/**
* @ingroup Part
* @brief Initialize a TS partition
* @param pID The partition identification number (1-4)
* @param tAddr
* - A24 VME Address of the TS
* - Slot number of TS (1 - 21)
* @param mode What mode to signal data ready from the partition
* - 0: Interrupt
* - 2: Polling
* @param iFlag Initialization bit mask
* - 0: No TS Initialization (map pointer only)
* @return OK if successful, otherwise ERROR
*/
int
tsPartInit(int pID, unsigned int tAddr, unsigned int mode, int iFlag)
{
unsigned int laddr;
unsigned int rval, boardID;
unsigned int firmwareInfo;
int stat;
int noBoardInit=0;
int tsType=0;
/* Check VME address */
if(tAddr<0 || tAddr>0xffffff)
{
printf("%s: ERROR: Invalid VME Address (%d)\n",__FUNCTION__,
tAddr);
}
if(tAddr==0)
{
/* Assume 0 means to use default from GEO (slot 20 or 21, whichever = MAX_VME_SLOTS) */
tAddr=(MAX_VME_SLOTS)<<19;
}
/* Check pID */
if(pID<1 || pID>4)
{
printf("%s: Invalid Partition ID (%d). Must be 1-4.\n",
__FUNCTION__,pID);
return ERROR;
}
noBoardInit = iFlag&(0x1);
/* Form VME base address from slot number */
#ifdef VXWORKS
stat = sysBusToLocalAdrs(0x39,(char *)tAddr,(char **)&laddr);
if (stat != 0)
{
printf("%s: ERROR: Error in sysBusToLocalAdrs res=%d \n",__FUNCTION__,stat);
return ERROR;
}
else
{
printf("TS address = 0x%x\n",laddr);
}
#else
stat = vmeBusToLocalAdrs(0x39,(char *)tAddr,(char **)&laddr);
if (stat != 0)
{
printf("%s: ERROR: Error in vmeBusToLocalAdrs res=%d \n",__FUNCTION__,stat);
return ERROR;
}
else
{
if(!noBoardInit)
printf("TS VME (Local) address = 0x%.8x (0x%.8x)\n",tAddr,laddr);
}
#endif
tsA24Offset = laddr-tAddr;
/* Set Up pointer */
TSp = (struct TS_A24RegStruct *)laddr;
/* Check if TS board is readable */
#ifdef VXWORKS
stat = vxMemProbe((char *)(&TSp->boardID),0,4,(char *)&rval);
#else
stat = vmeMemProbe((char *)(&TSp->boardID),4,(char *)&rval);
#endif
if (stat != 0)
{
printf("%s: ERROR: TS card not addressable\n",__FUNCTION__);
TSp=NULL;
return(-1);
}
else
{
/* Check that it is a TS */
if(((rval&TS_BOARDID_TYPE_MASK)>>16) != TS_BOARDID_TYPE_TS)
{
printf("%s: ERROR: Invalid Board ID: 0x%x (rval = 0x%08x)\n",
__FUNCTION__,
(rval&TS_BOARDID_TYPE_MASK)>>16,rval);
TSp=NULL;
return(ERROR);
}
/* Check if this is board has a valid slot number */
boardID = (rval&TS_BOARDID_GEOADR_MASK)>>8;
if((boardID <= 0)||(boardID >21))
{
printf("%s: ERROR: Board Slot ID is not in range: %d\n",
__FUNCTION__,boardID);
TSp=NULL;
return(ERROR);
}
}
/* Check if we should exit here, or initialize some board defaults */
if(noBoardInit)
{
return OK;
}
/* Get the Firmware Information and print out some details */
firmwareInfo = tsGetFirmwareVersion();
if(firmwareInfo>0)
{
printf(" User ID: 0x%x \tFirmware (type - revision): 0x%X - 0x%x.0x%02x\n",
(firmwareInfo&TS_FIRMWARE_ID_MASK)>>16,
(firmwareInfo&TS_FIRMWARE_TYPE_MASK)>>12,
(firmwareInfo&TS_FIRMWARE_MAJOR_VERSION_MASK)>>4,
firmwareInfo&TS_FIRWMARE_MINOR_VERSION_MASK);
tsVersion = firmwareInfo&0xFFF;
tsType = (firmwareInfo&TS_FIRMWARE_TYPE_MASK)>>12;
if((tsVersion < TS_SUPPORTED_FIRMWARE) || (tsType!=TS_SUPPORTED_TYPE))
{
printf("%s: ERROR: Type %x Firmware version (0x%x) not supported by this driver.\n Supported Type %x version 0x%x\n",
__FUNCTION__,
tsType,tsVersion,TS_SUPPORTED_TYPE,TS_SUPPORTED_FIRMWARE);
TSp=NULL;
return ERROR;
}
}
else
{
printf("%s: ERROR: Invalid firmware 0x%08x\n",
__FUNCTION__,firmwareInfo);
return ERROR;
}
/* Set some defaults, dependent on Master/Slave status */
tsReadoutMode = mode;
switch(mode)
{
case TS_READOUT_EXT_INT:
case TS_READOUT_EXT_POLL:
/* BUSY from Loopback and Switch Slot B */
tsSetBusySource(TS_BUSY_LOOPBACK | TS_BUSY_SWB,1);
/* Onboard Clock Source */
tsSetClockSource(TS_CLOCK_INTERNAL);
/* Loopback Sync Source */
tsSetSyncSource(TS_SYNC_LOOPBACK);
break;
default:
printf("%s: ERROR: Invalid TS Mode %d\n",
__FUNCTION__,mode);
return ERROR;
}
tsReadoutMode = mode;
tsPartitionID = pID;
switch(tsPartitionID)
{
case 2:
TSpart = (struct PartitionStruct *)(&TSp->part2);
break;
case 3:
TSpart = (struct PartitionStruct *)(&TSp->part3);
break;
case 4:
TSpart = (struct PartitionStruct *)(&TSp->part4);
break;
case 1:
default:
TSpart = (struct PartitionStruct *)(&TSp->part1);
break;
}
return OK;
}
/**
* @ingroup Part
* @brief Set the busy source for this partition
*
* @param busysrc
* - 1: Switch slot B
* - 2: Front Panel
* - 3: Fiber TI-A
* - 4: Fiber TI-B
*
* @return OK if successful, otherwise ERROR.
*/
int
tsPartSetBusySource(int busysrc)
{
unsigned int busybits=0;
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
if(busysrc > 4)
{
printf("%s: ERROR: Invalid busysrc (%d)\n",__FUNCTION__,busysrc);
return ERROR;
}
switch(busysrc)
{
case 0: /* Switch Slot B */
busybits = TS_PART_BUSYCONFIG_SWB;
break;
case 1: /* Front Panel */
busybits = TS_PART_BUSYCONFIG_FP;
break;
case 2: /* Fiber TI-A */
busybits = TS_PART_BUSYCONFIG_TI_A;
break;
case 3: /* Fiber TI-B */
default:
busybits = TS_PART_BUSYCONFIG_TI_B;
}
TSLOCK;
vmeWrite32(&TSpart->busyConfig,
(vmeRead32(&TSpart->busyConfig) & ~TS_PART_BUSYCONFIG_BUSYSRC_MASK) |
busybits);
TSUNLOCK;
return OK;
}
/**
* @ingroup Part
* @brief Set up the Block Buffer Level
* @param bufferlevel How many unacknowledged blocks in the system before busy
* @return OK if successful, otherwise ERROR
*/
int
tsPartSetBlockBufferLevel(unsigned int bufferlevel)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
if(bufferlevel>0xff)
{
printf("%s: ERROR: Invalid bufferlevel (%d).\n"
,__FUNCTION__,bufferlevel);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSpart->busyConfig,
((vmeRead32(&TSpart->busyConfig) & ~(TS_PART_BUSYCONFIG_BUFFERLEVEL_MASK))) |
(bufferlevel<<24) |
TS_PART_BUSYCONFIG_BUFFERLEVEL_ENABLE | TS_PART_BUSYCONFIG_ALMOSTFULL_ENABLE);
printf("%s: 0x%08x\n",
__FUNCTION__,vmeRead32(&TSpart->busyConfig));
TSUNLOCK;
return OK;
}
/**
* @ingroup Part
* @brief Select the input that has the TD Busy
* @param tdinput Input selection
* @return OK if successful, otherwise ERROR
*/
int
tsPartSetTDInput(unsigned int tdinput)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
if(tdinput>0xff)
{
printf("%s: ERROR: Invalid tdinput (%d).\n"
,__FUNCTION__,tdinput);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSpart->blockBuffer,
(vmeRead32(&TSpart->blockBuffer) & ~(TS_PART_BUSYCONFIG_TD_INPUT_MASK)) |
(tdinput));
TSUNLOCK;
return OK;
}
/**
* @ingroup Part
* @brief Set the FP Inputs for this partition
* @param input1
* @param input2
* @param input3
* @return OK if successful, otherwise ERROR
*/
int
tsPartSetFPInput(unsigned short input1,
unsigned short input2,
unsigned short input3)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
if((input1>0x3F) || (input2>0x3F) || (input3>0x3F))
{
printf("%s: ERROR: Input out of range. Must be 0-63.\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSpart->fpConfig,
input1 |
(input2<<6) |
(input3<<12));
TSUNLOCK;
return OK;
}
/**
* @ingroup Part
* @brief Set the GTP Inputs for this partition
* @param input1
* @param input2
* @param input3
* @param input4
* @param input5
* @return OK if successful, otherwise ERROR
*/
int
tsPartSetGTPInput(unsigned short input1,
unsigned short input2,
unsigned short input3,
unsigned short input4,
unsigned short input5)
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
if((input1>0x3F) || (input2>0x3F) || (input3>0x3F) || (input4>0x3F) || (input5>0x3F))
{
printf("%s: ERROR: Input out of range. Must be 0-63.\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSpart->gtpConfig,
input1 |
(input2<<6) |
(input3<<12) |
(input4<<18) |
(input5<<24) );
TSUNLOCK;
return OK;
}
/**
* @ingroup Part
* @brief Load the trigger table for current partition
* @return OK if successful, otherwise ERROR
*/
int
tsPartLoadTriggerTable()
{
if(TSp==NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
STRGSubTableLoad();
return OK;
}
/**
* @ingroup Part
* @brief Read a block of events from the current TS partition
*
* @param data - local memory address to place data
* @param nwrds - Max number of words to transfer
*
* @return Number of words transferred to data if successful, ERROR otherwise
*
*/
int
tsPartReadBlock(volatile unsigned int *data, int nwrds)
{
int ii=0, dCnt=0;
unsigned int val;
if(TSp==NULL)
{
logMsg("\ntsPartReadBlock: ERROR: TS not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
logMsg("\ntsPartReadBlock: ERROR: TS Partition not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if(data==NULL)
{
logMsg("\ntsPartReadBlock: ERROR: Invalid Destination address\n",0,0,0,0,0,0);
return(ERROR);
}
while(iidata;
#ifndef VXWORKS
val = LSWAP(val);
#endif
if((val==TS_EMPTY_FIFO) || (val==-1))
break;
#ifndef VXWORKS
val = LSWAP(val);
#endif
data[ii] = val;
ii++;
/* Check if this is the block trailer */
#ifndef VXWORKS
val = LSWAP(val);
#endif
if(val & TS_DATAFORMAT_DATA_TYPE_WORD)
{
if(((val & TS_DATAFORMAT_TYPE_MASK)>>27)==TS_DATAFORMAT_TYPE_BLOCK_TRAILER)
{
break;
}
}}
dCnt += ii;
TSUNLOCK;
return(dCnt);
}
/**
* @ingroup Part
* @brief Returns the number of Blocks available for readout for this partition
*
* @return Number of blocks available for readout if successful, otherwise ERROR
*
*/
unsigned int
tsPartBReady()
{
unsigned int rval=0;
if(TSp==NULL)
{
logMsg("\ntsPartBReady(): ERROR: TS not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
logMsg("\ntsPartBReady(): ERROR: TS Partition not initialized\n",1,2,3,4,5,6);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSpart->blockBuffer) & TS_PART_BLOCKBUFFER_BLOCKS_READY_MASK;
TSUNLOCK;
return rval;
}
/**
* @ingroup Part
* @brief Acknowledge an interrupt or latched trigger for this partition
*/
void
tsPartIntAck()
{
if(TSp == NULL)
{
logMsg("tsPartIntAck: ERROR: TS not initialized\n",0,0,0,0,0,0);
return;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
logMsg("\ntsPartReadBlock: ERROR: TS Partition not initialized\n",1,2,3,4,5,6);
return;
}
TSLOCK;
tsDoAck = 1;
tsAckCount++;
vmeWrite32(&TSp->reset,TS_RESET_PART_ACK(tsPartitionID));
TSUNLOCK;
}
#ifndef VXWORKS
static void
tsPartPoll(void)
{
int tsdata;
prctl(PR_SET_NAME,__FUNCTION__);
while(1)
{
pthread_testcancel();
/* If still need Ack, don't test the Trigger Status */
if(tsNeedAck>0)
{
continue;
}
tsdata = tsPartBReady();
if(tsdata && tsIntRunning)
{
INTLOCK;
tsDaqCount = tsdata;
tsIntCount++;
if (tsIntRoutine != NULL) /* call user routine */
(*tsIntRoutine) (tsIntArg);
/* Write to TS to Acknowledge Interrupt */
if(tsDoAck==1)
{
tsPartIntAck();
}
INTUNLOCK;
}
}
printf("%s: Read ERROR: Exiting Thread\n",__FUNCTION__);
pthread_exit(0);
}
#endif
#ifndef VXWORKS
static void
tsPartStartPollingThread(void)
{
int pts_status;
pts_status =
pthread_create(&tspollthread,
NULL,
(void*(*)(void *)) tsPartPoll,
(void *)NULL);
if(pts_status!=0)
{
printf("%s: ERROR: TS Partition Polling Thread could not be started.\n",
__FUNCTION__);
printf("\t pthread_create returned: %d\n",pts_status);
}
}
/**
* @ingroup Part
* @brief Enable interrupts or latching triggers for this partition
* @param iflag if = 1, trigger counter will be reset
*
* @return OK if successful, otherwise ERROR
*/
int
tsPartIntEnable(int iflag)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
if(iflag == 1)
{
tsIntCount = 0;
tsAckCount = 0;
}
tsIntRunning = 1;
tsDoAck = 1;
tsNeedAck = 0;
switch (tsReadoutMode)
{
case TS_READOUT_EXT_POLL:
tsPartStartPollingThread();
break;
default:
tsIntRunning = 0;
printf("%s: ERROR: TS Readout Mode not defined %d\n",
__FUNCTION__,tsReadoutMode);
TSUNLOCK;
return ERROR;
}
taskDelay(30); /* maybe replace with a condition variable? */
vmeBusLock(); /* Make sure things don't change while we're doing this */
/* Enable the bits we need */
vmeWrite32(&TSp->trigger,
vmeRead32(&TSp->trigger) |
TS_TRIGGER_ENABLE |
TS_TRIGGER_PART(tsPartitionID));
vmeBusUnlock();
TSUNLOCK;
return(OK);
}
/**
* @ingroup Part
* @brief Disable interrupts or latching triggers for this partition
*/
void
tsPartIntDisable()
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return;
}
TSLOCK;
vmeBusLock();
vmeWrite32(&TSp->trigger,
vmeRead32(&TSp->trigger) & ~(TS_TRIGGER_PART(tsPartitionID)));
vmeBusUnlock();
tsIntRunning = 0;
TSUNLOCK;
}
/**
* @ingroup Part
* @brief Connect a user routine to the TS Interrupt or
* latched trigger, if polling.
*
* @param routine Routine to call if block is available
* @param arg argument to pass to routine
*
* @return OK if successful, otherwise ERROR
*/
int
tsPartIntConnect(VOIDFUNCPTR routine, unsigned int arg)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
printf("%s: ERROR: TS Partition not initialized\n",__FUNCTION__);
return ERROR;
}
tsIntCount = 0;
tsAckCount = 0;
tsDoAck = 1;
if(routine)
{
tsIntRoutine = routine;
tsIntArg = arg;
}
else
{
tsIntRoutine = NULL;
tsIntArg = 0;
}
return OK;
}
/**
* @ingroup Part
* @brief Disable interrupts or kill the polling service thread
*
* @return OK if successful, otherwise ERROR
*/
int
tsPartIntDisconnect()
{
void *res;
if(TSp == NULL)
{
logMsg("tsPartIntDisconnect: ERROR: TS not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if((tsPartitionID==0) || (TSpart==NULL))
{
logMsg("tsPartIntDisconnect: ERROR: TS Partition not initialized\n",1,2,3,4,5,6);
return ERROR;
}
if(tsIntRunning)
{
logMsg("tsPartIntDisconnect: ERROR: TS is Enabled - Call tsPartIntDisable() first\n",
1,2,3,4,5,6);
return ERROR;
}
INTLOCK;
if(tspollthread)
{
if(pthread_cancel(tspollthread)<0)
perror("pthread_cancel");
if(pthread_join(tspollthread,&res)<0)
perror("pthread_join");
if (res == PTHREAD_CANCELED)
printf("%s: Polling thread canceled\n",__FUNCTION__);
else
printf("%s: ERROR: Polling thread NOT canceled\n",__FUNCTION__);
}
INTUNLOCK;
printf("%s: Disconnected\n",__FUNCTION__);
return OK;
}
#endif
/**
* @ingroup Dupl
* @brief Enable/Disable Duplication Mode
*
* @param set Enable/Disable setting
* - 0 - Disable
* - !0 - Enable
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplMode(int set)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
tsDuplicationMode = (set)?1:0;
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetBranchEnable(int b1, int b2, int b3, int b4)
{
unsigned int bmask=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(b1)
bmask |= TS_BUSY_BRANCH1;
if(b2)
bmask |= TS_BUSY_BRANCH2;
if(b3)
bmask |= TS_BUSY_BRANCH3;
if(b4)
bmask |= TS_BUSY_BRANCH4;
bmask |= TS_BUSY_ALL_BRANCHES;
return tsSetBusySource(bmask, 0);
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetLocalTrigComboMask(unsigned int mask)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(mask&0x1)
{
printf("%s: WARN: Invalid trigger combination mask (0x%08x). Masking off 0x1\n",
__FUNCTION__,mask);
mask = mask &~ 0x1;
}
TSLOCK;
vmeWrite32(&TSp->fpInputPrescale[2], mask);
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
unsigned int
tsDuplGetLocalTrigComboMask()
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->fpInputPrescale[2]);
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetLocalTrigCombo(unsigned int mask, int set)
{
int ibit=0, trigbit=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if((mask>0x3E) || (mask&0x1))
{
printf("%s: ERROR: Invalid trigger combination mask (0x%02x)\n",
__FUNCTION__,mask);
return ERROR;
}
/* Determine the bit in enable/disable */
for(ibit=1; ibit<6; ibit++)
{
if(mask&(1<fpInputPrescale[2],
vmeRead32(&TSp->fpInputPrescale[2]) | (1<fpInputPrescale[2],
vmeRead32(&TSp->fpInputPrescale[2]) & ~(1<0x7F)
{
printf("%s: ERROR: Invalid value (%d)\n",
__FUNCTION__, value);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpInputPrescale[3],
(vmeRead32(&TSp->fpInputPrescale[3]) &~ TS_DUPL_LOCAL_TRIG_RULE_MASK) |
value);
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetTriggerHoldoff()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->fpInputPrescale[3]) & TS_DUPL_LOCAL_TRIG_RULE_MASK;
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetLocalTriggerWidth(int width)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(width>0xFF)
{
printf("%s: ERROR: Invalid width (%d)\n",
__FUNCTION__, width);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpInputPrescale[3],
(vmeRead32(&TSp->fpInputPrescale[3]) &~ TS_DUPL_LOCAL_TRIG_WIDTH_MASK) |
(width)<<8 );
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetLocalTriggerWidth()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpInputPrescale[3]) & TS_DUPL_LOCAL_TRIG_WIDTH_MASK)>>8;
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetFastClearWidth(int width)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(width>0xFF)
{
printf("%s: ERROR: Invalid width (%d)\n",
__FUNCTION__, width);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpInputPrescale[3],
(vmeRead32(&TSp->fpInputPrescale[3]) &~ TS_DUPL_FAST_CLEAR_WIDTH_MASK) |
(width)<<16 );
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetFastClearWidth()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpInputPrescale[3]) & TS_DUPL_FAST_CLEAR_WIDTH_MASK)>>16;
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetFastClearDelay(int delay)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(delay>0x1FF)
{
printf("%s: ERROR: Invalid delay (%d)\n",
__FUNCTION__, delay);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpDelay[5],
(vmeRead32(&TSp->fpDelay[5]) &~ TS_DUPL_FAST_CLEAR_DELAY_MASK) |
(delay)<<10 );
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetFastClearDelay()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpDelay[5]) & TS_DUPL_FAST_CLEAR_DELAY_MASK)>>10;
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetFastClearVetoWidth(int width)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(width>0xFF)
{
printf("%s: ERROR: Invalid width (%d)\n",
__FUNCTION__, width);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpInputPrescale[3],
(vmeRead32(&TSp->fpInputPrescale[3]) &~ TS_DUPL_FAST_CLEAR_VETO_WIDTH_MASK) |
(width)<<24 );
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetFastClearVetoWidth()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpInputPrescale[3]) & TS_DUPL_FAST_CLEAR_VETO_WIDTH_MASK)>>24;
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetLocalTrigBusy(int value)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(value>0x3FF)
{
printf("%s: ERROR: Invalid value (%d)\n",
__FUNCTION__, value);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpDelay[6],
(vmeRead32(&TSp->fpDelay[6]) &~ TS_DUPL_LOCAL_TRIG_BUSY_MASK) |
(value) );
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetLocalTrigBusy()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpDelay[6]) & TS_DUPL_LOCAL_TRIG_BUSY_MASK);
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplSetFastClearBusy(int value)
{
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
if(value>0x3FF)
{
printf("%s: ERROR: Invalid value (%d)\n",
__FUNCTION__, value);
return ERROR;
}
TSLOCK;
vmeWrite32(&TSp->fpDelay[6],
(vmeRead32(&TSp->fpDelay[6]) &~ TS_DUPL_FAST_CLEAR_BUSY_MASK) |
(value)<<20 );
TSUNLOCK;
return OK;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetFastClearBusy()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = (vmeRead32(&TSp->fpDelay[6]) & TS_DUPL_FAST_CLEAR_BUSY_MASK)>>20;
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplGetBusyTime()
{
int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->duplBusyTime);
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
unsigned int
tsDuplGetBusyStatus()
{
unsigned int rval=0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
TSLOCK;
rval = vmeRead32(&TSp->duplBusyStatus);
TSUNLOCK;
return rval;
}
/**
* @ingroup Dupl
* @brief
*
* @param
*
* @return OK if successful, otherwise ERROR;
*/
int
tsDuplPrintBusyStatus()
{
unsigned int status=0;
int ibranch;
int en[4], alt[4], afc[4], fe[4], oa[4];
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if(tsDuplicationMode!=1)
{
printf("%s: ERROR: TS Library not configured for Duplication Mode\n",
__FUNCTION__);
return ERROR;
}
status = tsDuplGetBusyStatus();
for(ibranch=0; ibranch<4; ibranch++)
{
en[ibranch] = (status & (1<<(ibranch)))?1:0;
alt[ibranch] = (status & (1<<(4+ibranch)))?1:0;
afc[ibranch] = (status & (1<<(8+ibranch)))?1:0;
fe[ibranch] = (status & (1<<(12+ibranch)))?1:0;
oa[ibranch] = (status & (1<<(20+ibranch)))?1:0;
}
printf(" TS Duplication Mode Busy Status\n\n");
printf(" All Branches : %s\n\n", (status & (1<<17))?"BUSY":"Not Busy");
printf(" Local Trigger Rule: %s\n\n", (status & (1<<16))?"BUSY":"Not Busy");
printf(" After Local After Fast \n");
printf("Branch Enabled Trigger Clear FrontEnd Overall \n");
printf("--------------------------------------------------------------------------------\n");
for(ibranch=0; ibranch<4; ibranch++)
{
printf(" %d ",ibranch);
printf("%s ",en[ibranch]?"YES":"NO ");
if(en[ibranch])
{
printf("%s ",alt[ibranch]?"BUSY":"----");
printf("%s ",afc[ibranch]?"BUSY":"----");
printf("%s ",fe[ibranch]?"BUSY":"----");
printf("%s ",oa[ibranch]?"BUSY":"----");
}
printf("\n");
}
return OK;
}
/* MODIFIED FUNCTIONS */
/**
* @ingroup Config
* @brief Set the input delay for teh specified front panel input (0-31)
* @param chan Front Panel Input Channel (0-31)
* @param delay Delay in units of 4ns (0=8ns)
* @return OK if successful, otherwise ERROR
*/
int
tsSetFPDelay(int chan, int delay)
{
unsigned int addr_offset = 0;
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
if((chan<0) || (chan>31))
{
printf("%s: ERROR: Invalid chan (%d)\n",__FUNCTION__,
chan);
return ERROR;
}
if((delay<0) || (delay>0x1ff))
{
printf("%s: ERROR: Invalid delay (%d)\n",__FUNCTION__,
delay);
return ERROR;
}
addr_offset = chan/3;
TSLOCK;
// printf("URODY %d %d 0x%x 0x%x\n",chan, delay, ~TS_FPDELAY_MASK(chan),
// (vmeRead32(&TSp->fpDelay[addr_offset]) & ~TS_FPDELAY_MASK(chan))
// | delay<<(10*(chan%3)));
vmeWrite32(&TSp->fpDelay[addr_offset],
(vmeRead32(&TSp->fpDelay[addr_offset]) & ~TS_FPDELAY_MASK(chan))
| delay<<(10*(chan%3)));
TSUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief
*
* @param enable
* - 0: Disable
* - >0: Enable
*
* @return OK if successful, otherwise ERROR
*
*/
int tsSetDataReadout(int enable) {
if(TSp == NULL)
{
printf("%s: ERROR: TS not initialized\n",__FUNCTION__);
return ERROR;
}
TSLOCK;
if(enable)
vmeWrite32(&TSp->dataFormat,
vmeRead32(&TSp->dataFormat) | TS_DATAFORMAT_DATA_READOUT);
else
vmeWrite32(&TSp->dataFormat,
vmeRead32(&TSp->dataFormat) & ~TS_DATAFORMAT_DATA_READOUT);
TSUNLOCK;
return OK;
}