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

}

1 comment: