TinyOS provides a two level scheduling hierarchy consisting
of tasks
and events. TOS events generalize interrupt handling and
must do only a
small amount of work before completing. TOS
tasks are provided to
do any kind of general purpose
processing, providing concurrency
throughout the application
graph. They may be preempted by events,
so real-time
requirements, such as servicing the radio, may be met while
processing tasks.
A TOS task is declared as void TOS_TASK(taskname)(). It is a lower-level scheduling entity than events and may be preempted by events. Tasks execute atomically, relative to other tasks. Tasks do not preempt task. A task is posted using TOS_POST_TASK(taskname)(). They may be posted from within commands, events, or tasks. Tasks may not spin or block. They operate on their frame and complete their work. Chunks of work separated by long latency operations are broken into distinct tasks within a component sharing a frame.
To illustrate tasks, we have modified the SENSE application from lesson 2. It can be found at nest/apps/sense2. We have expanded the frame to contain a simple circular data buffer and provided a helper function putdata to deposit data into this buffer.
TOS_FRAME_BEGIN(SENSE_frame) {
char head;
short data[maxdata];
}
The data_ready event simply deposits data into the buffer and posts
a task for processing.
char TOS_EVENT(SENSE_DATA_READY)(short data){
putdata(data);
TOS_POST_TASK(processData);
return 1;
}
Some time after the event completes (there may be other tasks running
as well), the processData task will run. It computes a simple average
and renders it to the display.
TOS_TASK(processData){
int i, sum = 0;
TOS_CALL_COMMAND(SENSE_LEDg_toggle)();
for (i=0; i<maxdata; i++)
sum = sum + (VAR(data[i]) >> 7);
display(sum >> shiftdata);
}