Title: Writing a Primitive or Task
1SCT/Pixel DAQ Workshop
Writing a Primitive or Task
- Five easy steps to make a primitive.
- Seven not-quite-as-easy steps to make a task.
Douglas Ferguson UW-Madison LBL
2Writing a Primitive, Step 1
In primParams.h, define the constant mnemonic for
the primitive ID, the revision number and
structure tags for the input and output (reply)
data.
define CHECK_BIT (1 (ltpreviously last
primitivegt)) define R_CHECK_BIT 100 struct
CHECK_BIT_IN UINT32 registerId UINT32
bitNumber struct CHECK_BIT_OUT UINT32
bitSet define LAST_COMMON_PRIMITIVE
(CHECK_BIT)
NOTES
- To avoid forcing re-writes of pre-existing
primitive lists, this should be done - at the end of the section common, slave or
master primitives.
- There is no need to define structures for
primitives with un-structured data, - like Echo.
3Writing a Primitive, Step 2
In primParams.h, near the bottom, put a prototype
declaration for Your primitive in the appropriate
section
INT32 checkBit(struct PRIM_DATA )
Writing a Primitive, Step 3
In primParams.h, increment the PRIM_LIST_REVISION
compiler Constant, if you are brave.
NOTES
- While its a good idea to do step 3 in theory,
in practice it causes endless - compatibility problems. For individual
primitives, there are already revision - numbers. Changing that when you change the of
input parameters for a - primitive is a good idea. My suggestion We
leave the compiler constant - fixed, unless the primitive list structure is
radically altered.
4Writing a Primitive, Step 4
Update primIDList the primParameters array
inside initializePrimParams in primFuncts.c add
in the new primitive in the appropriate spot
(bottom of common, slave-only, or
master-only functions) primIDListprimLoop
CHECK_BIT primParametersprimLoop
.primFunction checkBit primParametersprimLoo
p.primRevision R_CHECK_BIT
NOTES
- The primParameters array is initially set to
point to a special routine called - noPrimitive. If this step is forgotten, it
will still point there and an error - will be generated if the primitive is called.
- Its not strictly necessary to keep the
primParameters primIDList arrays - in the same order as they appear in
primParams.h (where they MUST go at the - end of their section), but it helps readability.
5Writing a Primitive, Step 5
In primFuncts.c, slavePrimFuncts.c or
masterPrimFuncts.c, write the routine...
INT32 checkBit(struct PRIM_DATA primData)
INT32 returnCode SUCCESS INT32 error
UINT32 registerId UINT32 bitNumber UINT32
bitSet struct CHECK_BIT_IN checkBitIn
(struct CHECK_BIT_IN
)primData-gtpriBodyPtr struct CHECK_BIT_OUT
checkBitOut (struct
CHECK_BIT_OUT )primData-gtrepBodyPtr
registerId checkBitIn-gtregisterId bitNumber
checkBitIn-gtbitNumber primData-gtrepBodyLength
SIZEOF(struct CHECK_BIT_OUT)
NOTES
- If your primitive will be polling or will
otherwise return REPEAT_PRIMITIVE - under some circumstances, static variables are
needed.
- ALWAYS set the size of the reply data in the
function, as early as is - feasible. Not doing so will cause un-ending
amounts of grief.
6Writing a Primitive, Step 5 (cont)
error readRegister( registerId, 1, bitNumber,
bitSet) if (error lt 0) addError(returnCo
de,error, "checkBit","readRegister",
__FILE__, __LINE__) if (FATAL(returnCode))
return returnCode checkBitOut-gtbitSet
bitSet return returnCode
NOTES
- addError adds a functions return INT32 error
code (negative if an error) to - the returnCode, and concatenates the identifier
strings to the error message - which is already in the error buffer. If the
error originates inside the primitive - itself, use newError instead.
- If the function returns large amounts of data,
consider returning a pointer - data length instead, like sendData. Failing
that, check the reply datas length - against the length of the reply buffer.
7Writing a Primitive, Step 5 (cont)
endPtr primData-gtrepBodyPtr wSize if (endPtr
gt primData-gtrepBuffEnd) newError(returnCode,
MSG_EXCEEDS_LIST_BOUND, ERROR_0,
"sendData", "Reply data would exceed reply buffer
boundary! ...sending pointer", __FILE__,
__LINE__) return returnCode
NOTES
- Dont forget to update the revision number if
you change the number or - meaning of the input or output parameters!
Another source of grief.
8Writing a Primitive, Step 6
Compile and debug the routine! Arrgh!!
9Writing a Task, Step 1
In primParams.h, define the tasks revision
number and structure tags for the input and
output (reply) data, if any. The new task should
be defined in the section in primParams.h where
all the other tasks are defined (in the startTask
section). Add the new structure to startTasks
structure union. Tasks must have an
input structure of some sort defined. The union
cannot accept unstructured data, like echo.
define R_TRAP_TASK 100 struct TRAP_TASK_IN
UINT32 nEvents, reloadInterval, trapType,
eventType, trapBufferBase,
trapBufferLength
union TASK_STRUCTURES_IN struct
HISTOGRAM_CTRL_TASK_IN histoCtrlTaskIn struct
MIRROR_TASK_IN mirrorMemoryTaskIn struc
t TRAP_REQ_TASK_IN trapRequestTaskIn str
uct HISTOGRAM_TASK_IN histogramTaskIn struct
TRAP_TASK_IN trapTaskIn struct
OCCUPANCY_TASK_IN occupancyTaskIn struct
ERROR_TASK_IN errorTaskIn struct
RESYNCH_TASK_IN resynchTaskIn
10Writing a Task, Step 2
In primParams.h, if the task has output data
(variables, not processed event data), add the
new output structure to taskOperations structure
union. If tasks output data, it must have a
defined structure. A generalized output structure
is available for simple output.
The trapping task uses the generalized output
structure
struct GEN_TASK_OUT UINT32 dataPtr,
dataLength union TASK_STRUCTURES_OUT
struct HISTOGRAM_CTRL_TASK_OUT
histoCtrlTaskOut struct HISTOGRAM_TASK_OUT
histogramTaskOut struct ERROR_TASK_OUT
errorTaskOut struct GEN_TASK_OUT
genTaskOut
11Writing a Task, Step 3
In primParams.h, add the task to the appropriate
task ID list. There are no common tasks yet, only
master slave DSP tasks if a common task is
needed a new section will have to be created
several routines need updating. The task should
generally go at the bottom of the
list, especially if it is an event-based slave
DSP task.
/ slave DSP tasks / define SLAVE_TASK_BASE
(0x20) define HISTOGRAM_TASK (SLAVE_TASK_BASE)
define TRAP_TASK (1(HISTOGRAM_TASK)) defin
e OCCUPANCY_TASK (1(TRAP_TASK)) define
ERROR_TASK (1(OCCUPANCY_TASK)) define
RESYNCH_TASK (1(ERROR_TASK)) define
LAST_SLAVE_TASK (RESYNCH_TASK) define
NUM_SLAVE_TASKS ((LAST_SLAVE_TASK)-(SLAVE_TASK_BA
SE)1)
- DO NOT forget to update the maximum number of
tasks (master or slave), if - that has changed. Otherwise you will get
mysterious errors, with no idea why
/ MAX_NUM_TASKS is the maximum of the two task
numbers for master slave DSPs. Bad Things
can happen if it is not kept up to date
/ define MAX_NUM_TASKS 5
12Writing a Task, Step 4
If the task is event based, in primParams.h
update the trapping function field of
eventTrapSetup. There are not many more
fields available, so be conservative with these.
You will also need to update eventHandler.h, and
the event processing routines in eventHandler.c
Processed data should be handled by sendData.
define TRAP_FXN_HISTOGRAM 1 define
TRAP_FXN_TRAP 2 define
TRAP_FXN_OCCUPANCY 4 define TRAP_FXN_ERRORCNT
8 define TRAP_FXN_RESYNCH 16
Frame set registers
- 32 per frame set, used by the event manager to
jump from one frame to the - next when processing multi-frame events, and
determine which tasks to give them to.
- defined as 0xSSSD DDDD PPPP PETO FFFF FFFF IIII
IIII
Useful for monitoring can be decreased
or removed if needed.
Pending tasks
Delta to Next within Frame set
Frame set delta
Internal ID
Evt frame
Overflow bit
Trailer bit
Error bit
13Writing a Task, Step 5
In the appropriate c file, write the function
prototype. The following routines will also need
updating insertTask, taskOp, And getTaskData.
INT32 trapTask(union TASK_STRUCTURES_IN , union
TASK_STRUCTURES_OUT , UINT32)
Writing a Task, Step 6
Define the new tasks states. Your task will
probably be executing for a while, and it will be
helpful if the DAQ can know what mischief its up
to.. (see my DSP software talk for a good
example of task states.
/ TASK_INIT 1 / define HCTRL_NEWBIN
2 define HCTRL_WAITEXP 3 define
HCTRL_PULSING 4 define HCTRL_WAITING
5 define HCTRL_PREP 6 / TASK_DONE 0xD
/
14Writing a Task, Step 7
In the appropriate c file, write the task..
define MIRROR_RUNNING 0x2 define MIRROR_WAITING
0x3 INT32 mirrorTask(union TASK_STRUCTURES_IN
tsi, union TASK_STRUCTURES_OUT tso,
UINT32 opFlags) INT32 returnCode
REPEAT_TASK, slaveStat, errorCode static UINT8
state TASK_INIT, slvBits, nMirrorSlaves,
first, warn4, nibble,
nMirrors 0 static UINT32 hpic,
mirrorBase(UINT32 )(MIRROR_DEFAULT_BASE),
mirrorTotLen 0 static UINT32
mirrorFreqMAX_MIRRORS, lastUpdateMAX_MIRRORS,
mirrorSlvBaseMAX_MIRRORS,
mirrorLenMAX_MIRRORS UINT32
word, address, deltaTime, readTime, time UINT8
i, slv, slv_idx, accum, stateChange char
startStr40
15/ data retrieval routine
reset / if (opFlags gt 0x10) /
Place the interesting internal variables into the
output structure / tso-gtgenTaskOut.da
taPtr NULL tso-gtgenTaskOut.dataLength
0 if (opFlags TASK_HALT_MASK)
newInformation(__FILE__, __LINE__,
"Memory Mirror task
halting.\n") state TASK_INIT return
TASK_HALTED else if (opFlags
TASK_INIT_MASK) newInformation(__FILE__,
__LINE__, "Memory
Mirror task re-initing.\n") / reset nMirrors,
and the default base length,
which are not reset on task stopping to
allow accumulation. / nMirrors mirrorTotLen
0 mirrorBase (UINT32 ) (MIRROR_DEFAULT_BASE)
state TASK_INIT return TASK_INITIALIZED
16 else if (opFlags TASK_QUERY_MASK)
newInformation(__FILE__, __LINE__,
"Memory Mirror task query data
output.\n") return TASK_QUERIED
Initialization state must handle initialization
of all routine static variables
/ routine statesINIT
/ else if (state TASK_INIT)
/ set up any static variables beyond state
/ returnCode REPEAT_TASK nibble MIRROR_TASK
-MASTER_TASK_BASE first TRUE hpic
(1ltltHHPI_HPIC_HWOB_SHIFT) (1 ltlt(HHPI_HPIC_HWOB_S
HIFT
HWORD_W))
. . .
17else if ((state MIRROR_RUNNING)(state
MIRROR_WAITING)) if (first) first
FALSE taskMgrCtrl.runningTaskReg
(0xfltlt(nibble4)) taskMgrCtrl.runningTaskReg
(stateltlt(nibble4))
. . .
Above lines tell DAQ what state task is in
return returnCode
? If all went well, returnCode REPEAT_TASK