Lesson 3: Introducing Tasks for Application Data Processing


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);
}


< Previous Lesson | Next Lesson >