Wednesday, July 27, 2016

Project Configuration Example

Objective

The objective of this post is to show you how to configure the options in Contiki OS. I tested this tutorial in Contiki 3.0 and Ubuntu 16.04.

Step 1: Create a project-conf.h file

I am going to use the example-broadcast.c of the RIME stack. So, go to the following folder:

/home/YOURUSER/contiki-3.0/examples/rime

and create a file named project-conf.h, this file will contain all the specific configurations of your nodes.

Step 2: Select your configurations and write them in the file project-conf.h

Open your file project-conf.h and change the defines you want. In this example i want to change the radio frequency channel to 20. Remember that the default radio channel is 26. Then, my project-conf.h looks like this:
#define RF_CHANNEL 20 //RF_CHANNEL = Radio Fequency Channel

Step 3: Change your Makefile

Contiki only understands the changes you made in the project-conf.h file when you modify your Makefile. So, open your Makefile located in the rime folder:
/home/YOURUSER/contiki-3.0/examples/rime
and add the line CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\". So, now your Makefile should look like this:
CONTIKI = ../..

all: example-abc example-mesh example-collect example-trickle example-polite \
     example-rudolph1 example-rudolph2 example-rucb \
     example-runicast example-unicast example-neighbors

CONTIKI_WITH_RIME = 1
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
include $(CONTIKI)/Makefile.include

Step 4: Modify the contiki-conf.h of your platform

Next, you will need to modify the contiki-conf.h archive of your platform. In this case i am using a CM5000 sky node. Then, i must go to the folder /home/YOURUSER/Desktop/contiki-3.0/platform/sky, open the archive contiki-conf.h, and cut the following code located at the end of the file:


/* include the project config */
/* PROJECT_CONF_H might be defined in the project Makefile */
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */

Then, you must copy that code at the beginning of the archive. Finally, you contiki-conf.h archive would look like this:


/* -*- C -*- */

#ifndef CONTIKI_CONF_H
#define CONTIKI_CONF_H

/* include the project config */
/* PROJECT_CONF_H might be defined in the project Makefile */
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */

Step 5: Compile your code and load it in a node

The last step is to clean/compile your code and load it into a sensor node using the following commands:
make clean
make TARGET=sky example-broadcast.upload && make login
Then, you should see that the channel is set to 20:
Rime started with address 1.0                                                
MAC 01:00:00:00:00:00:00:00 Contiki 3.0 started. Node id is set to 1.        
nullsec CSMA ContikiMAC, channel check rate 8 Hz, radio channel 20           
Starting 'Broadcast example'

Monday, July 18, 2016

Measure the Received Signal Strength Indicator (RSSI) for cc2420 radio

Objective

To measure the Received Signal Strenght Indicator (RSSI) of the radio cc2420 for sky motes using Contiki OS 3.0. I tested this code in Ubuntu 16.04.

Code

The library cc2420.h already brings a variable that stores the RSSI of the last received packet. The variable is known as cc2420_last_rssi. Then, all you need to do is to add the mentioned library and use the variable cc2420_last_rssi, however, you must decrease the variable 45 in order to get the right RSSI. You can read the datasheet of the cc2420 in page 49, here it says that you must decrease the variable 45. The resulting RSSI is in dBm. The following link is the datasheet of the cc2420.

http://web.stanford.edu/class/cs244e/papers/cc2420.pdf

Here is the code.


#include "/home/YOURUSER/contiki-3.0/dev/cc2420/cc2420.h" // In order to recognize the variable cc2420_last_rssi

//Your code...

  // Declare the variables that you will use
  static signed char rss;
  static signed char rss_val;
  static signed char rss_offset;

  rss_val = cc2420_last_rssi;  // Get the RSSI from the last received packet
  rss_offset = -45; // Datasheet of cc2420 page 49 says you must decrease the value in -45
  rss = rss_val + rss_offset; // The RSSI correct value in dBm

  printf("RSSI of Last Received Packet = %d\n",rss);

Monday, July 11, 2016

How to set up the Contiki OS communication stack

Objective

Set up the Contiki OS communication stack. For detailed information about the Contiki communication stack, please visit the following web page.

http://anrg.usc.edu/contiki/index.php/MAC_protocols_in_ContikiOS

This post will explain how to set up the network, MAC, RDC (Radio Duty Cicle), framer and radio layer of your sensor node in Contiki OS 3.0. I used a CM5000 node and Ubuntu 16.04 to test this example. Besides, i used a RIME example named example-broadcast.c

Step 1: Create a project-conf.h archive

Go to your project folder, in this case /home/YOURUSER/Desktop/contiki-3.0/examples/rime, and create an archive called project-conf.h with the following content:


#define NETSTACK_CONF_NETWORK rime_driver // Define the network driver to use
#define NETSTACK_CONF_MAC     csma_driver // Define the MAC driver to use
#define NETSTACK_CONF_RDC     contikimac_driver // Define the RDC driver to use
#define NETSTACK_CONF_FRAMER  framer_802154 // Define the framer driver to use
#define NETSTACK_CONF_RADIO   cc2420_driver // Define the radio driver to use

The lines define the network driver, the MAC driver, the RDC driver, the framer driver and the radio driver respectively.

Step 2: Modify the Makefile

In order to include the previously defined project-conf.h archive within contiki you must tell contiki that it exists. To that end, you must include the following line in the Makefile CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\". Remember that the makefile is located in /home/YOURUSER/Desktop/contiki-3.0/examples/rime.Then, your Makefile must look like this:

CONTIKI = ../..

all: example-abc example-mesh example-collect example-trickle example-polite \
     example-rudolph1 example-rudolph2 example-rucb \
     example-runicast example-unicast example-neighbors

CONTIKI_WITH_RIME = 1
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
include $(CONTIKI)/Makefile.include

Step 3: Modify the contiki-conf.h of your platform

Next, you will need to modify the contiki-conf.h archive of your platform. In this case i am using a CM5000 sky node. Then, i must go to the folder /home/YOURUSER/Desktop/contiki-3.0/platform/sky, open the archive contiki-conf.h, and cut the following code located at the end of the file:


/* include the project config */
/* PROJECT_CONF_H might be defined in the project Makefile */
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */

Then, you must copy that code at the beginning of the archive. Finally, you contiki-conf.h archive would look like this:


/* -*- C -*- */

#ifndef CONTIKI_CONF_H
#define CONTIKI_CONF_H

/* include the project config */
/* PROJECT_CONF_H might be defined in the project Makefile */
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */

Step 4: Compile the example

Finally, you must clean and compile the example example-broadcast.c using the following commands:

make TARGET=sky clean && make TARGET=sky example-broadcast

Then, you must reset manually the node and then login with the following command.

make login

You will see in terminal the selected communication stack, for example, in the below code you can see that i selected Rime in the network layer, CSMA in the MAC layer and ContikiMAC in the RDC layer.

Rime started with address 2.0
MAC 02:00:00:00:00:00:00:00 Contiki 3.0 started. Node id is set to 2.
nullsec CSMA ContikiMAC, channel check rate 8 Hz, radio channel 26
Starting 'Example unicast' 'Reads the Sensors Information'

How to send information between two processes in Contiki OS

Objective

The objective of this post is to show you how to send information between two processes in Contiki OS, more specifically, i will show you how to send a structure from one process to the other. I tested the following example in a CM5000 sensor node, using Contiki OS 3.0 and ubuntu 16.04.

General Description of the C example

The example that is proposed here has two processes known as: read_temperature_light and example_unicast_process. The former process is in charge of reading the temperature and light values from the CM5000 sensor node, then it saves this information in a structure called environment. Then, this structure is sent to the process example_unicast_process via the function process_post(). Finally, the process example_unicast_process sends the structure environment wirelessly to the sink.

Process 1: read_temperature_light

The first process is in charge of reading the temperature and light values, saving this information in the structure environment and then passing this information to the second process example_unicast_process. The code below presents this process. Next, i will explain the most relevant lines:

  • static struct etimer et: This line defines the structure known as et, which is a timer that post an event each 5 seconds. This means that each 5 seconds the timer expires and the process read_temperature_light is ejecuted.
  • etimer_set(&et, CLOCK_SECOND * 5): This line sets the timer to expire in 5 seconds
  • PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)): This line makes the process wait until the timer expires (5 seconds)
  • envir.sequence = sequence: When the timer expires then the sequence is saved in the structure environment
  • envir.temp = temporal: When the timer expires then the temperature is saved in the structure environment
  • envir.light = temporal: When the timer expires then the light is saved in the structure environment
  • process_post(&example_unicast_process, PROCESS_EVENT_CONTINUE , &(envir) ) : This is the most important line. With this line the current process read_temperature_light post an event to the process example_unicast_process, this means that the latter process will execute next. Besides, the information that is sent to the process example_unicast_process is the structure environment, which contains the light and temperature value read by the sensor.

