/*----------------------------------------------------------------------------*/
/**
* @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:
* Software driver for the JLab Trigger Distribution Module
*
*
*----------------------------------------------------------------------------*/
#define _GNU_SOURCE
#ifdef VXWORKS
#include
#include
#include
#include
#include
#include
#include
#include
#include "vxCompat.h"
#else
#include
#include
#include "jvme.h"
#endif
#include
#include
#include
#include "tdLib.h"
/** Mutex to guard TD read/writes */
pthread_mutex_t tdMutex = PTHREAD_MUTEX_INITIALIZER;
/** Mutex Lock */
#define TDLOCK if(pthread_mutex_lock(&tdMutex)<0) perror("pthread_mutex_lock");
/** Mutex Unlock */
#define TDUNLOCK if(pthread_mutex_unlock(&tdMutex)<0) perror("pthread_mutex_unlock");
/* Global Variables */
int nTD = 0; /**< Number of TDs found with tdInit() */
volatile struct TD_A24RegStruct *TDp[MAX_VME_SLOTS+1]; /**< pointer to TD memory map */
int tdID[MAX_VME_SLOTS+1]; /**< array of slot numbers for TDs */
unsigned int tdAddrList[MAX_VME_SLOTS+1]; /**< array of a24 addresses for TDs */
unsigned long tdA24Offset=0; /**< Difference in CPU A24 Base and VME A24 Base */
int tdCrateID=0x59; /**< Crate ID */
int tdBlockLevel=0; /**< Block level for TD */
int tdFiberLatencyOffset = 0xbf; /**< Default offset for fiber latency */
unsigned int tdSlaveMask[MAX_VME_SLOTS+1]; /**< TI Slaves (mask) to be used */
#ifdef VXWORKS
extern int sysBusToLocalAdrs(int, char *, char **);
extern int intDisconnect(int);
extern int sysIntEnable(int);
IMPORT STATUS sysIntDisable(int);
#endif
/**
* @defgroup Config Initialization/Configuration
* @defgroup Status Status
* @defgroup Deprec Deprecated - To be removed
*/
/**
* @ingroup Config
* @brief Initialize JLAB TD Library
*
* @param addr
* - A24 VME Address of the TD
* @param addr_inc
* - Amount to increment addr to find the next TD
* @param nfind
* - Number of times to increment
* @param iFlag - Initialization mask
* - 0: Exit before board initialization (just map structure pointer)
* - 1: RFU
* - 2: Ignore firmware check
* - 3: Use tdAddrList instead of addr and addr_inc for VME addresses
*
* @return OK if successful, otherwise ERROR.
*/
STATUS
tdInit(UINT32 addr, UINT32 addr_inc, int nfind, int iFlag)
{
int useList=0, noBoardInit=0, noFirmwareCheck=0;
int islot, itd, TD_SLOT;
int res;
unsigned int rdata, boardID;
unsigned long laddr, laddr_inc;
unsigned int firmwareInfo=0, tdVersion=0, tdType=0;
volatile struct TD_A24RegStruct *td;
/* Check if we're skipping initialization, and just mapping the structure pointer */
if(iFlag&TD_INIT_NO_INIT)
{
noBoardInit = 1;
}
/* Check if we're skipping the firmware check */
if(iFlag&TD_INIT_SKIP_FIRMWARE_CHECK)
{
noFirmwareCheck=1;
}
/* Check if we're initializing using a list */
if(iFlag&TD_INIT_USE_ADDR_LIST)
{
useList=1;
}
/* Check for valid address */
if( (addr==0) && (useList==0) )
{ /* Scan through valid slot -> A24 address */
useList=1;
nfind=16;
/* Loop through JLab Standard GEOADDR to VME addresses to make a list */
for(islot=3; islot<11; islot++) /* First 8 */
tdAddrList[islot-3] = (islot<<19);
/* Skip Switch Slots */
for(islot=13; islot<21; islot++) /* Last 8 */
tdAddrList[islot-5] = (islot<<19);
}
else if(addr > 0x00ffffff)
{ /* A32 Addressing */
printf("%s: ERROR: A32 Addressing not allowed for TD configuration space\n",
__FUNCTION__);
return(ERROR);
}
else
{ /* A24 Addressing */
if(addr < 22)
{ /* First argument is a slot number, instead of VME address */
printf("%s: Initializing using slot number %d (VME address 0x%x)\n",
__FUNCTION__,addr,addr<<19);
addr = addr<<19; // Shift to VME A24 address;
/* If addr_inc is also in slot number form, shift it */
if((addr_inc<22) && (addr_inc>0))
addr_inc = addr_inc<<19;
/* Check and shift the address list, if it's used */
if(useList==1)
{
for(itd=0; itdboardID),VX_READ,4,(char *)&rdata);
#else
res = vmeMemProbe((char *) &(td->boardID),4,(char *)&rdata);
#endif
if(res < 0)
{
#ifdef SHOWERRORS
#ifdef VXWORKS
printf("%s: ERROR: No addressable board at addr=0x%x\n",
__FUNCTION__,(UINT32) td);
#else
printf("%s: ERROR: No addressable board at VME (Local) addr=0x%x (0x%x)\n",
__FUNCTION__,
(UINT32) laddr_inc-tdA24Offset, (UINT32) td);
#endif
#endif /* SUPPRESSERRORS */
}
else
{
/* Check that it is a TD */
if(((rdata&TD_BOARDID_TYPE_MASK)>>16) != TD_BOARDID_TYPE_TD)
{
printf(" WARN: For board at 0x%x, Invalid Board ID: 0x%x\n",
(UINT32) td, rdata);
continue;
}
else
{
/* Check if this is board has a valid slot number */
boardID = (rdata&TD_BOARDID_GEOADR_MASK)>>8;
if((boardID <= 0)||(boardID >21))
{
printf(" WARN: Board Slot ID is not in range: %d (this module ignored)\n"
,boardID);
continue;
}
else
{
TDp[boardID] = (struct TD_A24RegStruct *)(laddr_inc);
tdID[nTD] = boardID;
/* Get the Firmware Information and print out some details */
firmwareInfo = tdGetFirmwareVersion(tdID[nTD]);
if(firmwareInfo>0)
{
printf(" User ID: 0x%x \tFirmware (type - revision): %X - %x.%x\n",
(firmwareInfo&TD_FIRMWARE_ID_MASK)>>16,
(firmwareInfo&TD_FIRMWARE_TYPE_MASK)>>12,
(firmwareInfo&TD_FIRMWARE_MAJOR_VERSION_MASK)>>4,
firmwareInfo&TD_FIRWMARE_MINOR_VERSION_MASK);
tdVersion = firmwareInfo&0xFFF;
tdType = (firmwareInfo&TD_FIRMWARE_TYPE_MASK)>>12;
if((tdVersion < TD_SUPPORTED_FIRMWARE) || (tdType!=TD_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__,
tdType,tdVersion,TD_SUPPORTED_TYPE,TD_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__,
tdType,tdVersion,TD_SUPPORTED_TYPE,TD_SUPPORTED_FIRMWARE);
TDp[boardID]=NULL;
continue;
}
}
}
else
{
printf("%s: ERROR: Invalid firmware 0x%08x\n",
__FUNCTION__,firmwareInfo);
return ERROR;
}
printf("Initialized TD %2d Slot # %2d at address 0x%08lx (0x%08x) \n",
nTD, tdID[nTD],(unsigned long) TDp[(tdID[nTD])],
(UINT32)((unsigned long)TDp[(tdID[nTD])]-tdA24Offset));
}
}
nTD++;
}
}
#ifndef SHOWERROR
#ifndef VXWORKS
vmeSetQuietFlag(0);
#endif
#endif
tdInitPortNames();
if(noBoardInit)
{
if(nTD>0)
{
printf("%s: %d TD(s) successfully mapped (not initialized)\n",
__FUNCTION__,nTD);
return OK;
}
}
if(nTD==0)
{
printf("%s: ERROR: Unable to initialize any TD modules\n",
__FUNCTION__);
return ERROR;
}
/* Do some module initialization here */
for(itd=0; itd=nTD)
{
printf("%s: ERROR: Index (%d) >= TDs initialized (%d).\n",
__FUNCTION__,i,nTD);
return ERROR;
}
return tdID[i];
}
/**
* @ingroup Status
* @brief Return the VME Slot mask of initialized TDs
*
* @return Slot Mask if successful
*
*/
unsigned int
tdSlotMask()
{
int itd=0;
unsigned int dmask=0;
for(itd=0; itdboardID;
offset = ((unsigned long) &TDr->trigsrc) - base;
expected = 0x20;
if(offset != expected)
printf("%s: ERROR TDp->triggerSource not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->syncWidth) - base;
expected = 0x80;
if(offset != expected)
printf("%s: ERROR TDp->syncWidth not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->adr24) - base;
expected = 0xD0;
if(offset != expected)
printf("%s: ERROR TDp->adr24 not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->reset) - base;
expected = 0x100;
if(offset != expected)
printf("%s: ERROR TDp->reset not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->fpBusy) - base;
expected = 0x128;
if(offset != expected)
printf("%s: ERROR TDp->fpBusy not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->trigTable[0]) - base;
expected = 0x140;
if(offset != expected)
printf("%s: ERROR TDp->trigTable[0] not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->master_tiID) - base;
expected = 0x1F0;
if(offset != expected)
printf("%s: ERROR TDp->master_tiID not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->JTAGPROMBase[0]) - base;
expected = 0x10000;
if(offset != expected)
printf("%s: ERROR TDp->JTAGPROMBase[0] not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
offset = ((unsigned long) &TDr->JTAGFPGABase[0]) - base;
expected = 0x20000;
if(offset != expected)
printf("%s: ERROR TDp->JTAGFPGABase[0] not at offset = 0x%lx (@ 0x%lx)\n",
__FUNCTION__,expected,offset);
return OK;
}
/**
* @ingroup Status
* @brief Print some status information of the TD to standard out
*
* @param pflag
* - >0: print out raw registers
*
* @return OK if successful, ERROR otherwise
*/
void
tdStatus(int id, int pflag)
{
unsigned int boardID, fiber, intsetup, trigDelay;
unsigned int adr32, blocklevel, vmeControl, trigsrc, sync;
unsigned int busy, fiber_busy, blockBuffer;
unsigned int tsInput;
unsigned int output;
unsigned int livetime, busytime;
unsigned int inputCounter;
unsigned int blockStatus[5], iblock, nblocksReady, nblocksNeedAck;
unsigned int ifiber, fibermask;
unsigned long TDBase;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return;
}
/* Latch live and busy timers */
tdLatchTimers(id);
TDLOCK;
boardID = vmeRead32(&TDp[id]->boardID);
fiber = vmeRead32(&TDp[id]->fiber);
intsetup = vmeRead32(&TDp[id]->intsetup);
trigDelay = vmeRead32(&TDp[id]->trigDelay);
adr32 = vmeRead32(&TDp[id]->adr32);
blocklevel = vmeRead32(&TDp[id]->blocklevel);
vmeControl = vmeRead32(&TDp[id]->vmeControl);
trigsrc = vmeRead32(&TDp[id]->trigsrc);
sync = vmeRead32(&TDp[id]->sync);
busy = vmeRead32(&TDp[id]->busy);
fiber_busy = vmeRead32(&TDp[id]->fiber_busy);
blockBuffer = vmeRead32(&TDp[id]->blockBuffer);
tsInput = vmeRead32(&TDp[id]->tsInput);
output = vmeRead32(&TDp[id]->output);
livetime = vmeRead32(&TDp[id]->livetime);
busytime = vmeRead32(&TDp[id]->busytime);
inputCounter = vmeRead32(&TDp[id]->trigCount);
for(iblock=0;iblock<4;iblock++)
blockStatus[iblock] = vmeRead32(&TDp[id]->blockStatus[iblock]);
blockStatus[4] = vmeRead32(&TDp[id]->adr24);
TDUNLOCK;
TDBase = (unsigned long)TDp[id];
printf("\n");
#ifdef VXWORKS
printf("STATUS for TD %2d at base address 0x%08x \n",
id, (unsigned int) TDp[id]);
#else
printf("STATUS for TD %2d at VME (USER) base address 0x%08x (0x%08lx) \n",
id, (unsigned int)((unsigned long) TDp[id] - tdA24Offset), (unsigned long) TDp[id]);
#endif
printf("--------------------------------------------------------------------------------\n");
if(pflag>0)
{
printf(" Registers (offset):\n");
printf(" boardID (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->boardID) - TDBase, boardID);
printf(" fiber (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->fiber) - TDBase, fiber);
printf(" intsetup (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->intsetup) - TDBase, intsetup);
printf(" trigDelay (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->trigDelay) - TDBase, trigDelay);
printf(" adr32 (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->adr32) - TDBase, adr32);
printf(" vmeControl (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->vmeControl) - TDBase, vmeControl);
printf(" trigsrc (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->trigsrc) - TDBase, trigsrc);
printf(" sync (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->sync) - TDBase, sync);
printf(" busy (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->busy) - TDBase, busy);
printf(" blockBuffer (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->blockBuffer) - TDBase, blockBuffer);
printf(" output (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->output) - TDBase, output);
printf(" livetime (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->livetime) - TDBase, livetime);
printf(" busytime (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->busytime) - TDBase, busytime);
}
printf("\n");
printf(" Crate ID = 0x%02x\n",boardID&TD_BOARDID_CRATEID_MASK);
printf(" Block size = %d\n",blocklevel & TD_BLOCKLEVEL_MASK);
fibermask = fiber & TD_FIBER_MASK;
if(fibermask)
{
printf(" HFBR enabled (0x%x)= \n",fibermask);
for(ifiber=0; ifiber<8; ifiber++)
{
if( fibermask & (1<>8;
}
else
{
nblocksReady = (blockStatus[(ifiber-1)/2] & TD_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[(ifiber-1)/2] & TD_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
}
printf(" Fiber %d : Blocks ready / need acknowledge: %d / %d\n",
ifiber+1,nblocksReady, nblocksNeedAck);
}
}
printf(" Trigger counter = %d\n",inputCounter);
printf("--------------------------------------------------------------------------------\n");
printf("\n\n");
}
static
char portName[TD_MAX_VME_SLOTS][TD_MAX_FIBER_PORTS+1][TD_MAX_PORTNAME_CHARS];
/**
* @ingroup Config
* @brief Initialize portName array with default names in the form:
* Slot%2d - Port%d
* - This routine is called in tdInit(...)
*/
void
tdInitPortNames()
{
int islot=0, iport=0;
for(islot=0; islotTD_MAX_VME_SLOTS)
{
printf("%s: ERROR: Invalid Slot Number (%d)\n",
__FUNCTION__,id);
return ERROR;
}
if(iport>TD_MAX_FIBER_PORTS)
{
printf("%s: ERROR: Invalid Port Number (%d)\n",
__FUNCTION__,iport);
return ERROR;
}
if(name!=NULL)
{
if(strlen(name)>TD_MAX_PORTNAME_CHARS)
{
printf("%s: WARN: Truncating name (size = %d)\n",__FUNCTION__,strlen(name));
}
strncpy(portName[id][iport],name,TD_MAX_PORTNAME_CHARS);
}
else
{
printf("%s(%d): ERROR: Invalid input name\n",__FUNCTION__,id);
return ERROR;
}
return OK;
}
/**
* @ingroup Status
* @brief Get the current specified port name
* @param id Slot Number
* @param iport Port Number
* @param name Where to return port name
*
* @return OK if successful, otherwise ERROR.
*/
int
tdGetPortName(int id, int iport, char **name)
{
if(id==0) id=tdID[0];
if(iport>TD_MAX_FIBER_PORTS)
{
printf("%s: ERROR: Invalid port number (%d)\n",
__FUNCTION__,iport);
return ERROR;
}
if(name!=NULL)
{
strncpy((char *)name, portName[id][iport], TD_MAX_PORTNAME_CHARS);
}
else
{
printf("%s: Invalid pointer to return name\n",
__FUNCTION__);
return ERROR;
}
return OK;
}
/**
* @ingroup Status
* @brief Save the current port names to a file (with file name: filename)
*
* Format is the same which is expected by
* tdLoadPortNames(...)
* @param filename Name of output file
*
* @return OK if successful, otherwise ERROR.
*/
int
tdSavePortNames(char *filename)
{
FILE *outFile;
int islot=0, iport=0;
char name[TD_MAX_PORTNAME_CHARS+1];
outFile = fopen(filename,"w");
if(!outFile)
{
printf("%s: ERROR: Unable to open %s for writting\n",
__FUNCTION__,filename);
return ERROR;
}
for(islot=0; islot2))
{
printf("%s: ERROR: Invalid pflag (%d)\n",__FUNCTION__,pflag);
return;
}
/* Grab all of the register info we need */
TDLOCK;
for(itd=0; itdfiber);
trigsrc[id] = vmeRead32(&TDp[id]->trigsrc);
sync[id] = vmeRead32(&TDp[id]->sync);
busy[id] = vmeRead32(&TDp[id]->busy);
fiber_busy[id] = vmeRead32(&TDp[id]->fiber_busy);
blockBuffer[id] = vmeRead32(&TDp[id]->blockBuffer);
livetime[id] = vmeRead32(&TDp[id]->livetime);
busytime[id] = vmeRead32(&TDp[id]->busytime);
inputCounter[id] = vmeRead32(&TDp[id]->trigCount);
for(iblock=0;iblock<4;iblock++)
blockStatus[id][iblock] = vmeRead32(&TDp[id]->blockStatus[iblock]);
blockStatus[id][4] = vmeRead32(&TDp[id]->adr24);
}
TDUNLOCK;
printf("\n");
if((pflag==0) || (pflag==1))
{
printf("TD Module Status Summary\n");
/* printf(" Ports SyncSrc BusySrc Busy Status Waiting For \n"); */
/* printf("Slot (Connected, TrigSrcEn) (V15FL) (PLT12345678) (PL12345678) Trigger Ack\n"); */
printf(" Ports SyncSrc BusySrc Busy Status Triggers TrgAck\n");
printf("Slot (Connected, TrigSrcEn) (V15FL) (PLT12345678) (PL12345678) Received Wait\n");
printf("--------------------------------------------------------------------------------\n");
for(itd=0; itd>8;
}
else
{
nblocksReady = (blockStatus[id][(ifiber-1)/2] & TD_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[id][(ifiber-1)/2] & TD_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
}
printf(" %3d / %3d",nblocksReady, nblocksNeedAck);
printf("\n");
slaveCount++;
}
}
printf("\n");
printf("Total Slaves Added = %d\n",slaveCount);
}
printf("--------------------------------------------------------------------------------\n");
printf("\n");
}
/**
* @ingroup Config
* @brief Set the number of events per block
* @param id Slot number
* @param blockLevel Block Level
* @return OK if successful, ERROR otherwise
*/
int
tdSetBlockLevel(int id, unsigned int blockLevel)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if( (blockLevel>TD_BLOCKLEVEL_MASK) || (blockLevel==0) )
{
printf("%s: ERROR: Invalid Block Level (%d)\n",__FUNCTION__,blockLevel);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->blocklevel, blockLevel);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the block level for all initialized TDs
* @param blockLevel Block Level
* @return OK if successful, ERROR otherwise
*/
int
tdGSetBlockLevel(unsigned int blockLevel)
{
int res=OK, itd;
for(itd=0; itdTD_BLOCKBUFFER_BUFFERLEVEL_MASK)
{
printf("%s: ERROR: Invalid value for level (%d)\n",
__FUNCTION__,level);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->blockBuffer, level);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the block buffer level for the number of blocks in the system
* that need to be read out for all initialized TDs.
*
* If this buffer level is full, the TD 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
tdGSetBlockBufferLevel(unsigned int level)
{
int res=OK, itd;
for(itd=0; itdreset,TD_RESET_JTAG);
/* Reset FPGA JTAG to "reset_idle" state */
vmeWrite32(&TDp[id]->JTAGFPGABase[(0x003C)>>2],0);
/* enable the user_code readback */
vmeWrite32(&TDp[id]->JTAGFPGABase[(0x092C)>>2],0x3c8);
/* shift in 32-bit to FPGA JTAG */
vmeWrite32(&TDp[id]->JTAGFPGABase[(0x1F1C)>>2],0);
/* Readback the firmware version */
rval = vmeRead32(&TDp[id]->JTAGFPGABase[(0x1F1C)>>2]);
TDUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Enable Fiber transceiver
*
* Note: All Fiber are enabled by default
* (no harm, except for 1-2W power usage)
*
*
* @param id Slot number
* @param fiber integer indicative of the transceiver to enable
*
* @return OK if successful, ERROR otherwise.
*
*/
int
tdEnableFiber(int id, unsigned int fiber)
{
unsigned int sval;
unsigned int fiberbit;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((fiber<1) | (fiber>8))
{
printf("%s: ERROR: Invalid value for fiber (%d)\n",
__FUNCTION__,fiber);
return ERROR;
}
fiberbit = (1<<(fiber-1));
TDLOCK;
sval = vmeRead32(&TDp[id]->fiber);
vmeWrite32(&TDp[id]->fiber,
sval | fiberbit );
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Disable Fiber transceiver
*
* @param id Slot number
* @param fiber integer indicative of the transceiver to disable
*
* @return OK if successful, ERROR otherwise.
*
*/
int
tdDisableFiber(int id, unsigned int fiber)
{
unsigned int rval;
unsigned int fiberbit;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((fiber<1) | (fiber>8))
{
printf("%s: ERROR: Invalid value for fiber (%d)\n",
__FUNCTION__,fiber);
return ERROR;
}
fiberbit = (1<<(fiber-1));
TDLOCK;
rval = vmeRead32(&TDp[id]->fiber);
vmeWrite32(&TDp[id]->fiber,
rval & ~fiberbit );
TDUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Enable/Disable fiber ports according to specified mask
* @param id Slot number
* @param fibermask mask indicative of the transceivers to enable/disable
*
* @return OK if successful, ERROR otherwise.
*/
int
tdSetFiberMask(int id, unsigned int fibermask)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if(fibermask>0xFF)
{
printf("%s: ERROR: Invalid value for fibermask (%d)\n",
__FUNCTION__,fibermask);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->fiber, fibermask);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the busy source with a specified sourcemask
*
* @param id Slot number
* @param sourcemask bits:
* - N: FIXME: FILL THIS IN
*
* @param rFlag - decision to reset the global source flags
* - 0: Keep prior busy source settings and set new "sourcemask"
* - 1: Reset, using only that specified with "sourcemask"
* @return OK if successful, ERROR otherwise.
*/
int
tdSetBusySource(int id, unsigned int sourcemask, int rFlag)
{
unsigned int busybits=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if(sourcemask>TD_BUSY_SOURCEMASK)
{
printf("%s: ERROR: Invalid value for sourcemask (0x%x)\n",
__FUNCTION__, sourcemask);
return ERROR;
}
TDLOCK;
if(rFlag)
{
/* Read in the previous value , resetting previous BUSYs*/
busybits = vmeRead32(&TDp[id]->busy) & ~(TD_BUSY_SOURCEMASK);
}
else
{
/* Read in the previous value , keeping previous BUSYs*/
busybits = vmeRead32(&TDp[id]->busy);
}
busybits |= sourcemask;
vmeWrite32(&TDp[id]->busy, busybits);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the the trigger lock mode for the specified TD
*
* @param id Slot number
* @param enable Enable flag
* 0: Disable
* !0: Enable
*
* @return OK if successful, ERROR otherwise.
*/
int
tdSetTriggerLock(int id, int enable)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
if(enable)
vmeWrite32(&TDp[id]->busy,
vmeRead32(&TDp[id]->busy) | TD_BUSY_TRIGGER_LOCK);
else
vmeWrite32(&TDp[id]->busy,
vmeRead32(&TDp[id]->busy) & ~TD_BUSY_TRIGGER_LOCK);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set the the trigger lock mode for all initialized TDs
*
* @param enable Enable flag
* 0: Disable
* !0: Enable
*
* @return OK if successful, ERROR otherwise.
*/
int
tdGSetTriggerLock(int enable)
{
int itd=0, id=0;
TDLOCK;
for(itd=0; itdbusy,
vmeRead32(&TDp[id]->busy) | TD_BUSY_TRIGGER_LOCK);
else
vmeWrite32(&TDp[id]->busy,
vmeRead32(&TDp[id]->busy) & ~TD_BUSY_TRIGGER_LOCK);
}
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Get the current setting of the trigger lock mode for the specified TD
*
* @param id Slot number
*
* @return 1 if enabled, 0 if disabled, ERROR otherwise.
*/
int
tdGetTriggerLock(int id)
{
int rval=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = (vmeRead32(&TDp[id]->busy) & TD_BUSY_TRIGGER_LOCK)>>6;
TDUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Set the Sync source mask
*
* @param id Slot number
* @param sync - MASK indicating the sync source
* - 0: P0
* - 1: HFBR1
* - 2: HFBR5
* - 3: FP
* - 4: LOOPBACK
*
* @return OK if successful, ERROR otherwise
*
*/
int
tdSetSyncSource(int id, unsigned int sync)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if(sync>TD_SYNC_SOURCEMASK)
{
printf("%s: ERROR: Invalid Sync Source Mask (%d).\n",
__FUNCTION__,sync);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->sync,sync);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Set trigger sources with specified trigmask
*
* @param id Slot number
* @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
tdSetTriggerSource(int id, int trigmask)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
/* Check input mask */
if(trigmask>TD_TRIGSRC_SOURCEMASK)
{
printf("%s: ERROR: Invalid trigger source mask (0x%x).\n",
__FUNCTION__,trigmask);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->trigsrc, trigmask);
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Reset the configuration of TI Slaves on the TD.
*
* This routine removes all slaves and resets the fiber port busys.
*
* @param id Slot number
*
* @return OK if successful, ERROR otherwise
*
*/
int
tdResetSlaveConfig(int id)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
tdSlaveMask[id] = 0;
vmeWrite32(&TDp[id]->busy, (vmeRead32(&TDp[id]->busy) & ~TD_BUSY_HFBR_MASK));
TDUNLOCK;
return OK;
}
/**
* @ingroup Config
* @brief Add and configure a TI Slave for the TD.
*
* This routine should be used by the TD to configure
* HFBR port and BUSY sources.
*
* @param id Slot number
* @param fiber The fiber port of the TD that is connected to the slave
*
* @return OK if successful, ERROR otherwise
*/
int
tdAddSlave(int id, unsigned int fiber)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((fiber<1) || (fiber>8) )
{
printf("%s: ERROR: Invalid value for fiber (%d)\n",
__FUNCTION__,fiber);
return ERROR;
}
/* Add this slave to the global slave mask */
tdSlaveMask[id] |= (1<<(fiber-1));
/* Add this fiber as a busy source (use first fiber macro as the base) */
if(tdSetBusySource(id, TD_BUSY_HFBR1<<(fiber-1),0)!=OK)
return ERROR;
/* Enable the fiber */
if(tdEnableFiber(id, fiber)!=OK)
return ERROR;
return OK;
}
/**
* @ingroup Config
* @brief Remove a TI Slave for the TD.
*
* @param id Slot number
* @param fiber The fiber port of the TD to remove.
*
* @return OK if successful, ERROR otherwise
*/
int
tdRemoveSlave(int id, unsigned int fiber)
{
unsigned int busybits;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((fiber<1) || (fiber>8) )
{
printf("%s: ERROR: Invalid value for fiber (%d)\n",
__FUNCTION__,fiber);
return ERROR;
}
/* Remove this slave to the global slave mask */
tdSlaveMask[id] &= ~(1<<(fiber-1));
/* Remove this fiber as a busy source (use first fiber macro as the base) */
TDLOCK;
/* Read in previous values, keeping current busy's */
busybits = vmeRead32(&TDp[id]->busy);
/* Turn off busy to the fiber in question */
busybits &= ~(1<<(TD_BUSY_HFBR1-1+fiber));
/* Write the new mask */
vmeWrite32(&TDp[id]->busy, busybits);
TDUNLOCK;
/* Keep the fiber enabled: No call to tdEnableFiber(..) */
return OK;
}
/**
* @ingroup Config
* @brief Add and configure TI Slaves by using a mask for the TD.
*
* This routine should be used by the TD to configure
* HFBR ports and BUSY sources.
*
* @param id Slot number
* @param fibermask The fiber port mask of the TDs that are connected to
* the slaves. bit 0 - port 1... bit 7 - port 8
*
* @return OK if successful, ERROR otherwise
*/
int
tdAddSlaveMask(int id, unsigned int fibermask)
{
int ibit=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((fibermask==0) || (fibermask>0x100))
{
printf("%s: ERROR: Invalid value for fibermask (0x%x)\n",
__FUNCTION__,fibermask);
return ERROR;
}
for(ibit=0; ibit<8; ibit++)
{
if(fibermask & (1<reset, TD_RESET_IODELAY);
taskDelay(1);
/* Auto Align */
vmeWrite32(&TDp[id]->reset, TD_RESET_AUTOALIGN_P0_SYNC);
taskDelay(1);
TDUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the Module Serial Number
*
* @param id Slot number
* @param rSN Pointer to string to pass Serial Number
*
* @return SerialNumber if successful, ERROR otherwise
*
*/
unsigned int
tdGetSerialNumber(int id, char **rSN)
{
unsigned int rval=0;
char retSN[10];
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD (id=%2d) not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->reset,TD_RESET_JTAG); /* reset */
vmeWrite32(&TDp[id]->JTAGPROMBase[(0x3c)>>2],0); /* Reset_idle */
vmeWrite32(&TDp[id]->JTAGPROMBase[(0xf2c)>>2],0xFD); /* load the UserCode Enable */
vmeWrite32(&TDp[id]->JTAGPROMBase[(0x1f1c)>>2],0); /* shift in 32-bit of data */
rval = vmeRead32(&TDp[id]->JTAGPROMBase[(0x1f1c)>>2]);
TDUNLOCK;
if(rSN!=NULL)
{
sprintf(retSN,"TD-%d",rval&0xfff);
strcpy((char *)rSN,retSN);
}
printf("%s: TD in slot %2d Serial Number is %s (0x%08x)\n",
__FUNCTION__,id,retSN,rval);
return rval;
}
/**
* @ingroup Config
* @brief Latch the Busy and Live Timers.
*
* This routine should be called prior to a call to tdGetLiveTime and tdGetBusyTime
*
* @param id Slot number
* @sa tdGetLiveTime
* @sa tdGetBusyTime
*
* @return OK if successful, ERROR otherwise
*/
int
tdLatchTimers(int id)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->reset, TD_RESET_LATCH_TIMERS);
TDUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Return the current "live" time of the module
* @param id Slot number
*
* @returns The current live time in units of 7.68 us
*
*/
unsigned int
tdGetLiveTime(int id)
{
unsigned int rval=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = vmeRead32(&TDp[id]->livetime);
TDUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Return the current "busy" time of the module
* @param id Slot number
*
* @returns The current live time in units of 7.68 us
*
*/
unsigned int
tdGetBusyTime(int id)
{
unsigned int rval=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = vmeRead32(&TDp[id]->busytime);
TDUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Configure which ports (and self) to enable response of a SyncReset request.
* @param id Slot number
* @param portMask Mask of ports to enable (port 1 = bit 0)
* @param self 1 to enable self, 0 to disable
*
* @return OK if successful, otherwise ERROR
*/
int
tdEnableSyncResetRequest(int id, unsigned int portMask)
{
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if(portMask > 0xFF)
{
printf("%s: ERROR: Invalid portMask (0x%x)\n",
__FUNCTION__, portMask);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->rocEnable,
(vmeRead32(&TDp[id]->rocEnable) & TD_ROCENABLE_MASK) |
(portMask << 11));
TDUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Status of SyncReset Request received bits.
* @param id Slot number
* @param pflag Print to standard out if not 0
* @return Port mask of SyncReset Request received (port 1 = bit 0), otherwise ERROR;
*/
int
tdSyncResetRequestStatus(int id, int pflag)
{
int rval = 0, ibit = 0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = (int)(vmeRead32(&TDp[id]->rocEnable) & TD_ROCENABLE_SYNCRESET_REQUEST_MONITOR_MASK);
TDUNLOCK;
/* Reorganize the bits */
if(rval)
{
rval = rval >> 1;
}
if(pflag)
{
if(rval)
{
printf(" ***** SyncReset Requested from ");
for(ibit = 0; ibit < 8; ibit++)
{
printf("%d ", ibit + 1);
}
printf("*****\n");
}
else
{
printf(" No SyncReset Requested\n");
}
}
return rval;
}
/**
* @ingroup Status
* @brief Returns the mask of fiber channels that report a "connected" status from a TI.
* @param id Slot number
*
* @return mask of fiber channels that report "connected"
*/
int
tdGetConnectedFiberMask(int id)
{
int rval=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = (vmeRead32(&TDp[id]->fiber) & TD_FIBER_CONNECTED_MASK)>>16;
TDUNLOCK;
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.
*
* @param id Slot number
*
* @return mask of fiber channels that report "enabled" trigger source
*/
int
tdGetTrigSrcEnabledFiberMask(int id)
{
int rval=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = (vmeRead32(&TDp[id]->fiber) & TD_FIBER_TRIGSRC_ENABLED_MASK)>>24;
TDUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Reset the triggers enabled status bits of TI Slaves.
*
* @param id Slot number
*
* @return OK if successful, otherwise ERROR
*/
int
tdTriggerReadyReset(int id)
{
unsigned int syncsource=0;
if(id==0) id=tdID[0];
if(TDp[id]==NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
/* Reset Receiver */
vmeWrite32(&TDp[id]->reset, TD_RESET_MGT_RX_RESET);
taskDelay(1);
/* Get the current SyncReset Source */
syncsource = vmeRead32(&TDp[id]->sync) & TD_SYNC_SOURCEMASK;
/* Set Loopback as Source */
vmeWrite32(&TDp[id]->sync, TD_SYNC_LOOPBACK);
/* Send the Trigger Source Enabled Reset */
vmeWrite32(&TDp[id]->syncCommand,TD_SYNCCOMMAND_TRIGGER_READY_RESET);
/* Restore original SyncReset Source */
vmeWrite32(&TDp[id]->sync, syncsource);
TDUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Get the crate ID of the selected port
* @param id Slot number
* @param port
* - 1-8: Fiber port 1-8
*
* @return port Crate ID if successful, ERROR otherwise
*
*/
int
tdGetCrateID(int id, int port)
{
int rval=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((port<1) || (port>8))
{
printf("%s: ERROR: Invalid port (%d)\n",
__FUNCTION__,port);
}
TDLOCK;
rval = (vmeRead32(&TDp[id]->hfbr_tiID[port-1]) & TD_ID_CRATEID_MASK)>>8;
TDUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Set the port names for the specified TD from the received Crate IDs from the TI Slaves.
* @param id Slot number
* @return OK if successful, otherwise ERROR;
*/
int
tdSetPortNamesFromCrateID(int id)
{
int iport=0, crateID=0;
char portname[20];
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
for(iport=1; iport<9; iport++)
{
crateID = tdGetCrateID(id, iport);
sprintf((char *)&portname,"ROC%d",crateID);
tdSetPortName(id,iport,portname);
}
return OK;
}
/**
* @ingroup Config
* @brief Set the port names for all initialized TD from the received Crate IDs from the TI Slaves.
* @return OK if successful, otherwise ERROR;
*/
void
tdGSetPortNamesFromCrateID()
{
int itd=0;
for(itd=0; itd8))
{
printf("%s: ERROR: Invalid port (%d)\n",
__FUNCTION__,port);
}
TDLOCK;
rval = (vmeRead32(&TDp[id]->hfbr_tiID[port-1]) & TD_ID_TRIGSRC_ENABLE_MASK);
TDUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Get the blocklevel of the TI Slave on the selected port
* @param id Slot number
* @param port
* - 1-8: Fiber port 1-8
*
* @return port blocklevel if successful, ERROR otherwise
*/
int
tdGetSlaveBlocklevel(int id, int port)
{
int rval=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((port<1) || (port>8))
{
printf("%s: ERROR: Invalid port (%d)\n",
__FUNCTION__,port);
}
TDLOCK;
rval = (vmeRead32(&TDp[id]->hfbr_tiID[port-1]) & TD_ID_BLOCKLEVEL_MASK)>>16;
TDUNLOCK;
return rval;
}
/**
* @ingroup Config
* @brief Reset the MGT
* @param id Slot number
*/
int
tdResetMGT(int id)
{
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->reset, TD_RESET_MGT);
TDUNLOCK;
taskDelay(1);
return OK;
}
/**
* @ingroup Config
* @brief Reset the MGT Rx CDR
* @param id Slot number
*/
int
tdResetMGTRx(int id)
{
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
vmeWrite32(&TDp[id]->reset, TD_RESET_MGT_RX_RESET);
TDUNLOCK;
taskDelay(1);
return OK;
}
/**
* @ingroup Status
* @brief Print a summary of all fiber port connections to potential TI Slaves
*
* @param id Slot number
* @param pflag
* - 0: Default output
* - 1: Print Raw Registers
*/
void
tdSlaveStatus(int id, int pflag)
{
int iport=0, ibs=0, ifiber=0;
unsigned long TDBase;
unsigned int hfbr_tiID[8] = {1,2,3,4,5,6,7,8};
unsigned int blockStatus[5];
unsigned int fiber=0, busy=0, trigsrc=0;
int nblocksReady=0, nblocksNeedAck=0, slaveCount=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return;
}
TDLOCK;
for(iport=0; iport<8; iport++)
{
hfbr_tiID[iport] = vmeRead32(&TDp[id]->hfbr_tiID[iport]);
}
fiber = vmeRead32(&TDp[id]->fiber);
busy = vmeRead32(&TDp[id]->busy);
trigsrc = vmeRead32(&TDp[id]->trigsrc);
for(ibs=0; ibs<4; ibs++)
{
blockStatus[ibs] = vmeRead32(&TDp[id]->blockStatus[ibs]);
}
TDUNLOCK;
TDBase = (unsigned long)TDp[id];
printf("TD - Slot %2d - Port STATUS Summary\n",id);
printf(" Block Status\n");
if(pflag>0)
{
printf(" Registers (offset):\n");
printf(" TDBase (0x%08lx)\n",TDBase-tdA24Offset);
printf(" busy (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->busy) - TDBase, busy);
printf(" fiber (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->fiber) - TDBase, fiber);
printf(" hfbr_tiID[0] (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->hfbr_tiID[0]) - TDBase, hfbr_tiID[0]);
printf(" hfbr_tiID[1] (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->hfbr_tiID[1]) - TDBase, hfbr_tiID[1]);
printf(" hfbr_tiID[2] (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->hfbr_tiID[2]) - TDBase, hfbr_tiID[2]);
printf(" hfbr_tiID[3] (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->hfbr_tiID[3]) - TDBase, hfbr_tiID[3]);
printf(" hfbr_tiID[4] (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->hfbr_tiID[4]) - TDBase, hfbr_tiID[4]);
printf(" hfbr_tiID[5] (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->hfbr_tiID[5]) - TDBase, hfbr_tiID[5]);
printf(" hfbr_tiID[6] (0x%04lx) = 0x%08x\t", (unsigned long)(&TDp[id]->hfbr_tiID[6]) - TDBase, hfbr_tiID[6]);
printf(" hfbr_tiID[7] (0x%04lx) = 0x%08x\n", (unsigned long)(&TDp[id]->hfbr_tiID[7]) - TDBase, hfbr_tiID[7]);
printf("\n\n");
}
printf("Port ROCID Connected TrigSrcEn Busy Status Ready / NeedAck Blocklevel\n");
printf("--------------------------------------------------------------------------------\n");
/* Slaves last */
for(iport=1; iport<9; iport++)
{
/* Only continue of this port has been configured as a slave */
if((tdSlaveMask[id] & (1<<(iport-1)))==0) continue;
/* Slot and Port number */
printf("%d ", iport);
/* Port Name */
printf("%5d ",
(hfbr_tiID[iport-1]&TD_ID_CRATEID_MASK)>>8);
/* Connection Status */
printf("%s %s ",
(fiber & TD_FIBER_CONNECTED_TI(iport))?"YES":"NO ",
(fiber & TD_FIBER_TRIGSRC_ENABLED_TI(iport))?"ENABLED ":"DISABLED");
/* Busy Status */
printf("%s ",
(busy & TD_BUSY_MONITOR_FIBER_BUSY(iport))?"BUSY":" ");
/* Block Status */
ifiber=iport-1;
if( (ifiber % 2) == 0)
{
nblocksReady = blockStatus[ifiber/2] & TD_BLOCKSTATUS_NBLOCKS_READY0;
nblocksNeedAck = (blockStatus[ifiber/2] & TD_BLOCKSTATUS_NBLOCKS_NEEDACK0)>>8;
}
else
{
nblocksReady = (blockStatus[(ifiber-1)/2] & TD_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (blockStatus[(ifiber-1)/2] & TD_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
}
printf(" %3d / %3d",nblocksReady, nblocksNeedAck);
printf(" %3d",(hfbr_tiID[iport-1]&TD_ID_BLOCKLEVEL_MASK)>>16);
printf("\n");
slaveCount++;
}
printf("\n");
printf("Total Slaves Added = %d\n",slaveCount);
}
/**
* @ingroup Status
* @brief Obtain the status of blocks sent readout acknowledges received from the TI Slaves.
*
* @param id Slot number
* @param port Port number (1-8)
* @param pflag
* - !0: Print to standard out
*
* @return 16 bit integer with the following:
* - bits 0-7: The number of blocks sent to the TI Slave that have not been acknowedged.
* - bits 8-15: The number of blocks that have been acknowedged, but still require a readout acknowledge.
*/
unsigned int
tdGetBlockStatus(int id, int port, int pflag)
{
unsigned int rval=0;
int fiber=0, nblocksReady=0, nblocksNeedAck=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((port<1) || (port>8))
{
printf("%s: ERROR: Invalid port number (%d)\n",
__FUNCTION__,port);
return ERROR;
}
fiber=port-1;
TDLOCK;
if( (fiber % 2) == 0)
{
rval = vmeRead32(&TDp[id]->blockStatus[fiber/2]);
nblocksReady = rval & TD_BLOCKSTATUS_NBLOCKS_READY0;
nblocksNeedAck = (rval & TD_BLOCKSTATUS_NBLOCKS_NEEDACK0)>>8;
rval = rval & 0xFFFF;
}
else
{
rval = vmeRead32(&TDp[id]->blockStatus[(fiber-1)/2]);
nblocksReady = (rval & TD_BLOCKSTATUS_NBLOCKS_READY1)>>16;
nblocksNeedAck = (rval & TD_BLOCKSTATUS_NBLOCKS_NEEDACK1)>>24;
rval = (rval & 0xFFFF0000)>>16;
}
TDUNLOCK;
if(pflag)
{
printf(" %3d / %3d",nblocksReady, nblocksNeedAck);
}
return rval;
}
int
tdGetBusyStatus(int id, int port, int pflag)
{
unsigned int rval=0;
unsigned int busy=0;
unsigned int fiber_busy=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if((port<1) || (port>8))
{
printf("%s: ERROR: Invalid port number (%d)\n",
__FUNCTION__,port);
return ERROR;
}
TDLOCK;
busy = vmeRead32(&TDp[id]->busy);
fiber_busy = vmeRead32(&TDp[id]->fiber_busy);
TDUNLOCK;
if(busy & TD_BUSY_MONITOR_FIBER_BUSY(port))
{
rval = 1;
if(pflag)
printf("%s(%d): Port %d is BUSY (%s)\n",
__FUNCTION__,id,port,
(fiber_busy & TD_FIBER_BUSY(port))?"Fiber":"Block Count");
}
else
{
rval = 0;
if(pflag)
printf("%s(%d): Port %d is NOT BUSY\n",
__FUNCTION__,id,port);
}
return rval;
}
/**
* @ingroup Config
* @brief Set (or unset) high level for the output ports on the front panel
* labelled as O#1-4
*
* @param set1 O#1
* @param set2 O#2
* @param set3 O#3
* @param set4 O#4
*
* @return OK if successful, otherwise ERROR
*/
int
tdSetOutputPort(int id, unsigned int set1, unsigned int set2, unsigned int set3, unsigned int set4)
{
unsigned int bits=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
if(set1)
bits |= (1<<0);
if(set2)
bits |= (1<<1);
if(set3)
bits |= (1<<2);
if(set4)
bits |= (1<<3);
TDLOCK;
vmeWrite32(&TDp[id]->output, bits);
TDUNLOCK;
return OK;
}
/**
* @ingroup Status
* @brief Return the number of triggers received from the trigger supervisor.
*
* @param id Slot number
*
* @return trigger count if successful, otherwise ERROR
*/
unsigned int
tdGetTrigCount(int id)
{
unsigned int rval=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
rval = vmeRead32(&TDp[id]->trigCount);
TDUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Return BUSY counter for specified Busy Source
* @param id Slot number
* @param busysrc
* - 0: SWA
* - 1: SWB
* - 2: P2
* - 3: FP-FTDC
* - 4: FP-FADC
* - 5: FP
* - 6: Unused
* - 7: Loopack
* - 8-15: Fiber 1-8
* @return
* - Busy counter for specified busy source
*/
unsigned int
tdGetBusyCounter(int id, int busysrc)
{
unsigned int rval=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
if(busysrc<7)
rval = vmeRead32(&TDp[id]->busy_scaler1[busysrc]);
else
rval = vmeRead32(&TDp[id]->busy_scaler2[busysrc-7]);
TDUNLOCK;
return rval;
}
/**
* @ingroup Status
* @brief Print the BUSY counters for all busy sources
* @param id Slot number
* @return
* - OK if successful, otherwise ERROR;
*/
int
tdPrintBusyCounters(int id)
{
unsigned int counter[16];
const char *scounter[16] =
{
"SWA ",
"SWB ",
"P2 ",
"FP-FTDC",
"FP-FADC",
"FP ",
"Unused ",
"Loopack",
"Fiber 1",
"Fiber 2",
"Fiber 3",
"Fiber 4",
"Fiber 5",
"Fiber 6",
"Fiber 7",
"Fiber 8"
};
int icnt=0;
if(id==0) id=tdID[0];
if(TDp[id] == NULL)
{
printf("%s: ERROR: TD in slot %d not initialized\n",__FUNCTION__,id);
return ERROR;
}
TDLOCK;
for(icnt=0; icnt<16; icnt++)
{
if(icnt<7)
counter[icnt] = vmeRead32(&TDp[id]->busy_scaler1[icnt]);
else
counter[icnt] = vmeRead32(&TDp[id]->busy_scaler2[icnt-7]);
}
TDUNLOCK;
printf("\n\n");
printf(" Busy Counters \n");
printf("--------------------------------------------------------------------------------\n");
for(icnt=0; icnt<16; icnt++)
{
printf("%s 0x%08x (%10d)\n",
scounter[icnt], counter[icnt], counter[icnt]);
}
printf("--------------------------------------------------------------------------------\n");
printf("\n\n");
return OK;
}