/************************************************************************************ * taskManager.c * * synopsis: This file contains routines which organize tasks, which are run in a * list on each iteration through the main polling loop. They manage a * variety of tasks related to event-trapping and analysis on the slave DSPs, and * monitoring functions on the master DSP. If a task gathers data, it will not * send the data onward, but rather accumulate it in an internal list for a * primitive to process and output. The difference between tasks and primitives is * that tasks run in parallel, in the background, while a primitive list calls * primitives sequentially. If a primitive in the list needs repeating it returns * REPEAT_PRIMITIVE to execPrim(). This allows primitives to continue operating, * but no other primitives can run meanwhile. The task manager calls each task on * the task list in insertion order, so tasks run in "parallel". If a primitive * list is handed to the DSP it will execute normally with the tasks running in * the background beside it. Resource conflicts must be determined & handled by * the operator. * * nyi refinements: a way for tasks to automatically pause themselves while a * list is running (needed? task-op: pause is there), & for tasks * to pause a list. * * in this file: setTaskState, getTaskState, initTaskManager, insertTask, taskOp, * currentTask, getTaskData, taskManager, noTask, * * related files: * masterTasks.c: Contains the master DSP tasks. * slaveTasks.c: Contains the slave DSP tasks. * primFuncts.c: Contains the start & task operation primitives. * 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. The task function input and * output structures are defined here (for startTask & taskOperation). * * Douglas Ferguson, UW Madison (510) 486-5230 dpferguson@lbl.gov ************************************************************************************/ #include #include #include #include #include #include #include "resources.h" #include "taskManager.h" #include "comRegDfns.h" extern char genStr[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ #if defined(I_AM_SLAVE_DSP) extern far struct EvtMgrCtrl evtMgrCtrl; extern far struct EventQueue eventQueue; #endif #pragma CODE_SECTION(setTaskState, "xcode"); #pragma CODE_SECTION(getTaskState, "xcode"); #pragma CODE_SECTION(initTaskManager, "xcode"); #pragma CODE_SECTION(insertTask, "xcode"); #pragma CODE_SECTION(taskOp, "xcode"); #pragma CODE_SECTION(currentTask, "xcode"); #pragma CODE_SECTION(getTaskData, "xcode"); #pragma CODE_SECTION(noTask, "xcode"); #pragma CODE_SECTION(taskManager, "icode"); /* file scope variables */ #pragma DATA_SECTION(taskMgrCtrl, "idata"); TaskMgrCtrl taskMgrCtrl, *taskMgrCtrlPtr; TaskList taskList; /* task output structures array */ TaskOutput taskOut[MAX_NUM_TASKS]; /* file level routines */ INT32 noTask(TaskInput *, TaskOutput *, UINT32); /************************************************************************************ * set/getTaskState * * synopsis: setTaskState sets the appropriate nibble in the task state register * to the input state, getTaskState retrieves the state for a given * task. * ************************************************************************************/ void setTaskState(UINT8 taskType, UINT8 state) { UINT8 nibble; nibble= taskType -TASK_BASE; ASGN_RFLD(TASK_STATE_REG, nibble*4, 4, state); } UINT8 getTaskState(UINT8 taskType) { UINT8 nibble; nibble= taskType -TASK_BASE; return (UINT8) GET_RFLD(TASK_STATE_REG, nibble*4, 4); } /************************************************************************************ * initTaskManager * * synopsis: Initializes all the variables & structures associated with * the task manager. * * author: Douglas Ferguson ************************************************************************************/ INT32 initTaskManager() { INT32 returnCode= SUCCESS; int i; taskMgrCtrlPtr= &taskMgrCtrl; taskMgrCtrl.taskIterations= 0; taskList.nTasks= 0; setMem((UINT32 *) &taskMgrCtrl, SIZEOF(TaskMgrCtrl), 0); for (i=0; i0xff)||(priority==0)) { newError(&returnCode, TASK_PRIORITY_MAX_ERROR, FATAL_ERR, "insertTask", "Priority must range between 0 and 255. \n", __FILE__, __LINE__); return returnCode; } /* check whether the task is already running, or there is another task running at this priority level. */ for (i=0; i7)) { /* (nibble>7) ==> protect the task reg (see below) */ newError(&returnCode, TASK_NONEXISTANT_ERROR, FATAL_ERR, "insertTask", "This task type does not exist on this type of DSP!", __FILE__, __LINE__); return returnCode; } /* check to see that the task's revision number is good. */ #if defined(I_AM_MASTER_DSP) if ( ( (taskType==HISTOGRAM_CTRL_TASK) &&(taskRevision!=R_HISTOGRAM_CTRL_TASK)) ||((taskType==MIRROR_TASK) &&(taskRevision!=R_MIRROR_TASK)) ||((taskType==TRAP_REQ_TASK) &&(taskRevision!=R_TRAP_REQ_TASK)) ) {revisionErr= 1; } #elif defined(I_AM_SLAVE_DSP) if ( ((taskType==HISTOGRAM_TASK) &&(taskRevision!=R_HISTOGRAM_TASK)) ||((taskType==TRAP_TASK) &&(taskRevision!=R_TRAP_TASK)) ||((taskType==ERROR_TASK) &&(taskRevision!=R_ERROR_TASK)) ||((taskType==OCCUPANCY_TASK) &&(taskRevision!=R_OCCUPANCY_TASK)) ||((taskType==RESYNCH_TASK) &&(taskRevision!=R_RESYNCH_TASK)) ) {revisionErr= 1; } #endif if (revisionErr) { newError(&returnCode, TASK_REVISION_ERROR, FATAL_ERR, "insertTask", "The requested task's DAQ version number is wrong.", __FILE__, __LINE__); return returnCode; } else { /* all ok, insert task on list. */ strcat(genStr, "task started on DSP.\n"); newInformation(__FILE__, __LINE__, genStr); //taskMgrCtrl.runningTaskReg &= ~(0xf<<(nibble*4)); //taskMgrCtrl.runningTaskReg |= (TASK_INIT<<(nibble*4)); setTaskState(taskType, TASK_INIT); i= taskList.nTasks; taskList.taskData[i].taskType= taskType; taskList.taskData[i].taskRevision= taskRevision; taskList.taskData[i].priority= priority; taskList.taskData[i].completionFlag= completionFlag; taskList.taskData[i].state= TASK_INIT; copyMem((UINT32 *) taskStruct, (UINT32 *) &taskList.taskData[i].taskStruct, SIZEOF(TaskInput)); #if defined(I_AM_MASTER_DSP) if (taskType==HISTOGRAM_CTRL_TASK) {taskFxn= histoCtrlTask; } else if (taskType==MIRROR_TASK) {taskFxn= mirrorTask; } else if (taskType==TRAP_REQ_TASK) {taskFxn= trapReqTask; } trapFxn= 0; #elif defined(I_AM_SLAVE_DSP) /* if (taskType==HISTOGRAM_TASK) {taskFxn= histogramTask; } else if (taskType==TRAP_TASK) {taskFxn= trapTask; } else if (taskType==ERROR_TASK) {taskFxn= errorTask; } else if (taskType==OCCUPANCY_TASK) {taskFxn= occupancyTask; } else if (taskType==RESYNCH_TASK) {taskFxn= resynchTask; } */ //dpsf xxx if (taskType==HISTOGRAM_TASK) {taskFxn= histogramTask; trapFxn= TRAP_FXN_HISTOGRAM; } else if (taskType==TRAP_TASK) {taskFxn= trapTask; trapFxn= TRAP_FXN_TRAP; } else if (taskType==ERROR_TASK) {taskFxn= errorTask; trapFxn= TRAP_FXN_OCCUPANCY; } else if (taskType==OCCUPANCY_TASK) {taskFxn= occupancyTask; trapFxn= TRAP_FXN_ERRORCNT; } else if (taskType==RESYNCH_TASK) {taskFxn= resynchTask; trapFxn= TRAP_FXN_RESYNCH; } #endif taskList.taskData[i].taskFunction= taskFxn; taskList.taskData[i].trapFxn= trapFxn; //dpsf xxx ++taskList.nTasks; ASGN_RFLD(STATUS_REG_0, SR_NTASKS, SR_NTASKS_W, taskList.nTasks); } /* re-order the tasks according to their priority */ /* if (taskList.nTasks>1) { for (i=0; i0) ++taskMgrCtrl.taskIterations; #if defined(I_AM_SLAVE_DSP) eventQueue.nEvents= eventQueue.writePtr -eventQueue.readPtr; rPtr= eventQueue.readPtr; if ((eventQueue.nEvents == 0)&&(!GET_RBIT(COMMAND_REG_0, CR_HISTO_OVERRIDE))) return returnCode; trapMask= (eventQueue.eventData[rPtr].data2 & EVT_MGR_TRAPMASK) >> EVT_MGR_TRAP_O; #endif for (i=0; i 0) { CSR &= ~1; //Disable interrupts globally (bit 0 in CSR). rPtr= eventQueue.readPtr; evtMgrCtrl.iFrameCnt-= eventQueue.eventData[rPtr].iFrameCnt; evtMgrCtrl.xFrameCnt-= eventQueue.eventData[rPtr].xFrameCnt; if (eventQueue.eventData[rPtr].iFrameCnt>0) { newPos= eventQueue.eventData[rPtr].iStartFrame +eventQueue.eventData[rPtr].iFrameCnt; //Wrap beyond frame #(nFrames -1): if (newPos > evtMgrCtrl.iFrameMax) newPos-= (evtMgrCtrl.iFrameMax +1); ASGN_RFLD(TRAPSTAT_REG1_2, TSR2_IFRAME_HEAD,TSR2_IFRAME_HEAD_W, newPos); /* If it was held high (no room), can now lower pin4 mask. The post-increment sets the pin4MaskDown flag to TRUE. */ if (!evtMgrCtrl.pin4MaskDown++) MCBSP_FSET(PCR1, DXSTAT, 0); } if (eventQueue.eventData[rPtr].xFrameCnt>0) { newPos= eventQueue.eventData[rPtr].xStartFrame +eventQueue.eventData[rPtr].xFrameCnt; //Wrap beyond end: if (newPos > evtMgrCtrl.xMaxIdx) newPos-= (evtMgrCtrl.xFrameMax +1); ASGN_RFLD(TRAPSTAT_REG1_2, TSR2_XFRAME_HEAD,TSR2_XFRAME_HEAD_W, newPos); } ++eventQueue.readPtr; --eventQueue.nEvents; CSR |= 1; //Re-enable interrupts. Any triggered will have pended until now. } #endif return returnCode; } /************************************************************************************ * noTask * * synopsis: Safety net; should never be called. * * author: Douglas Ferguson ************************************************************************************/ INT32 noTask(TaskInput *tsi, TaskOutput *tso, UINT32 opFlags) { INT32 returnCode= SUCCESS; if (taskMgrCtrl.taskIterations%100000== 0) newInformation(__FILE__, __LINE__, "noTask!\n"); return returnCode; }