Until now, we have stored the light and temperature values in the structure environment, then we called the process example_unicast_process and sent it the information contained in the structure named environment. In the process 2 example_unicast_process we will read the information from the structure environment.


PROCESS_THREAD(read_temperature_light, ev, data)  // Process for reading the temperature and light values
{
  static struct etimer et; // Struct used for the timer
  int temporal; //Temporal Variable

  PROCESS_BEGIN();  // Says where the process starts 
  
  while(1){
  
  etimer_set(&et, CLOCK_SECOND * 5); // Configure timer to expire in 5 seconds
 
  SENSORS_ACTIVATE(light_sensor); // Activate light sensor
  SENSORS_ACTIVATE(sht11_sensor); // Activate temperature sensor
 
  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); // Wait until timer expires 
 
  printf("Data\t"); // Print the string "Data"
  sequence++;
  printf("%d\t", sequence);  // Print the sequence number
  envir.sequence = sequence; // To save the sequence in the struct envir
  printf("%d\t", temporal = get_temp()); // Print the temperature value
  envir.temp = temporal; // To save the temperature in the struct envir
  printf("%d\n", temporal = get_light());  // Print the light value
  envir.light = temporal; // To save the light in the struct envir

  process_post(&example_unicast_process, PROCESS_EVENT_CONTINUE , &(envir) ); // This function posts an asynchronous event to the process example_unicast_process with the information of the structure called envir
 
  etimer_reset(&et); // Reset timer
 
  SENSORS_DEACTIVATE(light_sensor); // Deactivate light sensor
  SENSORS_DEACTIVATE(sht11_sensor);  // Deactivate temperature sensor
 
  }
  
  PROCESS_END();//Says where the process ends

}

Process 2: example_unicast_process

In this process we will read the information from the structure environment. The code below presents this process. We will explain the most relevant lines:

  • PROCESS_WAIT_EVENT(): This process executes whenever an event is posted. It means each time the process read_temperature_light post an event via the function process_post
  • struct environment *envirRX = data: This line takes the data that the process received and save it into the structure pointer named *envirRX
  • printf("%d\t", envirRX->sequence ): In order to access a structure's element we use the operator ->
  • packetbuf_copyfrom( envirRX , sizeof( (*envirRX) ) ): We copy the structure envirRX in the packet buffer to send it wirelessly via the unicast_send() function

PROCESS_THREAD(example_unicast_process, ev, data) // Process for sending a unicast message
{
  PROCESS_EXITHANDLER(unicast_close(&uc);)//Specify an action when a process exits. 
    
  PROCESS_BEGIN();  // Says where the process starts

  unicast_open(&uc, 146, &unicast_callbacks);  //Opens a unicast connection

  while(1) {

    linkaddr_t addr; //Declares the addr variable
    
    PROCESS_WAIT_EVENT(); //Wait for an event to be posted to the process. 

    struct environment *envirRX =  data; //Saves the information that comes from the other process (read_temperature_light) into a structure pointer called *envirRX


    printf("Data\t"); // Print the string "Data"
    printf("%d\t", envirRX->sequence );  // Print the sequence number
    printf("%d\t", envirRX->temp ); // Print the temperature value
    printf("%d\n", envirRX->light );  // Print the light value

    packetbuf_copyfrom(  envirRX , sizeof(  (*envirRX)  ) ); 

    addr.u8[0] = 1; //This is the sink's address
    addr.u8[1] = 0; //This is the sink's address
    if(!linkaddr_cmp(&addr, &linkaddr_node_addr)) { //if the address is diferent from the current's node
      unicast_send(&uc, &addr); //Send a unicast message to the sink
    }

  }

  PROCESS_END();  //Says where the process ends
}

Full Example

The below code presents the full example.


/*
 * Copyright (c) 2007, Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the Contiki operating system.
 *
 */

/**
 * \file
 *         Example of a node sending messages to a sink
 * \author
 *        Sergio Diaz
 */

