TinyOS

From Céupédia
Jump to: navigation, search

This page is about running the Céu programming language in the TinyOS platform.

1 Installation

You can either download a virtual machine preloaded with Céu, or install it manually from the git repository:

2 Examples

The distribution comes with some samples ready for playing with Céu.

After the installation, open a terminal window and cd to the TinyOS/nesC directory:

   $ cd ceu-tinyos/

2.1 Blinking LEDs

The first example, blink.ceu, mimics the exact behavior of the Blink application on the TinyOS Tutorial:

   par do                            // a parallel statement
       // 1st trail
       loop do                       // an infinite loop that:
           await 250ms;              //   - awaits 250ms
           _Leds_led0Toggle();       //   - toggles the led
       end                           //   - repeats
   with
       // 2nd trail
       loop do
           await 500ms;
           _Leds_led1Toggle();
       end
   with
       // 3rd trail
       loop do
           await 1000ms;
           _Leds_led2Toggle();
       end
   end

To compile and upload it to your board, run the following command:

   $ make CEUFILE=samples/blink.ceu micaz install mib520,/dev/ttyUSB0

You should see the leds blinking, just like in the video on the right.

The program runs three loops in parallel, each blinks a led with a different frequency.

C symbols like Leds_led0Toggle must be preceded with an underscore.

The await primitive suspends the running line of execution (a trail in Céu) until the referred event occurs (e.g. 500ms).

With multiple trails, it is possible to wait for multiple events at the same time, as the example illustrates.

2.2 Sensing

The second example, sense.ceu, requires a light sensor connected to the mote.

   $ make CEUFILE=samples/sense.ceu micaz install mib520,/dev/ttyUSB0

This example is derived from the Sense application on the TinyOS Tutorial:

   input int Photo_readDone;                // input event from TinyOS
   int data;
   
   loop do
       await 100ms;
       _Photo_read();                       // requests sensor read
       data = await Photo_readDone;         // awaits the response with the value
       _Leds_set(data/100);
   end

The program is an infinite loop that reads the light sensor every 100ms. On each iteration, the application requests the _Photo_read operation to read the sensor, then awaits the response, and lights on the corresponding leds.

There's no need for callbacks in Céu, the request/await pattern greatly simplifies the programming effort. Moreover, it still reflects the underlying Split-Phase mechanism of TinyOS that avoids blocking the operating system, that is, other parts of the program (in parallel) remain alive and reactive.

2.3 Communicating via radio

The third example, radio_echo.ceu, illustrates the use of the radio for communication among motes.

   $ make CEUFILE=samples/radio_echo.ceu micaz install mib520,/dev/ttyUSB0       # repeat for another mote

Each time a mote receives a message, it shows the received value on the LEDs (a simple counter incremented after each send). The video on the right shows the expected behavior for the program running in two motes.

First, we need to define which events are used in the program, and also the struct for the radio message:

   input  int                 RADIO_STARTDONE;
   input  (_message_t*, int)  RADIO_SENDDONE;
   input  (_message_t*, int)  RADIO_RECEIVE;
   output (_message_t*, int*) RADIO_SEND;
   
   native do
       typedef struct {
           nx_uint16_t cnt;              // a simple 16 bits counter
       } Msg ;
   end

The native do .. end block allows the definition of C structs and functions from within Céu.

The next step is to initialize the radio for communication. If you are not familiar with radio communication under TinyOS, see the mote to mote communication tutorial.

   // loop to retry until the initialization is successful
   loop do
       var int err = _Radio_start();     // requests `Radio_start'
       if err == _SUCCESS then
           err = await RADIO_STARTDONE;  // awaits the confirmation
           if err == _SUCCESS then
               break;                    // everything is ok, escapes the loop
           end
       end
       await 1s;                         // waits 1 second before retrying
   end

In sequence with the radio initialization, we proceed to use the radio with two activities in parallel: one that receives the messages and show them on the LEDs, and another that sends the counter every 2 seconds:

   par do
       /* Receive activity */
       loop do
           var _message_t* pkt_rcv;
           var u8 len;
           (pkt_rcv, len) = await RADIO_RECEIVE;                       // waits for the next message
           var _Msg* msg_rcv = _Radio_getPayload(pkt_rcv,0);           // gets a pointer to the message payload
           _Leds_set(msg_rcv:cnt);                                     // shows the received
       end
   
   with
       /* Send activity */
       var _message_t pkt_snd;                                         // buffer to send messages
       var _Msg* msg_snd = _Radio_getPayload(&pkt_snd, sizeof(_Msg));  // gets a pointer to the message payload
       msg_snd:cnt = 0;                                                // sets the initial value for the counter
   
       loop do
           await 2s;
           _Radio_setDestination(&pkt_snd, _AM_BROADCAST_ADDR);        // sends the message via broadcast
           _Radio_setPayloadLength(&pkt_snd, sizeof(_Msg));
           emit RADIO_SEND => (&pkt_snd,null);
           msg_snd->cnt = msg_snd->cnt + 1;                            // increments the counter for the next send
       end
   end

For the sake of simplicity, we did not test the return status of RADIO_SEND.

2.4 Ring communication

For a more complete example, check the following blog post: