/************************************************************************************* * primFuncts.c * * synopsis: Contains the primitive functions common to both DSPs, and the function * which initializes the array of pointers to these functions. * * in this file: initializePrimParams, noPrimitive, echo, setErrMsgMask, pauseList, * eventTrapSetup, setMemory, copyMemory, memoryTest, setLed, flashLed, * sendData, moduleMask, setTrigger, startTask, taskOperation, * writeBuffer. * * related files: * listManager.c: Routines which manage the execution of a primitive list and * writing the reply data. * primFuncts.h: Declares the structure tag which communicates necessary information * to primitive functions. * primParams.h: Defines primitive ids which are used to index the array of pointers * to primitive functions, structure tags for primitive data and reply * data, and prototypes of primitive functions. * eventHandler.c, .h: Contain many routines and variable definitions needed by the * event trapping & histogram related routines. * histogram.c, .h: Contains routines and variable definitions needed for * histogramming. * * Damon Fasching, UW Madison fasching@wisconsin.cern.ch * Douglas Ferguson, UW Madison (510) 486-5230 dpferguson@lbl.gov * Tom Meyer, Iowa State University meyer@iastate.edu * Roy McKay, Iowa State University mckay@iastate.edu ************************************************************************************/ #include #include #include #include #include #include #include "resources.h" #include "listProc.h" #include "comRegDfns.h" #if (defined(I_AM_MASTER_DSP)) #include "accessSlave.h" #endif extern char genStr[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ extern far ModuleMaskData moduleMaskData[N_TOTMODULES]; #if defined(I_AM_MASTER_DSP) extern far Module moduleConfigSet[N_MODULE_CONFIG_SETS][N_TOTMODULES]; #elif defined(I_AM_SLAVE_DSP) extern far UINT32 maskDataFlag, calCoeffFlag; extern far HistoCtrl histoCtrl; extern far BinCtr binCtr; #endif #pragma CODE_SECTION(initializePrimParams, "xcode"); #pragma CODE_SECTION(noPrimitive, "xcode"); #pragma CODE_SECTION(echo, "xcode"); #pragma CODE_SECTION(setMessageMask, "xcode"); #pragma CODE_SECTION(pauseList, "xcode"); #pragma CODE_SECTION(eventTrapSetup, "xcode"); #pragma CODE_SECTION(setMemory, "xcode"); #pragma CODE_SECTION(copyMemory, "xcode"); #pragma CODE_SECTION(memoryTest, "xcode"); #pragma CODE_SECTION(setLed, "xcode"); #pragma CODE_SECTION(flashLed, "xcode"); #pragma CODE_SECTION(sendData, "xcode"); #pragma CODE_SECTION(moduleMask, "xcode"); #pragma CODE_SECTION(setTrigger, "xcode"); #pragma CODE_SECTION(startTask, "xcode"); #pragma CODE_SECTION(taskOperation, "xcode"); #pragma CODE_SECTION(setBin, "xcode"); #pragma CODE_SECTION(writeBuffer, "xcode"); /************************************************************************************* * initializePrimParams * * synopsis: Loads the array of primitive revisions and function pointers. * * author: Damon Fasching * * modifications/bugs * - The primitive IDs have been decoupled from the list structure, so that * primitive lists on the vme host do not have to be re-written with each * insertion of a primitive (alternative was to always tack onto the end, * which eventually will lead to confusion). This demands a new array which * stores the IDs. 16.04.02 dpsf ************************************************************************************/ void initializePrimParams(UINT32 primIDList[],struct PRIM_PARAMETERS primParameters[], UINT32 *listRevision) { INT32 primLoop; *listRevision = PRIM_LIST_REVISION; /* First initialize all to dummy values. */ for (primLoop = 0; primLoop < NUM_PRIMITIVES; ++primLoop) { primIDList[primLoop]= 0xffffffff; primParameters[primLoop].fxnValidate = pass_validate; primParameters[primLoop].primFunction = noPrimitive; primParameters[primLoop].primRevision = UNINITIALIZED_PRIM; } /* Initialize the primitive ID list and the primParameters structure; the ordering of the list is arbitrary, but for consistency should be ordered as in primParams.h If an input primitive ID is not on the list, execPrim will generate an error message. */ /* functions common to both DSP types: */ primLoop= 0; primIDList[primLoop]= ECHO; primParameters[primLoop].primFunction= echo; primParameters[primLoop++].primRevision= R_ECHO; primIDList[primLoop]= SET_MESSAGE_MASK; primParameters[primLoop].primFunction= setMessageMask; primParameters[primLoop++].primRevision= R_SET_MESSAGE_MASK; primIDList[primLoop]= PAUSE_LIST; primParameters[primLoop].primFunction= pauseList; primParameters[primLoop++].primRevision= R_PAUSE_LIST; //EventTrapSetup: VME host -> MDSP -> SDSP primIDList[primLoop]= EVENT_TRAP_SETUP; primParameters[primLoop].primFunction= eventTrapSetup; primParameters[primLoop++].primRevision= R_EVENT_TRAP_SETUP; primIDList[primLoop]= SET_MEMORY; primParameters[primLoop].primFunction= setMemory; primParameters[primLoop++].primRevision= R_SET_MEMORY; primIDList[primLoop]= COPY_MEMORY; primParameters[primLoop].primFunction= copyMemory; primParameters[primLoop++].primRevision= R_COPY_MEMORY; primIDList[primLoop]= MEMORY_TEST; primParameters[primLoop].primFunction= memoryTest; primParameters[primLoop++].primRevision= R_MEMORY_TEST; primIDList[primLoop]= SET_LED; primParameters[primLoop].primFunction= setLed; primParameters[primLoop++].primRevision= R_SET_LED; primIDList[primLoop]= FLASH_LED; primParameters[primLoop].primFunction= flashLed; primParameters[primLoop++].primRevision= R_FLASH_LED; primIDList[primLoop]= SEND_DATA; primParameters[primLoop].primFunction= sendData; primParameters[primLoop++].primRevision= R_SEND_DATA; primIDList[primLoop]= MODULE_MASK; primParameters[primLoop].primFunction= moduleMask; primParameters[primLoop++].primRevision= R_MODULE_MASK; primIDList[primLoop]= SET_TRIGGER; primParameters[primLoop].primFunction= setTrigger; primParameters[primLoop++].primRevision= R_SET_TRIGGER; primIDList[primLoop]= START_TASK; primParameters[primLoop].primFunction= startTask; primParameters[primLoop].fxnValidate= startTask_validate; //Validation. primParameters[primLoop++].primRevision= R_START_TASK; primIDList[primLoop]= TASK_OPERATION; primParameters[primLoop].primFunction= taskOperation; primParameters[primLoop++].primRevision= R_TASK_OPERATION; primIDList[primLoop]= TEST; primParameters[primLoop].primFunction= test; primParameters[primLoop++].primRevision= R_TEST; primIDList[primLoop]= WRITE_BUFFER; primParameters[primLoop].primFunction= writeBuffer; primParameters[primLoop++].primRevision= R_WRITE_BUFFER; #if defined(I_AM_SLAVE_DSP) /* functions for the slave DSPs: */ primIDList[primLoop]= START_EVENT_TRAPPING; primParameters[primLoop].primFunction= startEventTrapping; primParameters[primLoop++].primRevision= R_START_EVENT_TRAPPING; primIDList[primLoop]= STOP_EVENT_TRAPPING; primParameters[primLoop].primFunction= stopEventTrapping; primParameters[primLoop++].primRevision= R_STOP_EVENT_TRAPPING; primIDList[primLoop]= HISTOGRAM_SETUP; primParameters[primLoop].primFunction= histogramSetup; primParameters[primLoop++].primRevision= R_HISTOGRAM_SETUP; #elif defined(I_AM_MASTER_DSP) /* functions for the master DSP: */ primIDList[primLoop]= RW_SLAVE_MEMORY; primParameters[primLoop].primFunction= rwSlaveMemory; primParameters[primLoop++].primRevision= R_RW_SLAVE_MEMORY; primIDList[primLoop]= TRANS_SERIAL_DATA; primParameters[primLoop].primFunction= transSerialData; primParameters[primLoop++].primRevision= R_TRANS_SERIAL_DATA; primIDList[primLoop]= START_SLAVE_EXECUTING; primParameters[primLoop].primFunction= startSlaveExecuting; primParameters[primLoop++].primRevision= R_START_SLAVE_EXECUTING; primIDList[primLoop]= CONFIG_SLAVE; primParameters[primLoop].primFunction= configSlave; primParameters[primLoop++].primRevision= R_CONFIG_SLAVE; primIDList[primLoop]= RW_REG_FIELD; primParameters[primLoop].primFunction= rwRegField; primParameters[primLoop++].primRevision= R_RW_REG_FIELD; primIDList[primLoop]= POLL_REG_FIELD; primParameters[primLoop].primFunction= pollRegField; primParameters[primLoop++].primRevision= R_POLL_REG_FIELD; primIDList[primLoop]= RW_FIFO; primParameters[primLoop].primFunction= rwFifo; primParameters[primLoop++].primRevision= R_RW_FIFO; primIDList[primLoop]= SEND_SLAVE_LIST; primParameters[primLoop].primFunction= sendSlaveList; primParameters[primLoop++].primRevision= R_SEND_SLAVE_LIST; primIDList[primLoop]= START_SLAVE_LIST; primParameters[primLoop].primFunction= startSlaveList; primParameters[primLoop++].primRevision= R_START_SLAVE_LIST; primIDList[primLoop]= SLAVE_LIST_OP; primParameters[primLoop].primFunction= slaveListOp; primParameters[primLoop++].primRevision= R_SLAVE_LIST_OP; primIDList[primLoop]= BUILD_STREAM; primParameters[primLoop].primFunction= buildStream; primParameters[primLoop++].primRevision= R_BUILD_STREAM; primIDList[primLoop]= SEND_STREAM; primParameters[primLoop].primFunction= sendStream; primParameters[primLoop++].primRevision= R_SEND_STREAM; primIDList[primLoop]= RW_MODULE_DATA; primParameters[primLoop].primFunction= rwModuleData; primParameters[primLoop++].primRevision= R_RW_MODULE_DATA; primIDList[primLoop]= SEND_CONFIG; primParameters[primLoop].primFunction= sendConfig; primParameters[primLoop++].primRevision= R_SEND_CONFIG; primIDList[primLoop]= DSP_RESET; primParameters[primLoop].primFunction= dspReset; primParameters[primLoop++].primRevision= R_DSP_RESET; primIDList[primLoop]= SET_ROD_MODE; primParameters[primLoop].primFunction= setRodMode; primParameters[primLoop++].primRevision= R_SET_ROD_MODE; primIDList[primLoop]= RW_MODULE_VARIABLE; primParameters[primLoop].primFunction= rwModuleVariable; primParameters[primLoop++].primRevision= R_RW_MODULE_VARIABLE; primIDList[primLoop]= RW_BOC_DATA; primParameters[primLoop].primFunction= rwBocData; primParameters[primLoop++].primRevision= R_RW_BOC_DATA; primIDList[primLoop]= BOC_HISTOGRAM; primParameters[primLoop].primFunction= bocHistogram; primParameters[primLoop++].primRevision= R_BOC_HISTOGRAM; primIDList[primLoop]= WRITE_FLASH; primParameters[primLoop].primFunction= writeFlash; primParameters[primLoop++].primRevision= R_WRITE_FLASH; #endif /* SDSP/MDSP */ return; } /**************************PRIMITIVES COMMON TO ALL DSPS****************************/ /************************************************************************************ * noPrimitive * * synopsis: All elements of the primitive function pointer array, * primParameters[].primFunction are initialized to point here. If the * pointer to the primitive indexed by ID has not been assigned to the * appropriate function in initializePrimParams, this function will be * executed instead of the intended primitive function. * * author: Damon Fasching ************************************************************************************/ INT32 noPrimitive(PrimData *primData) { INT32 returnCode; newError(&returnCode, PRIM_FNCT_PTR_ERROR, FATAL_ERR, "noPrimitive", "Pointer to primitive not initialized. Check initializePrimParams().", __FILE__, __LINE__); return returnCode; } /************************************************************************************ * echo * * synopsis: Echos the primitive into the reply buffer. * * arguments * INOUT primData: structure for passing data to and from primitive functions * defined in primFuncts.h; described in detail in primParams.h * * author: Damon Fasching ************************************************************************************/ INT32 echo(PrimData *primData) { UINT32 counter; for (counter = 0; counter < primData->priBodyLength; ++counter) { *(primData->repBodyPtr + counter) = *(primData->priBodyPtr + counter); } primData->repBodyLength = primData->priBodyLength; return SUCCESS; } /************************************************************************************* * setErrMsgMask * * synopsis: Sets a mask for printing error messages to the text buffer. * * arguments * IN: errMsgMaskIn->errMsgMask: value to set errMsgMask to; * DEFAULT means do not change the value * OUT: errMsgMaskOut->errMsgMask: value of errMsgMask at end of this routine * * author: Tom Meyer * * bugs/modifications: * - Added assignment of primData->repBodyLength dpf * - Used constant FATAL_BIT (already defined in errorCodes.h) in place of * hardwired data in old code "UINT32 nonFatalMask = 0x3fffffff;" dpf * - In the orignal routine an input mask of -1 meant just read and return * the current mask. This depends on the DSPs and the host having the * same representation of negative numbers. In addition, errMsgMask was * a global variable declared in main, declared external and used in * smSendTextBuff.c and declared external and set here. This routine has * been largely rewritten to reflect the following changes (function * comments above changed accordingly): * 1) an input mask of DEFAULT means just read the current mask. * 2) errMsgMask is now a file level variable in smSendTextBuff.c. * It is set and read here via access routines. 5/03/01 dpf * - Moved definition of nonFatalMask to the access routines. 5/03/01 dpf ************************************************************************************/ INT32 setMessageMask(PrimData *primData) { SetMessageMaskIn *msgMaskIn= (SetMessageMaskIn *) primData->priBodyPtr; //dpsf only error buffer for now. if (msgMaskIn->messageMask != DEFAULT) { setErrMask(msgMaskIn->messageMask); } primData->repBodyLength= 0; return SUCCESS; } /************************************************************************************ * pauseList * * synopsis: Causes the pause flag to be set which in turn causes the list * processing state machine to go to PAUSED on the next cycle. Execution * will resume when the RESUME bit in the command register is toggled. * * author: Damon Fasching ************************************************************************************/ INT32 pauseList(PrimData *primData) { setPausedByPrim(); return SUCCESS; } /************************************************************************************ * eventTrapSetup * * synopsis: Sets up the router for DMAs to a slave DSP then sends a primitive list * to the slave containing this primitive so that the slave can set itself * up for DMA with the same parameters as the router. * * arguments * IN: slvBits: Pass on the primitive to the indicated slaves (master DSP). * * numberOfEvents: Number of events to collect; the special value of zero * indicates that routines should collect events indefinitely. * * timeoutInUsec: Timeout for the reply of the slave DSP (master DSP only). * * extRouterSetup: If set, indicates that router is set up using external * rwRegField primitives, and the input parameters should be * simply passed along to the slave DSPs. Note that this also bypasses the * checks upon the router-specific input parameters. * * distribute: Should the router's trap remainders be set up so that the * events are distributed among the slave DSPs? * * releaseFrames: If set, after the last task has finished with an event, * it will release the frames as they are finished. If not * set, the event is freed in a burst at the end. May be useful for * histogramming tasks with large, many-frame events. * * permitBackPressure: Allow the router to apply back-pressure to the EFB if * it overflows. This is disabled during normal ATLAS * running. * * dataMode: If this is set, the router sends raw data over without * regard to event boundaries. * * slink: If set, will trap all events and operate like the slink; * this overrides anything else. * * format: Indicates the format of trapped events: the "error format" * which contains the L1 & BC IDs for the links, or the normal * data format. See xxx * * trapStray: If set, the event manager will send stray events-- events * which do not get processed by a currently running task-- * to a reserve buffer for observation. This applies to error events as * well. If not set, the events are removed. * * iterLimit: The limit in iterations that the event manager will wait * before removing a stray event. Should be kept small. * * trapConfig[2]: Determines the type of event which will be trapped- ROD * specific, TIM specific, ATLAS events, or errors. * * trapExclusionFlag[2]: Does the trap match register trap the indicated event, * or anything but it? * * trapFunction[2]: Determines what will be done with the events which are * trapped. * * trapMatch[2]: The type of ROD, TIM, or ATLAS events to be trapped. * * trapModulus[2]: The modulus of the trapping. If the special modulus * of zero is used, a single event is trapped; the trap * must be reloaded before trapping another event. * * trapRemainder[2]: The remainder of the trapping. Events are trapped when * (event-type counter)%modulus = remainder. * * OUT: errorCode: did the primitive succeed or fail * * author: Damon Fasching * * modifications/bugs: * - Added initialization of the event manager (initEventManager). 10.05.02 dpsf * - Removed frameSize and framesPerBlock as inputs, since we've decided * that they should be fixed now (their variability is causing too much * trouble both in the router VHDL code & in the DSP code now that trapping is * event-based). The router retains the possibility for data-based trapping * (ie. no specified word boundaries for event fragment beginnings & no * guarantee from router that when it gets a small event it will transfer it * immediately)-- this may be used in re-sychronization/ error counting later. * If it interferes with the new eventManager, some modifications may be * necessary. 17.05.02 dpsf * - Put both versions of the function in primFuncts.c for easier * maintenance; added in the new router registers (event trap types, * prescale and modulus values, etc.) 24.05.01 dpsf * - Moved call to setupDmaParams into initEventManager. 10.06.01 dpsf * - Router registers are now set up in a separate routine, setupRouter * (re-used elsewhere). The trap parameters are checked for validity * there. Error events have their own separate format, which can also * be used by the other trapped event types (ATLAS, TIM, ROD, or all * S-Link data); this is indicated by the format parameter. 28.06.02 dpsf * - The routine now loops internally, sending a copy of itself on to any * slaves which have the corresponding bit in slvBits set (replaces * slaveNumber). 09.07.02 dpsf * - Replaced call to startUserTimer with a measurement of the time at * init-- the user timer is now started in main() with the maximal period * and left running. Successive calls to TIMER_getCount will subtract * correctly. 09.01.03 dpsf ************************************************************************************/ INT32 eventTrapSetup(PrimData *primData) { INT32 returnCode= SUCCESS, errorCode; EventTrapSetupIn *eventTrapSetupIn= (EventTrapSetupIn *) primData->priBodyPtr; EventTrapSetupOut *eventTrapSetupOut= (EventTrapSetupOut *) primData->repBodyPtr; UINT32 permitBackPressure, dataMode, sLink, format, i; RouterTrapParams traps[2]; UINT32 iterLimit; #if defined(I_AM_MASTER_DSP) static UINT8 slvBits, slvNum, init= TRUE, waiting; static UINT32 timeoutInTmrUnits, timerCnt, initTime, distrib; UINT32 extRouterSetup, distribRemainder= 0, distribProblem= FALSE; UINT32 listIndx, timeoutInUsec, timeout; UINT32 msgPtr, msgLength, lastMsg; INT32 slaveStat; EventTrapSetupOut *eventTrapSetupReply; #elif defined(I_AM_SLAVE_DSP) UINT32 numberOfEvents, releaseFrames, trapStray; #endif /* Write reply data structure params and set output reply data length */ primData->repBodyLength= SIZEOF(EventTrapSetupOut); permitBackPressure= eventTrapSetupIn->permitBackPressure; dataMode= eventTrapSetupIn->dataMode; sLink= eventTrapSetupIn->sLink; format= eventTrapSetupIn->format; iterLimit= eventTrapSetupIn->iterLimit; for (i=0; i<2; ++i) { traps[i].config= eventTrapSetupIn->trapConfig[i]; traps[i].exclusionFlag= eventTrapSetupIn->trapExclusionFlag[i]; traps[i].function= eventTrapSetupIn->trapFunction[i]; traps[i].match= eventTrapSetupIn->trapMatch[i]; traps[i].modulus= eventTrapSetupIn->trapModulus[i]; traps[i].remainder= eventTrapSetupIn->trapRemainder[i]; } #if defined(I_AM_MASTER_DSP) if (init) { slvBits= eventTrapSetupIn->slvBits; if (slvBits == 0) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "eventTrapSetup", " Must configure at least one slave DSP.\n", __FILE__, __LINE__); return returnCode; } init= waiting= FALSE; /* otherwise, begin processing the slaves */ } /****************************** initialization ******************************/ if (!waiting) { /* Initialize these here so there is a reply even if there is an error exit */ eventTrapSetupOut->errorCode= !(SUCCESS); extRouterSetup= eventTrapSetupIn->extRouterSetup; distrib= eventTrapSetupIn->distribute; /* get the first non-zero slave bit */ for (i= 0; i< N_SDSP; ++i) { if (!(slvBits & 1<= 0xffff) { sprintf(genStr,"%s%s","The iteration limit for keeping unprocessed ", "events must be < 0xffff (KEEP_EVENTS=> no limit).\n"); newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "eventTrapSetup", genStr, __FILE__, __LINE__); } if (FATAL(returnCode)) { init= TRUE; return returnCode; } if (!extRouterSetup) { /* Distribute events among available slaves if requested. Note that the modulus should be adjusted accordingly. */ if ((distrib==TRAP_DISTRIB_PRIMARY)||(distrib==TRAP_DISTRIB_BOTH)) { traps[0].remainder= distribRemainder; } if ((distrib==TRAP_DISTRIB_SECONDARY)||(distrib==TRAP_DISTRIB_BOTH)) { traps[1].remainder= distribRemainder; } distribRemainder++; errorCode= setupRouter(slvNum, permitBackPressure, dataMode, sLink, format, traps); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "eventTrapSetup", "setupRouter", __FILE__, __LINE__); } } if (FATAL(returnCode)) { init= TRUE; return returnCode; } /* no errors; pass list to slave */ timeoutInUsec = eventTrapSetupIn->timeoutInUsec; timeoutInTmrUnits = timeoutInUsec * (DSPClockInMHz()/4); /* SLAVE: send primitive list, a single primitive to set up data trap parameters, to the slave, via the inter-DSP primitive list */ errorCode= addMessage(INTR_DSP_LIST_SND, PRM, EVENT_TRAP_SETUP, R_EVENT_TRAP_SETUP,SIZEOF(EventTrapSetupIn), (void *) eventTrapSetupIn); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "eventTrapSetup", "addMessage", __FILE__, __LINE__); if (FATAL(returnCode)) { init= TRUE; return returnCode; } } addListWrapper(INTR_DSP_LIST_SND, PRM, 0); initiateListSendSM(slvNum); initTime= TIMER_getCount(timer1); /* must allow the CPU to loop to find and process the reply */ waiting = TRUE; return REPEAT_PRIMITIVE; } /* initializing, ie. not waiting for slave's reply */ /************************** wait for slave's reply **************************/ else { timeout = FALSE; if (SDSP_IDSP_LIST_BUSY) { if ((timerCnt= TIMER_getCount(timer1) -initTime) > timeoutInTmrUnits) { newError(&returnCode, TIMEOUT_ERR, FATAL_ERR, "eventTrapSetup", "Timer timed out.", __FILE__, __LINE__); timeout= TRUE; waiting= FALSE; } } else {waiting= FALSE; } if (waiting) { return REPEAT_PRIMITIVE; } if (FATAL(returnCode)) { init= TRUE; return returnCode; } if (!replyDataAvail()) { newError(&returnCode, SLV_REPLY_ERR, FATAL_ERR, "eventTrapSetup", "Expected slave reply, none received. \n", __FILE__, __LINE__); } else { errorCode= readListWrapper(INTR_DSP_LIST_SND, REP, &listIndx); if (errorCode < 0) { addError(&returnCode, errorCode, "eventTrapSetup", "readListWrapper", __FILE__, __LINE__); } } if (FATAL(returnCode)) { init= TRUE; return returnCode; } getReplyMsg(INTR_DSP_LIST_SND, &msgPtr, &msgLength, &lastMsg); if (!lastMsg) { newError(&returnCode, SLV_REPLY_ERR, FATAL_ERR, "eventTrapSetup", "Too many reply messages.\n", __FILE__, __LINE__); } else if (msgLength != SIZEOF(EventTrapSetupOut)) { newError(&returnCode, SLV_REPLY_ERR, FATAL_ERR, "eventTrapSetup", "Reply message length error.\n", __FILE__, __LINE__); } else { eventTrapSetupReply = (EventTrapSetupOut *)msgPtr; if (eventTrapSetupReply->errorCode != SUCCESS) { newError(&returnCode, SLV_REPLY_ERR, FATAL_ERR, "eventTrapSetup", "Slave reply != SUCCESS.\n", __FILE__, __LINE__); } eventTrapSetupOut->errorCode = eventTrapSetupReply->errorCode; } /* reply retrieval if-else block */ if (FATAL(returnCode)) { init= TRUE; return returnCode; } else { sprintf(genStr,"%s%s%d%s%d%s","Event trapping setup complete for ", "slave #",slvNum,". (delta t= ",(timerCnt*4)/160, " micro-seconds).\n"); newInformation(__FILE__, __LINE__, genStr); slvBits ^= 1<numberOfEvents; releaseFrames= eventTrapSetupIn->releaseFrames; trapStray= eventTrapSetupIn->trapStray; errorCode= initEventManager(numberOfEvents, releaseFrames, permitBackPressure, dataMode, sLink, format, trapStray, traps); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "eventTrapSetup", "initEventManager", __FILE__, __LINE__); } eventTrapSetupOut->errorCode = returnCode; #endif return returnCode; } /************************************************************************************* * setMemory() synopsis: set DSP memory to input value. Quick alternative to * rwSlaveMemory; can also write to sections of master DSP * memory. DANGEROUS ROUTINE! * * author: Douglas Ferguson ************************************************************************************/ INT32 setMemory(PrimData *primData) { SetMemoryIn *setMemoryIn= (SetMemoryIn *) primData->priBodyPtr; UINT32 *start, size, val; INT32 returnCode; start= setMemoryIn->start; size= setMemoryIn->size; val= setMemoryIn->val; returnCode= setMem(start, size, val); if (returnCode!= SUCCESS) { newError(&returnCode, SET_MEMORY_ERROR, FATAL_ERR, "setMemory", "Problem allocating DMA channel/global register. Fatal \0", __FILE__, __LINE__); return returnCode; } return returnCode; } /************************************************************************************* * copyMemory() synopsis: copy one section of the DSP memory to another. Quick & * convenient alternative to rwSlaveMemory; works on both * types of DSP. DANGEROUS ROUTINE! * * author: Douglas Ferguson ************************************************************************************/ INT32 copyMemory(PrimData *primData) { CopyMemoryIn *copyMemoryIn= (CopyMemoryIn *) primData->priBodyPtr; UINT32 *source, *destination, size; INT32 returnCode; source= copyMemoryIn->source; destination= copyMemoryIn->destination; size= copyMemoryIn->size; returnCode= copyMem(source, destination, size); return returnCode; /* dpsf update copyMem so that whichever direction an overlapping copy is going, it will still work. */ } /************************************************************************************* * memoryTest() synopsis: perform a set of diagnostic memory tests on the selected * section of memory. This routine is DANGEROUS! * * Inputs *start: The starting address of the memory to be tested. * size: The size of the memory to be tested, in words. * repetitions[]: Number of times to repeat each test. * errorsBeforeFail: Number of errors tolerated in a given test before exit. * continueOnError: If set, when an earlier test gives errors, will * continue on to the next test. * * Outputs Error codes via function return value, together with information * messages. * * author: Douglas Ferguson ************************************************************************************/ INT32 memoryTest(PrimData *primData) { /* store last state so that routine returns to proper spot */ static int errStore= SUCCESS, nErrorsStore= 0; static char state= 0, initial= 1, sendMessage= 1; INT32 returnCode; extern struct TXTBUFFER errBuffer; MemoryTestIn *memoryTestIn= (MemoryTestIn *) primData->priBodyPtr; MemoryTestOut *memoryTestOut= (MemoryTestOut *) primData->repBodyPtr; UINT32 *start, *addr, size, repetitions[6], errorsBeforeFail, continueOnError, nReads, dmaFlag; UINT32 floatVal, cbdVal, errVal, err; int i, n, repeat, nErrors; char errStr[100]; returnCode= errStore; primData->repBodyLength= SIZEOF(MemoryTestOut); start= memoryTestIn->start; size= memoryTestIn->size; for (i= 0; i< 6; ++i) repetitions[i]= memoryTestIn->repetitions[i]; /* implicit repetition of 32x for floating 0, 1 test-- see below. */ repetitions[3]*= 32; repetitions[4]*= 32; errorsBeforeFail= memoryTestIn->errorsBeforeFail; continueOnError= memoryTestIn->continueOnError; nReads= memoryTestIn->nReads; dmaFlag= memoryTestIn->dmaFlag; /* If no pending messages in info buffer, send a message to host giving test to be done next, and return. Then wait until the host indicates it has received it (buffer is flushed & goes into idle loop again, ready for new messages). */ if (initial) { initial= 0; sprintf(errStr, "\n\nMemory Test B: starting address: 0x%x, len: 0x%x (w)\n", (UINT32) start, size); newInformation(__FILE__, __LINE__, errStr); } if ((sendMessage)&&(repetitions[state]>0)) { sendMessage= 0; switch(state) { case 0: newInformation(__FILE__, __LINE__, " memoryTest: address test (*addr = addr) \n\0"); break; case 1: newInformation(__FILE__, __LINE__, " memoryTest: checkerboard test 1 (0x55555555 0xAAAAAAAA) \n\0"); break; case 2: newInformation(__FILE__, __LINE__, " memoryTest: checkerboard test 2 (0xAAAAAAAA 0x55555555) \n\0"); break; case 3: newInformation(__FILE__, __LINE__, " memoryTest: floating 0 test \n\0"); break; case 4: newInformation(__FILE__, __LINE__, " memoryTest: floating 1 test \n\0"); break; case 5: newInformation(__FILE__, __LINE__, " memoryTest: random address/value test \n\0"); break; default: break; } /* end switch(state) */ return REPEAT_PRIMITIVE; } /* wait for reception of both buffers used (err buff in case error in last test) */ if ( (!txtBuffSMIdle(INFO_BUFF)) || (!txtBuffSMIdle(ERR_BUFF)) ) { return REPEAT_PRIMITIVE; } /******************************************************************* * The memory tests: * 0) address test: store & read back the addresses stored * inside the corresponding word in memory. * 1) checkerboard test 1: store & read back a bit pattern * of 01010101b-- test for crosstalk. * 2) checkerboard test 2: store & read back a bit pattern * of 10101010b-- test for crosstalk. * 3) floating 0 test: store & read back a bit pattern which * has all 1s except for 1 bit, and float * the 0 across-- test for bad data lines. * 4) floating 1 test: store & read back a bit pattern which * has all 0s except for 1 bit, and float * the 1 across-- test for bad data lines. * 5) random test: store & read back a series of random values * stored inside random addresses, mimicking as * closely as possible real program accesses. * *******************************************************************/ while (state < 6) { for (nErrors= repeat= 0; repeat< repetitions[state]; ++repeat) { if (state == 3) floatVal= 0xFFFFFFFF ^ (1<<(repeat%32)); else if (state == 4) floatVal= 0x0 | (1<<(repeat%32)); if (dmaFlag && ((state==3)||(state==4))) { setMem(start, size, floatVal); } else { for (addr= start, i= 0; i< size; ++i, ++addr) { if (state == 0) { *addr= (UINT32) addr; } else if (state == 1) { if (((UINT32) addr)%8 == 0) *addr= 0x55555555; else *addr= 0xAAAAAAAA; } else if (state == 2) { if (((UINT32) addr)%8 == 0) *addr= 0xAAAAAAAA; else *addr= 0x55555555; } else if (state == 3) { *addr= floatVal; } else if (state == 4) { *addr= floatVal; } } /* set mem */ } for (n= 0; n< nReads; ++n) { /* multiple reads */ for (addr= start, i= 0; i< size; ++i, ++addr) { /* check mem */ err= 0; /* error flag */ if (state == 1) { if (((UINT32) addr)%8 == 0) cbdVal= 0x55555555; else cbdVal= 0xAAAAAAAA; } else if (state == 2) { if (((UINT32) addr)%8 == 0) cbdVal= 0xAAAAAAAA; else cbdVal= 0x55555555; } errVal= *addr; if ((state == 0) && (errVal != (UINT32) addr)) { /* => problems */ err= MEMORY_TEST_ADDR_ERROR; sprintf(errStr, "ADDR: memory failure at 0x%x : val 0x%x \n\0", (UINT32) addr, errVal); } else if ((state == 1) && (errVal != cbdVal)) { err= MEMORY_TEST_CB1_ERROR; sprintf(errStr, "Ckbd 1: memory failure at 0x%x : val 0x%x \n\0", (UINT32) addr, errVal); } else if ((state == 2) && (errVal != cbdVal)) { err= MEMORY_TEST_CB2_ERROR; sprintf(errStr, "Ckbd 2: memory failure at 0x%x : val 0x%x \n\0", (UINT32) addr, errVal); } else if ((state == 3) && (errVal != floatVal)) { err= MEMORY_TEST_FLT0_ERROR; sprintf(errStr, "Flt 0: memory failure at 0x%x : val 0x%x \n\0", (UINT32) addr, errVal); } else if ((state == 4) && (errVal != floatVal)) { err= MEMORY_TEST_FLT1_ERROR; sprintf(errStr, "Flt 1: memory failure at 0x%x : val 0x%x \n\0", (UINT32) addr, errVal); } /* MEMORY_TEST_RAND_ERROR */ if (err) { ++nErrors; ++nErrorsStore; if (nErrors == 1) { newError(&returnCode, err, ERROR_0, "memoryTest", errStr, __FILE__, __LINE__); } else { txtAddBufferEntry(&errBuffer, __FILE__, __LINE__, errStr); MERGE_ERROR(returnCode, err); } if (nErrors > errorsBeforeFail) { txtAddBufferEntry(&errBuffer, __FILE__, __LINE__, "error limit exceeeded-- exiting test \n\0"); MERGE_ERROR(returnCode, FATAL_ERR); errStore= returnCode; ++state; sendMessage= 1; return REPEAT_PRIMITIVE; } } /* error */ } /* check mem */ } /* multiple reads */ } /* repetitions loop*/ if ((returnCode != SUCCESS) && (!continueOnError)) { /* return with error */ memoryTestOut->returnCode= returnCode; state= 0; errStore= SUCCESS; nErrorsStore= 0; sendMessage= 1; initial= 1; return returnCode; } else { ++state; errStore= returnCode; sendMessage= 1; return REPEAT_PRIMITIVE; /* prepare for next test */ } } /* state while loop */ memoryTestOut->returnCode= returnCode; state= 0; errStore= SUCCESS; nErrorsStore= 0; sendMessage= 1; /* reset state */ initial= 1; return returnCode; } /************************************************************************************ * setLed * * synopsis: Sets or resets the yellow LED. * * arguments * IN: ledState - set it or reset it * toggle - if set, ignores ledState and toggles the LED. * * author: Tom Meyer * * - Added a switch for the production ROD. 5/12/01 dpf * - Took out the PROTO_ROD & PRODXN_ROD compiler switches; the prototype * RODs are not used any more. The old code is stored in obsolete.c. * Added code to set the state of the yellow LED. 01.05.02 dpsf * - Made into a common primitive (was slave), since both types of DSP * have an available LED; minor code differences. 14.05.02 dpsf * - Encapsulated code into a function so that other routines have simple * call to set an LED. 24.02.03 dpsf ************************************************************************************/ INT32 setLed(PrimData *primData) { /* UINT32 serPcrAddrPort1= 0x01900024, val; */ SetLedIn *setLedIn= (SetLedIn *) primData->priBodyPtr; setLedState(setLedIn->ledNum, setLedIn->ledState); return SUCCESS; } /************************************************************************************ * flashLed * * synopsis: Flashes the yellow LED at a settable period for a settable number of * times. There is no reply data since the LED is visible. * * arguments * IN: period - flash period in milliseconds * numTimes - number of times to flash the LED * * author: Tom Meyer * * modifications/bugs: * - Removed hardwired constants as in original setLed() (end of file) 4/15/01 dpf * - Timer channel was not being released at exit of routine. After * calling this primitive twice, it would stop working because both * timer channels were busy. 4/15/01 dpf * - Added a switch for the production ROD. 5/12/01 dpf * - Replaced the constant 41750000 with DSClockInMHz()*1000000/4. The * timer frequency is 1/4 the DSP clock frequency, i.e. 40 MHz. 5/15/01 dpf * - Took out the PROTO_ROD & PRODXN_ROD compiler switches; the prototype * RODs are not used any more. Rewrote code- old (broken) code is * stored in obsolete.c. 01.05.02 dpsf * - ticksPerHalfCycle was being computed incorrectly for period= 1: * the integer division caused it to be set to 0. fixed. 13.05.02 dpsf * - Made into a common primitive (was slave), since both types of DSP * have an available LED; minor code differences. Period is now in * milliseconds (was seconds). 14.05.02 dpsf * - Replaced call to startUserTimer with a measurement of the time at * init-- the user timer is now started in main() with the maximal period * and left running. Successive calls to TIMER_getCount will subtract * correctly. 09.01.03 dpsf * - Encapsulated code into a function so that other routines have simple * call to set an LED. 24.02.03 dpsf ************************************************************************************/ INT32 flashLed(PrimData *primData) { FlashLedIn *flashLedIn= (FlashLedIn *) primData->priBodyPtr; UINT32 period, times, i, ticksPerHalfCycle, initTime; INT32 returnCode= SUCCESS; period= flashLedIn->period; times= flashLedIn->numTimes; /* The timer frequency is 1/4 the DSP clock frequency */ ticksPerHalfCycle= period * ( (DSPClockInMHz()*1000) / 4 )/2; /* Do the loop, turning LED on then off for a half period each */ for (i=0; iledNum, ON); while (delta_t(initTime) < ticksPerHalfCycle); initTime= TIMER_getCount(timer1); setLedState(flashLedIn->ledNum, OFF); while ((TIMER_getCount(timer1) -initTime) < ticksPerHalfCycle); } return returnCode; } /************************************************************************************ * sendData * * synopsis: Sends the requested data back to the VME host. This routine differs * from the rwSlaveMemory routine in that a) the data can be on the master DSP as * well, and (more importantly) b) the data is of a specific type & is stored in a * specific location, but can be of indeterminate size. The routine returns the * data through a pointer to the data start, and its length. The VME host then * initiates a DMA data transfer. * * arguments * IN: dataType: The type of data to be transferred. Current implemented * types are EVENT_DATA and HISTOGRAM_DATA (anticipated: * OCCUPANCY_DATA, FIT_DATA). * * repBufferFlag: If set, the routine will attempt to fit the data into * the reply buffer. The reply data is unstructured. * * timeout: If the type is EVENT_DATA, and sendData is issued when * there are no events in the queue, will wait for the * specified period (in milliseconds) before timing out. * * OUT: dataPtr: Pointer to the start of the requested data. * * dataLength: The length in words of the requested data. * * author: Douglas Ferguson ************************************************************************************/ INT32 sendData(PrimData *primData) { INT32 returnCode= SUCCESS, status; SendDataIn *sdi= (SendDataIn *) primData->priBodyPtr; SendDataOut *sdo= (SendDataOut *) primData->repBodyPtr; TaskOutput *taskOut; UINT32 dataType, *endPtr, wSize, repBufferFlag, timeout; dataType= sdi->dataType; repBufferFlag= sdi->repBufferFlag; timeout= sdi->timeout; /* reserve default reply space (filled in later): */ status= addReplyData(primData, &sdo, SIZEOF(struct SEND_DATA_OUT)); if (status != SUCCESS) addErrFatalM(&returnCode, status, "sendData", "addPrimData"); #if defined(I_AM_MASTER_DSP) if ( ((dataType == MIRROR_DATA) && (currentTask(MIRROR_TASK))) ) { newInformation(__FILE__, __LINE__, "Warning: The task has not yet completed.\n"); } if (dataType == MIRROR_DATA) { taskOut= getTaskData(MIRROR_TASK); if (taskOut== NULL) { newError(&returnCode, TASK_NOTRUN_ERROR, FATAL_ERR, "sendData", "The mirror task has not been run yet!", __FILE__, __LINE__); return returnCode; } } #elif defined(I_AM_SLAVE_DSP) if ( ((dataType == EVENT_DATA) && (currentTask(TRAP_TASK))) ||((dataType == HISTOGRAM_DATA) && (currentTask(HISTOGRAM_TASK))) ||((dataType == OCCUPANCY_DATA) && (currentTask(OCCUPANCY_TASK))) ) { newInformation(__FILE__, __LINE__, "Warning: The task has not yet completed.\n"); } if (dataType == EVENT_DATA) { taskOut= getTaskData(TRAP_TASK); if (taskOut== NULL) { newError(&returnCode, TASK_NOTRUN_ERROR, FATAL_ERR, "sendData", "The event trapping task has not been run yet!", __FILE__, __LINE__); return returnCode; } sdo->dataPtr= taskOut->genTaskOut.dataPtr; sdo->dataLength= taskOut->genTaskOut.dataLength; } else if ((dataType == HISTOGRAM_DATA)||(dataType == OCCUPANCY_DATA)) { if (!histoCtrl.histogramsAreSetup) { newError(&returnCode, TASK_NOTRUN_ERROR, FATAL_ERR, "sendData", "Histogramming has not been set up yet!", __FILE__, __LINE__); return returnCode; } sdo->dataPtr= histoCtrl.base; sdo->dataLength= histoCtrl.size; } else if (dataType == BIN_DATA) { if (!histoCtrl.histogramsAreSetup) { newError(&returnCode, TASK_NOTRUN_ERROR, FATAL_ERR, "sendData", "Histogramming has not been set up yet!", __FILE__, __LINE__); return returnCode; } sdo->dataPtr= &binCtr; sdo->dataLength= SIZEOF(binCtr); } else if (dataType == FIT_DATA) { } #endif if (repBufferFlag) { status= addReplyData(primData, sdo->dataPtr, sdo->dataLength); if (status != SUCCESS) addErrFatalM(&returnCode, status, "sendData", "addReplyData"); sdo->dataPtr= (UINT32 *) (DEFAULT); /* DEFAULT => reply buffer */ } return returnCode; } /************************************************************************************ * moduleMask * * synopsis: Sets the masking bits for the output control links & the input data * lines for a module; these determine the fanouts of the two serial * streams to the detector electronics, and set the formatter links on which the * DSPs will expect to see a given module's data. Like eventTrapSetup, this * routine is meant to coordinate between the ROD electronics. It should be sent * to the master DSP; the master DSP will then send a version on to the slave DSPs, * if desired. Note that the MDSP & SDSPs have different input parameters. * * arguments (MDSP) * IN: moduleNum: the index inside the moduleMaskData array which will store * the data. * port: The serial port mask to set when the routine is called. Can * be either of the two ports, or both. * useStructSet: If this flag is set, the moduleNum, cmdLine and dataLine[] * inputs will be ignored, and the (init) module configuration * structure will be used to configure the masks. * passOn: If true the MDSP will pass a copy of the primitive on to * the indicated slave DSPs. If set this is the only thing * which will happen. * slvBits: Bitfield indicating which slave DSPs receive the primitive. * cmdLine: The command line used by this module. * fmtLink[2]: The data lines used by this module; unused data lines are * indicated with DATA_LINK_OFF (= 0xff). * * cfg: If set, the primitive will actually set masks using the * parameters which follow; it will ignore all the parameters * above except port. * modMask[2]: A convienent bitfield which indicates which modules * contribute to this mask set. * maskType: Indicates how to set the masks. Possible values are defined * in rodConfiguration.h (also for next 2 parameters). * storage: Indicates the operation to be applied to the mask set. * maskSet: The mask set to use/modify. * * arguments (SDSP) * IN: ModuleMaskData moduleMaskData[N_TOTMODULES]: The data to transfer * into the SDSP's internal array. * * author: Douglas Ferguson ************************************************************************************/ INT32 moduleMask(PrimData *primData) { INT32 returnCode= SUCCESS, status; ModuleMaskIn *moduleMaskIn= (ModuleMaskIn *) primData->priBodyPtr; #if defined(I_AM_MASTER_DSP) UINT8 cfgSet= PHYSICS_CONFIG_SET, si, sf, mod, i, port, cmdLine; UINT8 dataLine[4]= {DATA_LINK_OFF, DATA_LINK_OFF, DATA_LINK_OFF, DATA_LINK_OFF}; static UINT8 slvBits, slv, init= TRUE, waiting= FALSE; static UINT32 timeoutCnt, initTime; UINT32 mask[2], mt; UINT8 timeout; INT32 slaveStat; #endif #if defined(I_AM_MASTER_DSP) port= moduleMaskIn->port; mask[0]= moduleMaskIn->modMask[0]; mask[1]= moduleMaskIn->modMask[1]; if (moduleMaskIn->passOn) { if (init) { //note that init is actually a tri-state, to avoid reloading the slvBits //when passing on to multiple SDSPs. if (init == TRUE) slvBits= moduleMaskIn->slvBits; /* get the first non-zero slave bit */ for (slv= N_SDSP, i= 0; i< N_SDSP; ++i) { if (!(slvBits & 1< timeoutCnt) { newError(&returnCode, TIMEOUT_ERR, FATAL_ERR, "moduleMask", "Timer timed out.", __FILE__, __LINE__); timeout= TRUE; waiting= FALSE; } } else {waiting= FALSE; } if (waiting) {return REPEAT_PRIMITIVE; } else if (timeout) {init= TRUE; return returnCode; } redLed_off; yellowLed_on; redLed_on; yellowLed_off; //dpsf Later: check for problems executing prim on SDSP & change rep list //header so that errors are handled in DAQ friendly way: Every prim list //generates a reply list, and the header indicates the #of successfully //executed primitives, and also gives the return code of last executed prim. slvBits^= 1<cfg) { //Configure masks. /* No checks needed- inputs to setLinkMasks will be ignored if incorrect. Note that this routine has the capability of configuring all the mask sets, including the reserved internal ones; this feature is a convenience and should be used with care, since the internal routines may therefore be disrupted by it. The intent is to allow easy re-configuration of all the mask sets if needed after switching the ROD mode. */ if (moduleMaskIn->maskSet == MASK_SET_ALL) {si= 0; sf= N_MASK_SETS -1; } else {si= moduleMaskIn->maskSet; sf= si +1; } for (cfgSet=si; cfgSetstorage == UPDATE_MASK) { for (mod=0; mod= 32) && (!((mask[1]) & (1<<(mod-32)))) ) continue; sprintf(genStr, "mod= %d.\n", mod); newInformation(__FILE__, __LINE__, genStr); setLinkMasks(mod, port, moduleMaskIn->maskType, moduleMaskIn->storage, cfgSet); } } //Only UPDATE_MASK incrementally updates the masks, all other modes //manipulate the masks in one go (so no loop needed). else { setLinkMasks(mod, port, moduleMaskIn->maskType, moduleMaskIn->storage, cfgSet); } } } else { //Load masks. if (moduleMaskIn->useStructSet) { for (mod=0; modmoduleNum; cmdLine= moduleMaskIn->cmdLine; #if defined(SCT_ROD) for (i=0; i<2; ++i) dataLine[i]= moduleMaskIn->dataLine[i]; #elif defined(PIXEL_ROD) for (i=0; i<4; ++i) dataLine[i]= moduleMaskIn->dataLine[i]; #endif status= setMaskConfig(mod, cmdLine, dataLine); if (status != SUCCESS) { addError(&returnCode, status, "moduleMask", "setMaskConfig", __FILE__, __LINE__); return returnCode; } /* Update the INIT mask configuration set. */ mt= (DATA_LINK_PLAY) +(COMMAND_LINK_ON) +(LINK_CFG_ON); setLinkMasks(mod, port, mt, UPDATE_MASK, MASK_SET_INIT); } } //Mask loading #elif defined(I_AM_SLAVE_DSP) copyMem((UINT32 *) moduleMaskIn, (UINT32 *) moduleMaskData, SIZEOF(moduleMaskData)); maskDataFlag= TRUE; #endif return returnCode; } #if defined(I_AM_MASTER_DSP) extern struct MasterHistoCtrl hc; #pragma DATA_SECTION(timeTest3, "idata"); #pragma DATA_SECTION(timeTest4, "idata"); struct TimeTest { UINT32 marker; UINT32 i; UINT32 initCnt; UINT32 finalCnt; } timeTest3, timeTest4; #define SET_TRIGGER_CMD_ID 0xfe #define HCTRL_PROCESSING_TIMEOUT 0x02800000 /* ~ 1 s */ #endif /************************************************************************************ * setTrigger ************************************************************************************/ INT32 setTrigger(PrimData *primData) { INT32 returnCode= SUCCESS; SetTriggerIn *setTriggerIn= (SetTriggerIn *) primData->priBodyPtr; #if defined(I_AM_MASTER_DSP) UINT8 slv, timeOut; UINT32 i, timer0, delta_microSec; #elif defined(I_AM_SLAVE_DSP) #endif #if defined(I_AM_SLAVE_DSP) histoCtrl.currentBin= setTriggerIn->bin; histoCtrl.histogramSet= setTriggerIn->set; setHistoModuleBase(FALSE /* init */, setTriggerIn->bin); #endif return returnCode; } /************************************************************************************ * startTask * * synopsis: Begin a task on the target DSP. Tasks are run once during each * iteration of the main program loop. * * arguments * IN: taskType: The type of task to be started. See primParams.h and * taskManager.c,.h for details. * * taskRevison: The revison number of the task. * * priority: The priority of the task. The task manager runs tasks * in order of the priority they have on the list. * * completionFlag: If set, the task manager will send a message out when * a task completes. * * taskStruct: Contains the input data for the task. * * author: Douglas Ferguson ************************************************************************************/ INT32 startTask(PrimData *primData) { INT32 returnCode= SUCCESS, status; StartTaskIn *startTaskIn= (StartTaskIn *) primData->priBodyPtr; UINT32 taskType, taskRevision, priority, completionFlag, offset= 0; TaskInput taskStruct; ScanControl *scan; taskType= startTaskIn->taskType; taskRevision= startTaskIn->taskRevision; priority= startTaskIn->priority; completionFlag= startTaskIn->completionFlag; taskStruct= startTaskIn->taskStruct; scan= (ScanControl *) &taskStruct; /* The histogram control task is passed two pointers to the range lists; these can be set to the value DEFAULT ==> in the primitive list (right after the task structure). If so, calculate the actual pointers' positions and substitute these in the pointers. The task cannot do this since it only has access to the local copy of its task structure, and not to the primitive list. */ #if defined(I_AM_MASTER_DSP) if (taskType == HISTOGRAM_CTRL_TASK) { if ( (!scan->general.uniformPoints[0]) &&(scan->general.dataPtr[0] == (MDAT32 *) DEFAULT) ){ scan->general.dataPtr[0]= ((MDAT32 *) &startTaskIn->taskStruct) +SIZEOF(TaskInput); offset= scan->general.nBins[0]; } if ( (!scan->general.uniformPoints[1]) &&(scan->general.dataPtr[1] == (MDAT32 *) DEFAULT) ){ scan->general.dataPtr[1]= ((MDAT32 *) &startTaskIn->taskStruct) +SIZEOF(TaskInput) +offset; } } //Histogram control task #endif status= insertTask(taskType, taskRevision, priority, completionFlag, &taskStruct); if (status != SUCCESS) { addError(&returnCode, status, "startTask", "insertTask", __FILE__, __LINE__); } return returnCode; } /************************************************************************************ * taskOperation * * synopsis: Performs a suite of operations upon a task. Tasks may be stopped, * paused, resumed (from a pause), queried. * * arguments * IN: taskType: The type of task to be started. See primParams.h and * taskManager.c,.h for details. * * author: Douglas Ferguson ************************************************************************************/ INT32 taskOperation(PrimData *primData) { INT32 returnCode= SUCCESS, errorCode; TaskOperationIn *taskOperationIn= (TaskOperationIn *) primData->priBodyPtr; UINT32 taskType, taskOperation, data; UINT32 nibbleVal, requested= 1; /* requested=1 => give message nv= 0xf => stopTask prim */ taskType= taskOperationIn->taskType; taskOperation= taskOperationIn->taskOperation; data= taskOperationIn->data; /* stopping a task causes its internal variables to be re-initialized. The output data from the task (if any) is not touched; it will be valid until the next time the task completes or is queried. Resetting a task is equivalent to stopping and then re-starting it. */ if (taskOperation == TASK_STOP) {nibbleVal= TASK_FORCED; } else if (taskOperation == TASK_PAUSE) {nibbleVal= TASK_PAUSED; } else if (taskOperation == TASK_RESUME) { /* nV set to previous value */ } /* query a task: this causes a task to dump relevant variables into the task operations queryData output. This is meant to be a very quick method of seeing how far along a task is to completion (or how much data it has gathered for those which cycle until stopped). For now this is unstructured data. */ else if (taskOperation == TASK_QUERY) { /* doesn't matter */ } else if (taskOperation == TASK_RESET) {nibbleVal= TASK_INIT; } /* Change priority of a currently running task */ else if (taskOperation == TASK_SETPRIORITY) { /* doesn't matter */ } errorCode= taskOp(taskType, nibbleVal, requested, taskOperation); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "taskOperation", "taskOp", __FILE__, __LINE__); } return returnCode; } /************************************************************************************ * setBin * * synopsis: Sets the current bin # for the DSP. * * author: Douglas Ferguson ************************************************************************************/ INT32 setBin(PrimData *primData) { INT32 returnCode= SUCCESS; SetBinIn *setBinIn= (SetBinIn *) primData->priBodyPtr; #if defined(I_AM_MASTER_DSP) UINT32 sdsp; for (sdsp= 0; sdsp < N_SDSP; ++sdsp) { if (!(setBinIn->slvBits & (1<bin<bin; #endif return returnCode; } /************************************************************************************ * writeBuffer * * synopsis: Temporary test routine for DAQ: writes to chosen text buffer. * * author: Douglas Ferguson ************************************************************************************/ INT32 writeBuffer(PrimData *primData) { WriteBufferIn *writeBufferIn= (WriteBufferIn *) primData->priBodyPtr; char buffer; INT32 returnCode; buffer= (char) writeBufferIn->buffer; if (buffer==0) { newError(&returnCode, PRIM_PARAMETER_ERROR, ERROR_0, "writeBuffer", writeBufferIn->string, __FILE__, __LINE__); } else if (buffer==1) {newInformation(__FILE__, __LINE__, writeBufferIn->string); } else if (buffer==2) {newDiagnostic (__FILE__, __LINE__, writeBufferIn->string); } #ifdef I_AM_MASTER_DSP if (buffer==3) {newXfer(__FILE__, __LINE__, writeBufferIn->string); } #endif return SUCCESS; }