/*----------------------------------------------------------------------------*/ /** * @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; }