#include "contiki.h"
#include "net/rime/rime.h"

#include "dev/button-sensor.h"

#include "dev/leds.h"

#include 

//Libraries to manage the sensors
#include "/home/sink/Desktop/contiki-3.0/dev/sht11/sht11-sensor.h"
#include "/home/sink/Desktop/contiki-3.0/platform/sky/dev/light-sensor.h"
#include "/home/sink/Desktop/contiki-3.0/core/dev/leds.h"

//#include "example-uni-temp.h"  // Declares the struct environment

struct environment{ //You can put this structure declaration in an archive called example-uni-temp.h

   int sequence; //To save the sequence number
   int temp; // To save the temperature value
   int light; // To save the light value


}

/*---------------------------------------------------------------------------*/
PROCESS(example_unicast_process, "Example unicast"); // Process for sending a unicast message
PROCESS(read_temperature_light, "Reads the Sensors Information"); // Process for reading the temperature and light values
 
AUTOSTART_PROCESSES(&example_unicast_process, &read_temperature_light); //Start the process when the node boots

struct environment envir; // Struct used to store the temperature and light values  

/*---------------------------------------------------------------------------*/
static int
get_light(void) //Get the light value from sensor
{
  return 10 * light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC) / 7;
}
/*---------------------------------------------------------------------------*/
static int
get_temp(void) //Get the temperature value from sensor
{
  return ((sht11_sensor.value(SHT11_SENSOR_TEMP) / 10) - 396) / 10;
}
/*---------------------------------------------------------------------------*/
 
int sequence = 0; // A sequence number that enumerates the data from 0 and increases in 1 each time.

/*---------------------------------------------------------------------------*/
static void
recv_uc(struct unicast_conn *c, const linkaddr_t *from)
{
  //The node does not need to receive packets
}

static const struct unicast_callbacks unicast_callbacks = {recv_uc};  //Every time a packet arrives the function recv_uc is called.
static struct unicast_conn uc;  // Declares the unicast connection uc

/*---------------------------------------------------------------------------*/
PROCESS_THREAD(read_temperature_light, ev, data)  // Process for reading the temperature and light values
{
  static struct etimer et; // Struct used for the timer
  int temporal; //Temporal Variable

  PROCESS_BEGIN();  // Says where the process starts 
  
  while(1){
  
  etimer_set(&et, CLOCK_SECOND * 5); // Configure timer to expire in 5 seconds
 
  SENSORS_ACTIVATE(light_sensor); // Activate light sensor
  SENSORS_ACTIVATE(sht11_sensor); // Activate temperature sensor
 
  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); // Wait until timer expires 
 
  printf("Data\t"); // Print the string "Data"
  sequence++;
  printf("%d\t", sequence);  // Print the sequence number
  envir.sequence = sequence; // To save the sequence in the struct envir
  printf("%d\t", temporal = get_temp()); // Print the temperature value
  envir.temp = temporal; // To save the temperature in the struct envir
  printf("%d\n", temporal = get_light());  // Print the light value
  envir.light = temporal; // To save the light in the struct envir

  process_post(&example_unicast_process, PROCESS_EVENT_CONTINUE , &(envir) ); // This function posts an asynchronous event to the process example_unicast_process with the information of the structure called envir
 
  etimer_reset(&et); // Reset timer
 
  SENSORS_DEACTIVATE(light_sensor); // Deactivate light sensor
  SENSORS_DEACTIVATE(sht11_sensor);  // Deactivate temperature sensor
 
  }
  
  PROCESS_END();//Says where the process ends

}


/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_unicast_process, ev, data) // Process for sending a unicast message
{
  PROCESS_EXITHANDLER(unicast_close(&uc);)//Specify an action when a process exits. 
    
  PROCESS_BEGIN();  // Says where the process starts

  unicast_open(&uc, 146, &unicast_callbacks);  //Opens a unicast connection

  while(1) {

    linkaddr_t addr; //Declares the addr variable
    
    PROCESS_WAIT_EVENT(); //Wait for an event to be posted to the process. 

    struct environment *envirRX =  data; //Saves the information that comes from the other process (read_temperature_light) into a structure pointer called *envirRX


    printf("Data\t"); // Print the string "Data"
    printf("%d\t", envirRX->sequence );  // Print the sequence number
    printf("%d\t", envirRX->temp ); // Print the temperature value
    printf("%d\n", envirRX->light );  // Print the light value

    packetbuf_copyfrom(  envirRX , sizeof(  (*envirRX)  ) ); 

    addr.u8[0] = 1; //This is the sink's address
    addr.u8[1] = 0; //This is the sink's address
    if(!linkaddr_cmp(&addr, &linkaddr_node_addr)) { //if the address is diferent from the current's node
      unicast_send(&uc, &addr); //Send a unicast message to the sink
    }

  }

  PROCESS_END();  //Says where the process ends
}
/*---------------------------------------------------------------------------*/



