Monday, July 11, 2016

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
}
/*---------------------------------------------------------------------------*/



4 comments:

  1. As we execute, the first line that comes up is

    fatal: Not a git repository: '../../.git'

    why does this occur?

    ReplyDelete
  2. I tried to use this idea for my project, I get an error which says the process which used "process_post" function ,does not recognize the other process which sent data to. the exact error sentence is "undefined reference to 'process_thread_receive_process' ". do you know how to fix it?

    ReplyDelete
  3. hi, I'm a Halima. I executed the programme of DV-HOP with contiki cooja, in the first step I got good result but when I repeat the simulation with another value I didn't get any results.please help me to resolve this problem .
    halima.ghribi33@gmail.com

    ReplyDelete
  4. hi, I want to implement an algorithm that can calculate the complexity of DV-HOP.please help me .
    email: halima.ghribi33@gmail.com

    ReplyDelete