Friday, July 8, 2016

Send temperature and light from a node to the sink

Objective

The objective of this post is to send the temperature and light data from a sensor node to the sink. I tested this example in a CM5000 sensor node and a sink, which is basically a standard computer with a CM5000 sensor node connected to a USB port. I used Contiki 3.0 and Ubuntu 16.04.

Sensor Node Code

The sensor node code has two basic components: a process known as read_temperature_light to sense the temperature and light data, and a process known as example_unicast_process to send this information wirelessly via a unicast message. Next, i will explain each process.
  • read_temperature_light: This process has a timer called et which expires each 5 seconds. It means that each 5 seconds this process will execute. When the process executes, it sense the temperature and light values from the sensor node, then it saves this information in the structure called envir. Finally, the second process (example_unicast_process) is called and we deliver it the structure envir. The latter is done via the function process_post(). Below, you will see the code of this process.
  • 
    PROCESS_THREAD(read_temperature_light, ev, data)  // Process for reading the temperature and light values
    {
      static struct etimer et; // Struct used for the timer
      int temporal; //Temporal Variable
    
      PROCESS_BEGIN();  // Says where the process starts 
      
      while(1){
      
      etimer_set(&et, CLOCK_SECOND * 5); // Configure timer to expire in 5 seconds
     
      SENSORS_ACTIVATE(light_sensor); // Activate light sensor
      SENSORS_ACTIVATE(sht11_sensor); // Activate temperature sensor
     
      PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); // Wait until timer expires 
     
      printf("Data\t"); // Print the string "Data"
      sequence++;
      printf("%d\t", sequence);  // Print the sequence number
      envir.sequence = sequence; // To save the sequence in the struct envir
      printf("%d\t", temporal = get_temp()); // Print the temperature value
      envir.temp = temporal; // To save the temperature in the struct envir
      printf("%d\n", temporal = get_light());  // Print the light value
      envir.light = temporal; // To save the light in the struct envir
    
      process_post(&example_unicast_process, PROCESS_EVENT_CONTINUE , &(envir) ); // This function posts an asynchronous event to the process example_unicast_process with the information of the structure called envir
     
      etimer_reset(&et); // Reset timer
     
      SENSORS_DEACTIVATE(light_sensor); // Deactivate light sensor
      SENSORS_DEACTIVATE(sht11_sensor);  // Deactivate temperature sensor
     
      }
      
      PROCESS_END();//Says where the process ends
    
    }
    
    
  • example_unicast_process: This processs receives the structure envir and sends it wirelessly to the sink, which has address 1.0. Below, you will see the code of this process

PROCESS_THREAD(example_unicast_process, ev, data) // Process for sending a unicast message
{
  PROCESS_EXITHANDLER(unicast_close(&uc);)//Specify an action when a process exits. 
    
  PROCESS_BEGIN();  // Says where the process starts

  unicast_open(&uc, 146, &unicast_callbacks);  //Opens a unicast connection

  while(1) {

    linkaddr_t addr; //Declares the addr variable
    
    PROCESS_WAIT_EVENT(); //Wait for an event to be posted to the process. 

    struct environment *envirRX =  data; //Saves the information that comes from the other process (read_temperature_light) into a structure pointer called *envirRX


    printf("Data\t"); // Print the string "Data"
    printf("%d\t", envirRX->sequence );  // Print the sequence number
    printf("%d\t", envirRX->temp ); // Print the temperature value
    printf("%d\n", envirRX->light );  // Print the light value

    packetbuf_copyfrom(  envirRX , sizeof(  (*envirRX)  ) ); 

    addr.u8[0] = 1; //This is the sink's address
    addr.u8[1] = 0; //This is the sink's address
    if(!linkaddr_cmp(&addr, &linkaddr_node_addr)) { //if the address is diferent from the current's node
      unicast_send(&uc, &addr); //Send a unicast message to the sink
    }

  }

  PROCESS_END();  //Says where the process ends
}

Sink Code

The sink code only has a process known as sink_receive which is in charge of receiving the structure envir and printing its information. Below, you will see the code of the process sink_receive. This process just opens a unicast connection and waits for an event, it means, that each time an event is detected (Some node sent a message), then the sink will execute the function recv_uc to handle the event.
PROCESS_THREAD(sink_receive, ev, data) //Declares the protothread called sink_receive

{
  PROCESS_EXITHANDLER(unicast_close(&uc);) // Specify an action when a process exits
     
  PROCESS_BEGIN(); // Says where the process starts
 
  unicast_open(&uc, 146, &unicast_callbacks); //Opens a unicast connection
 
  while(1) {
      PROCESS_WAIT_EVENT(); //Wait for an event to be posted to the process
                            //Wait for the event of receiving a message
  }
 
  PROCESS_END(); //Says where the process ends
}

Full Example

Below you will find three source codes. The first one is loaded to the CM5000 sensor node to read the temperature and light data and send it wirelessly to the sink, which has address 1.0. The second code is loaded to the sink which waits until a message is received, and then prints its contents. The third code is a .h file that defines the structure environment.

/*
 * Copyright (c) 2007, Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the Contiki operating system.
 *
 */

/**
 * \file
 *         Example of a node sending messages to a sink
 * \author
 *        Sergio Diaz
 */

#include "contiki.h"
#include "net/rime/rime.h"

#include "dev/button-sensor.h"

#include "dev/leds.h"

#include 

//Libraries to manage the sensors
#include "/home/sink/Desktop/contiki-3.0/dev/sht11/sht11-sensor.h"
#include "/home/sink/Desktop/contiki-3.0/platform/sky/dev/light-sensor.h"
#include "/home/sink/Desktop/contiki-3.0/core/dev/leds.h"

#include "example-uni-temp.h"  // Declares the struct environment

/*---------------------------------------------------------------------------*/
PROCESS(example_unicast_process, "Example unicast"); // Process for sending a unicast message
PROCESS(read_temperature_light, "Reads the Sensors Information"); // Process for reading the temperature and light values
 
AUTOSTART_PROCESSES(&example_unicast_process, &read_temperature_light); //Start the process when the node boots

struct environment envir; // Struct used to store the temperature and light values  

/*---------------------------------------------------------------------------*/
static int
get_light(void) //Get the light value from sensor
{
  return 10 * light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC) / 7;
}
/*---------------------------------------------------------------------------*/
static int
get_temp(void) //Get the temperature value from sensor
{
  return ((sht11_sensor.value(SHT11_SENSOR_TEMP) / 10) - 396) / 10;
}
/*---------------------------------------------------------------------------*/
 
int sequence = 0; // A sequence number that enumerates the data from 0 and increases in 1 each time.

/*---------------------------------------------------------------------------*/
static void
recv_uc(struct unicast_conn *c, const linkaddr_t *from)
{
  //The node does not need to receive packets
}

static const struct unicast_callbacks unicast_callbacks = {recv_uc};  //Every time a packet arrives the function recv_uc is called.
static struct unicast_conn uc;  // Declares the unicast connection uc

/*---------------------------------------------------------------------------*/
PROCESS_THREAD(read_temperature_light, ev, data)  // Process for reading the temperature and light values
{
  static struct etimer et; // Struct used for the timer
  int temporal; //Temporal Variable

  PROCESS_BEGIN();  // Says where the process starts 
  
  while(1){
  
  etimer_set(&et, CLOCK_SECOND * 5); // Configure timer to expire in 5 seconds
 
  SENSORS_ACTIVATE(light_sensor); // Activate light sensor
  SENSORS_ACTIVATE(sht11_sensor); // Activate temperature sensor
 
  PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); // Wait until timer expires 
 
  printf("Data\t"); // Print the string "Data"
  sequence++;
  printf("%d\t", sequence);  // Print the sequence number
  envir.sequence = sequence; // To save the sequence in the struct envir
  printf("%d\t", temporal = get_temp()); // Print the temperature value
  envir.temp = temporal; // To save the temperature in the struct envir
  printf("%d\n", temporal = get_light());  // Print the light value
  envir.light = temporal; // To save the light in the struct envir

  process_post(&example_unicast_process, PROCESS_EVENT_CONTINUE , &(envir) ); // This function posts an asynchronous event to the process example_unicast_process with the information of the structure called envir
 
  etimer_reset(&et); // Reset timer
 
  SENSORS_DEACTIVATE(light_sensor); // Deactivate light sensor
  SENSORS_DEACTIVATE(sht11_sensor);  // Deactivate temperature sensor
 
  }
  
  PROCESS_END();//Says where the process ends

}


/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_unicast_process, ev, data) // Process for sending a unicast message
{
  PROCESS_EXITHANDLER(unicast_close(&uc);)//Specify an action when a process exits. 
    
  PROCESS_BEGIN();  // Says where the process starts

  unicast_open(&uc, 146, &unicast_callbacks);  //Opens a unicast connection

  while(1) {

    linkaddr_t addr; //Declares the addr variable
    
    PROCESS_WAIT_EVENT(); //Wait for an event to be posted to the process. 

    struct environment *envirRX =  data; //Saves the information that comes from the other process (read_temperature_light) into a structure pointer called *envirRX


    printf("Data\t"); // Print the string "Data"
    printf("%d\t", envirRX->sequence );  // Print the sequence number
    printf("%d\t", envirRX->temp ); // Print the temperature value
    printf("%d\n", envirRX->light );  // Print the light value

    packetbuf_copyfrom(  envirRX , sizeof(  (*envirRX)  ) ); 

    addr.u8[0] = 1; //This is the sink's address
    addr.u8[1] = 0; //This is the sink's address
    if(!linkaddr_cmp(&addr, &linkaddr_node_addr)) { //if the address is diferent from the current's node
      unicast_send(&uc, &addr); //Send a unicast message to the sink
    }

  }

  PROCESS_END();  //Says where the process ends
}
/*---------------------------------------------------------------------------*/




/*
 * Copyright (c) 2007, Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the Contiki operating system.
 *
 */

/**
 * \file
 *         Example of sink receiving messages from a single node
 * \author
 *         Sergio Diaz
 */

#include "contiki.h"
#include "net/rime/rime.h"

#include "dev/button-sensor.h"

#include "dev/leds.h"

#include 

#include "example-uni-temp.h" // Declares the struct environment

/*---------------------------------------------------------------------------*/
PROCESS(sink_receive, "Sink Receive"); //Through this process the Sink receives messages
 
AUTOSTART_PROCESSES(&sink_receive); //Start the process when the node boots

/*---------------------------------------------------------------------------*/
static void
recv_uc(struct unicast_conn *c, const linkaddr_t *from) //Receives the messages from the nodes and prints them
{

  printf("unicast message received from %d.%d\n",
  from->u8[0], from->u8[1]); // The sink informs from which node the message comes from

  struct environment envirRX; // Declare the structure envirRX

  packetbuf_copyto( &envirRX ); // Copy the message from the packet buffer to the structure called envirRX

  printf("Data\t"); // Print the string "Data"
  printf("%d\t", envirRX.sequence);  // Print the sequence number
  printf("%d\t", envirRX.temp); // Print the temperature value
  printf("%d\n", envirRX.light);  // Print the light value

}
static const struct unicast_callbacks unicast_callbacks = {recv_uc}; //Every time a packet arrives the function recv_uc is called
static struct unicast_conn uc; // Declares the unicast connection uc
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(sink_receive, ev, data) //Declares the protothread called sink_receive
{
  PROCESS_EXITHANDLER(unicast_close(&uc);) // Specify an action when a process exits
    
  PROCESS_BEGIN(); // Says where the process starts

  unicast_open(&uc, 146, &unicast_callbacks); //Opens a unicast connection

  while(1) {
      PROCESS_WAIT_EVENT(); //Wait for an event to be posted to the process
                            //Wait for the event of receiving a message
  }

  PROCESS_END(); //Says where the process ends
}
/*---------------------------------------------------------------------------*/



//This is the library called example-uni-temp.h
struct environment{
 
   int sequence; //To save the sequence number
   int temp; // To save the temperature value
   int light; // To save the light value

}