Monday, December 12, 2016

How to improve the packet reception rate of your sky nodes

Objective

The objective of this tutorial is to improve the packet reception rate of your sky nodes. For this tutorial, i am going to be using sky CM5000 nodes, Contiki V3.x and Lubuntu 16.04.

Problem

In this section i am going to describe the problem that i had with the CM5000 sky nodes. When i got my CM5000 nodes, the first thing that i wanted to test was sending a unicast message from node 2 to node 1. To that end, i used an example from the rime stack named example-unicast.c located in /home/YOUR_USER/Desktop/contiki/examples/rime. This example is very straightforward since it sends unicast messages from a node to node 1. However, when you run this example you have to make sure that a node within the network has address 1. In order to set one node with address 1, you can see the following tutorial:

http://contiki-iot.blogspot.com.co/2016/06/setting-node-id-for-sky-motes.html

The unicast rime example runs fine. You can see that the messages from node 2 to node 1 arrives. However, the problem is that a huge amount of messages are lost. You may wonder why. Why a huge amount of messages are lost in a simple unicast message sent from node 2 to node 1? What is the problem with the rime unicast example?

Solution to the problem

At first i thought that the wireless channel had a lot of interference. Then, i read in the book Internet of things in 5 days (link below) that wireless channels 15, 20, 25 and 26 do not overlap with WiFi. Besides, the default wireless channel used by Contiki rime is 26, hence, there should not be any interference problems. Additionally, i used the Spectrum Analizer Application available in Contiki, (which is explained in the link below) and i realized that there were no other transmissions in channel 26. In conclusion, the problem was not interference on the wireless channel. So, what was the problem? Why a huge amount of messages were lost when using the rime unicast example?

http://wireless.ictp.it/school_2015/book/#_ieee_802_15_4_channels_and_pan_id

After discarding wireless interference, i started reading about the Contiki stack (See link below). Then, i realized that there was a layer called Radio Duty Cycling which was in charge of turning the radio on and off to save energy.

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

The default Radio Duty Cycling used by Contiki is called ContikiMAC. To understand the ContikiMAC, please go to the following link:

https://github.com/contiki-os/contiki/wiki/Radio-duty-cycling

After reading the above link, i understood that the receivers periodically turn on their radios to inspect for messages in the channel. So, the answer to my problem was: A lot of messages are lost in the rime unicast example because the receiver node (node 1) does not poll the radio medium with the appropriate frecuency. So, i increased the polling rate and no more messages were lost. In Contiki the polling rate is referred as RDC_CHANNEL_CHECK_RATE. It is important to notice that the RDC_CHANNEL_CHECK_RATE is proportional to the energy consumption of the nodes, i.e. if the node has a higher RDC_CHANNEL_CHECK_RATE, then it will consume more energy.

Implementation of the solution

Before you implement the solution, you must be aware that it will increase the energy consumption of the nodes.

In order to implement the solution all you have to do is to increase the RDC_CHANNEL_CHECK_RATE. In order to do so, you must first create a project configuration file project-conf.h (Please do the following tutorial) :

http://contiki-iot.blogspot.com.co/2016/07/project-configuration-example.html

In the above tutorial i created a project configuration file and changed the necessary stuff to make it work. Besides, in the above tutorial, i changed the radio channel from 26 to 20. But in this tutorial i want to change the RDC_CHANNEL_CHECK_RATE. To do so, just add the following line to your project-conf.h file.

#define NETSTACK_CONF_RDC_CHANNEL_CHECK_RATE 128 //Change the rate at which the node check for radio activity in the channel

The above line says that the node will turn the radio on 128 times per second to check whether there is a packet in the channel. The default RDC_CHANNEL_CHECK_RATE is 8. So, increasing the check frequency to 128 ensures that no packet is lost.

Verify the solution

To verify that the changes were made do this: 1) upload the unicast rime example to a sky node, 2) connect to it via a serial port, 3) the reboot the node manually. You can do the first 2 steps with this command line:

make clean && make TARGET=sky example-unicast.upload && make login

After manually rebooting the node, you should see this:

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 128 Hz, radio channel 20
Starting 'Example unicast'

This is the message shown by the node when it is rebooted. This message shows that the RDC_CHANNEL_CHECK_RATE is equal to 128: channel check rate 128 Hz . If you see that message then your problem is solved. You must not have any lost packets.

Friday, December 2, 2016

How to calculate the latency in Contiki OS

Objective

In this tutorial i am going to show you how to calculate the latency of a packet in a wireless link. I am using Contiki v3.x, sky (CM5000) nodes and lubuntu 16.04. First of all, to compute the latency of a packet you need to have the nodes synchronized. In order to synchronize the nodes of the network, you can use the Implicit Network Time Synchronization of Contiki, which i explain in the following tutorial:

http://contiki-iot.blogspot.com.co/2016/11/implicit-network-time-synchronization_28.html

It means that you must to do the above tutorial if you want to calculate the latency of a packet.

NOTE: Since the Implicit Network Time Synchronization mechanism of Contiki only works on sky nodes, this latency computation only works on sky nodes too.

Step 1: Synchronize your nodes

As mentioned above, you must have your nodes synchronized to calculate the latency of a packet. In order to synchronize your nodes, go to the following tutorial:

http://contiki-iot.blogspot.com.co/2016/11/implicit-network-time-synchronization_28.html

Step 2: Modify your example-broadcast.c

I am going to calculate the latency of a packet in the broadcast rime example. I got the basic idea from an example named shell-rime-debug.c which is located in /home/YOUR_USER/Desktop/contiki/apps/shell. So, you can go and check that file in order to get the information directly from a contiki source file.

Next, i am going to explain the changes that i made to the example-broadcast.c file:

  • Create a latency structure: We create a latency structure to save the timestamp of the message, i.e. the time when the message was sent.
  • Send a broadcast with the timestamp: The normal/original example-broadcast.c file sends a broadcast with a 'hello' message, in this tutorial, we are going to send a broadcast with the timestamp. So, we comment/delete the 'hello' message and add our timestamp to the broadcast.
  • Receive a broadcast with the timestamp and compute the latency: We receive the broadcast that includes the timestamp. Then, we compute the time difference between the current time (timesynch_time()) and the broadcast timestamp (msg.timestamp), that difference (timesynch_time() - msg.timestamp) is equal to the latency.

Now, we show you the full code:

/*
 * 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
 *         Testing the broadcast layer in Rime
 * \author
 *         Adam Dunkels 
 */

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

#include "dev/button-sensor.h"

#include "dev/leds.h"

#include 


/*--------------------------------------*/

struct latency_structure{ // Structure to save the time when the message was send

   rtimer_clock_t timestamp;// Time when the message was send

};
/*---------------------------------------------------------------------------*/
PROCESS(example_broadcast_process, "Broadcast example");
AUTOSTART_PROCESSES(&example_broadcast_process);
/*---------------------------------------------------------------------------*/

//Receive a broadcast with the timestamp and compute the latency
static void
broadcast_recv(struct broadcast_conn *c, const linkaddr_t *from)
{
  struct latency_structure msg;
  rtimer_clock_t latency;

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

#if TIMESYNCH_CONF_ENABLED
  latency = timesynch_time() - msg.timestamp;
#else
  latency = 0;
#endif

  printf("broadcast message received from %d.%d with latency %lu ms\n",
         from->u8[0], from->u8[1], (1000L * latency) / RTIMER_ARCH_SECOND );
}
static const struct broadcast_callbacks broadcast_call = {broadcast_recv};
static struct broadcast_conn broadcast;
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_broadcast_process, ev, data)
{
  struct latency_structure *msg;

  static struct etimer et;

  PROCESS_EXITHANDLER(broadcast_close(&broadcast);)

  PROCESS_BEGIN();

  broadcast_open(&broadcast, 129, &broadcast_call);

  while(1) {

    /* Delay 2-4 seconds */
    etimer_set(&et, CLOCK_SECOND * 4 + random_rand() % (CLOCK_SECOND * 4));

    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

#if TIMESYNCH_CONF_ENABLED
      msg->timestamp = timesynch_time();
#else
      msg->timestamp = 0;
#endif

    // Do not send the normal/original 'hello' message. Instead, send a message with the timestamp.
    packetbuf_copyfrom(msg,   sizeof(*msg) ); // This message msg includes the timestamp
    //packetbuf_copyfrom("Hello", 6);
    broadcast_send(&broadcast);
    printf("broadcast message sent\n");
  }

  PROCESS_END();
}
/*---------------------------------------------------------------------------*/


Step 3: Upload the code to 2 or more sky nodes

Since the Implicit Network Time Synchronization mechanism of Contiki only works on sky nodes, this latency computation only works on sky nodes. In order to upload the code to the sky nodes, do this:

make clean && make TARGET=sky example-broadcast.upload && make login

If everything is working correctly you should see a message like this:

broadcast message received from X.X with latency 1167 ms

When i tested the code the latency varies from 12ms to 1652 ms. Notice that X.X is the address of the node that sent the broadcast. In my example, the sky node has address 185.144

Monday, November 28, 2016

Implicit Network Time Synchronization - timesynch file

Objective

In this tutorial, i am going to show you how to use the Implicit Network Time Synchronization of Contiki OS in real nodes. I am using the sky motes CM5000, Contiki OS v3.x and Lubuntu v16.04. It is important to notice that this synchronization mechanism only works in sky nodes.

Background

The Implicit Network Time Synchronization is implemented in Contiki via 2 files: timesynch.c and timesynch.h

/home/YOUR_USER/Desktop/contiki/core/net/rime/timesynch.c
/home/YOUR_USER/Desktop/contiki/core/net/rime/timesynch.h

If you want to get a deep understanding of the synchronization mechanism, please read the following 2 references:

http://anrg.usc.edu/contiki/images/f/fd/Time_Synchronization.pdf

http://dunkels.com/adam/chen07time.pdf

The first link is a presentation that explains the synchronization mechanism very clearly, and the second link is a paper of Adam Dunkels (The author of the timesynch.c.h files). Now, i am going to explain in my own words the synchronization mechanism.

Synchronization Mechanism in my own words

How the CM5000 sky mote counts the time? To count time the CM5000 sky node has a 16-bit timer (TIMER_A) capable of counting from 0 to 65535. In every clock tick the counter is incremented in 1. Besides, when the TIMER_A is equal to 32768, then 1 second has passed. And when the TIMER_A is equal to 65536, then 2 seconds has passed. Notices, than when TIMER_A = 65536, it overflows and goes back to 0 (because we have a 16-bit timer). Hence, this timer is only capable of counting up to 2 seconds, then it overflows.

How to synchronize 2 nodes? If you want to synchronize 2 nodes, then the TIMER_A of both of them must have the same value. Usually, both timers do not have the same value because it is virtually impossible to reset the 2 nodes at the same time to make that both timers start from 0 at the same time. Besides, the clock tick can be slightly different between the 2 sensor nodes. Hence, in order to synchronize the 2 nodes the timesynch file constantly sends a broadcast synchronization message that compares the TIMER_A from node 1 and the TIMER_A from node 2.

How does timesynch file work? This file constantly sends a broadcast synchonization message that compares the TIMER_A from node 1 and the TIMER_A from node 2. The difference between those values is called the offset. Let me say here, that the 2 nodes have an important parameter called Authority level, which is used to determine which node has the reference time. Here, i am going to establish that the Node ID is equal to the authority level (You can assign the authority level any way you want). The node whose authority level is lower will be the owner of the reference time. In this example (See Figure below), node 1 has an authority level of 1, hence, it is the owner of the reference time. It means that if node 1 has a TIMER_A = 15, this will be the actual time of the network, and the other nodes will have to modify their TIMER_A (by summing the offset) to agree with this time. In the next figure, i assume that node 2 has a TIMER_A = 10. Therefore, the offset (difference between node1's TIMER_A (15) and node2's TIMER_A (10) = 15 - 10 = 5 ) is equal to 5. In conclusion, the actual time of the network is node1's TIMER_A = 15, and node 2 corrects its timer by summing the offset (10 + 5 = 15), then both nodes think they synchronized (they have the same time of 15).

Test the rime broadcast example

In this section, i am just going to upload the rime broadcast example in 2 sensor nodes. In the next section i am going to enable the Implicit Network Time Synchronization for this broadcast example.

Here, i am going to use the broadcast example from rime, hence, open the following file:

cd /home/YOUR_USER/Desktop/contiki/examples/rime/
gedit /home/YOUR_USER/Desktop/contiki/examples/rime/example-broadcast.c

This file just sends a broadcast message every 2 to 4 seconds. Clean, compile and upload this file to 2 nodes using the following command:

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

Note that i am using TARGET=sky since i am working with sky CM5000 nodes (The Implicit Network Time Synchronization mechanism only works on sky nodes ). Then look to which serial your nodes are connected using this:

make TARGET=sky sky-motelist

Notice one device from the list, for example, the /dev/ttyUSB0. Then connect to one of your nodes to see the arriving broadcast messages:

make TARGET=sky login MOTES=/dev/ttyUSB0

If the broadcast messages are arriving correctly, then you should see this:

broadcast message received from X.X: 'hello'
broadcast message sent

where, X.X is the address of the node that sends the message, for example, 185.144 or another number ( This number does not really matter). Besides, you see that the node connected to /dev/ttyUSB0 is actually sending messages: broadcast message sent.

Enable Implicit Network Time Synchronization for the rime broadcast example

To enable the Implicit Network Time Synchronization, you must create a project-conf.h file as follows:

cd /home/YOUR_USER/Desktop/contiki/examples/rime/
> project-conf.h
gedit /home/YOUR_USER/Desktop/contiki/examples/rime/project-conf.h

The above does: 1) go to the directory of rime, 2)Create the project-conf.h file, 3) Open the file. Then, in the recently opened file copy this:

#ifndef __PROJECT_CONF_H__
#define __PROJECT_CONF_H__

//Define the network stack
#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     nullrdc_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. 

#undef TIMESYNCH_CONF_ENABLED  // TO ENABLE THE Implicit Network Time Synchronization
#define TIMESYNCH_CONF_ENABLED 1 // TO ENABLE THE Implicit Network Time Synchronization

//Define the channel to be used
#define RF_CHANNEL 20

#endif /* __PROJECT_CONF_H__ */

The lines that actually enable the Implicit Network Time Synchronization are only 2, and the rest is optional (Another configuration parameters). If you just want to enable the Synchronization mechanism, then copy the following lines in your project-conf.h file.

#ifndef __PROJECT_CONF_H__
#define __PROJECT_CONF_H__

#undef TIMESYNCH_CONF_ENABLED  // TO ENABLE THE Implicit Network Time Synchronization
#define TIMESYNCH_CONF_ENABLED 1 // TO ENABLE THE Implicit Network Time Synchronization

#endif /* __PROJECT_CONF_H__ */

Now, modify your Makefile, and include the following line:

CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"

To modify your Makefile do this:

cd /home/YOUR_USER/Desktop/contiki/examples/rime/
gedit /home/YOUR_USER/Desktop/contiki/examples/rime/Makefile

Copy and paste this line CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\", and your Makefile should look like this:

CONTIKI = ../..

all: unmodulated_carrier 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

Then, you need to modify the contiki-conf.h file by doing this:

cd /home/YOUR_USER/Desktop/contiki/platform/sky
gedit /home/YOUR_USER/Desktop/contiki/platform/sky/contiki-conf.h

In the recently opened file cut this lines:

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

And paste them at the beginning of the contiki-conf.h file, then your file must look like this:


// START OF FILE (THIS IS A NOTE FROM THIS BLOG)

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

// ANOTHER STUFF (THIS IS A NOTE FROM THIS BLOG)

That's it. You have enabled the Implicit Network Time Synchronization in Contiki.

See Debug Messages for the Implicit Network Time Synchronization

To see debug messages open the timesynch.c and add the following line at the end of the broadcasr_recv function:

printf("broadcast_recv, timesynch_offset = %u timesynch_authority_level = %d \n\r", timesynch_offset(), timesynch_authority_level());

Hence, your broadcasr_recv function should look like this:

static void
broadcast_recv(struct broadcast_conn *c, const linkaddr_t *from)
{
  struct timesynch_msg msg;

  memcpy(&msg, packetbuf_dataptr(), sizeof(msg));

  /* We check the authority level of the sender of the incoming
       packet. If the sending node has a lower authority level than we
       have, we synchronize to the time of the sending node and set our
       own authority level to be one more than the sending node. */
  if(msg.authority_level < authority_level) {
    adjust_offset(msg.timestamp + msg.authority_offset,
                  packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP));
    timesynch_set_authority_level(msg.authority_level + 1);
  }

  printf("broadcast_recv, timesynch_offset = %u timesynch_authority_level = %d \n\r", timesynch_offset(), timesynch_authority_level());

}

Now, go to the step Test the rime broadcast example and run the broadcast example again. You should see the printf that we just added that shows the offset and the authority level of each node when a synchronization broadcast arrives:

broadcast_recv, timesynch_offset = {0-65535} timesynch_authority_level = {AUTHORITY_VALUE}

Notice that you can modify the timesynch_authority_level with the function timesynch_set_authority_level. If you see the message above, then you successfully configured your Implicit Network Time Synchronization mechanism.

NOTE: It is important that you notice that in this example there are 2 kinds of broadcasts. The first kind of broadcast is the 'hello' message sent by the rime example (example-broadcast.c). The second kind of broadcast is the synchronization message sent by the timesynch.c file

Wednesday, November 16, 2016

How to clone Contiki OS from Github using git

Objective

To clone the Contiki OS software from Github. Then, to upload the Contiki files to your own Github repository.

Step 1: Clone the Contiki OS software from Github

To clone Contiki OS from github, go to your desktop directory and clone Contiki as follows:

cd /home/YOUR_USER/Desktop/
git clone https://github.com/contiki-os/contiki.git

After this step, the following directory was created /home/YOUR_USER/Desktop/contiki. That's it, you are done! Now, you can develop your own applications under Contiki. If you want to upload the Contiki files to your own Github repository see the next step.

Step 2: Upload the Contiki files to your own Github repository

If you develop applications for Contiki and want to save this files in your own Github repository, read this section. First you need to create your own repository, and to do so, see the following link, specifically see the section Create a new repository on GitHub:

https://help.github.com/articles/create-a-repo/

Then, 1) Go to your contiki folder 2) Add your remote repository, 3) Verify that it was added, 4) upload the Contiki files to your repository with the push command:

cd /home/YOUR_USER/Desktop/contiki
git remote add NAME_YOU_CHOOSE https://github.com/YOUR_GITHUB_USER/YOUR_GITHUB_REPOSITORY.git
git remote -v
git push -u NAME_YOU_CHOOSE master

After the push command, you must introduce your Github user and password. Then, go to your Github repository and verify that the file were uploaded, you must see this:

Now, we are going to create a new folder named MyExample, and a file named example.c

cd /home/YOUR_USER/Desktop/contiki/examples/
mkdir MyExample
cd /home/YOUR_USER/Desktop/contiki/examples/MyExample
> example.c

Next, we are going to: 1) see the status of the git 2) Add all the changes to Github 3) Commit the changes 4) Upload the changes with the push command.

git status
git add -A
git commit -m "This is the Commit Message"
git push -u NAME_YOU_CHOOSE master

After the push command, you must introduce your Github user and password. That's it, you are done! Now, go to your Github page, and look for the folder /YOUR_GITHUB_REPOSITORY/examples/MyExample and its file example.c.

Sunday, November 13, 2016

Setting node ID for the re-mote (zoul)

Objective

The objective of this tutorial is to set up the id of the re-motes from Zolertia using Contiki-3.0. I am using the RIME stack for this example.

Procedure

To find a comprehensive explanation of how to set up the node ID of the re-motes please go to this link and see section Node IEEE/RIME/IPv6 Addresses

https://github.com/contiki-os/contiki/tree/master/platform/zoul

If you want to set up the re-mote address at compilation time you could simply add NODEID=YOUR_ADDRESS when uploading the code to the node, as follows:

make NODEID=0x0001 TARGET=zoul sink-channelQuality.upload

This line configured the rime address to 00:01, and when you reset the node, then you can see the following:

Contiki-2.6-4041-gaad203e
Zolertia RE-Mote revision B platform
CC2538: ID: 0xb964, rev.: PG2.0, Flash: 512 KiB, SRAM: 32 KiB, AES/SHA: 1, ECC/RSA: 1
System clock: 16000000 Hz
I/O clock: 16000000 Hz
Reset cause: External reset
Rime configured with address 00:01
Net: Rime
MAC: CSMA
RDC: ContikiMAC

It is important to notice the line Rime configured with address 00:01, which says that we just changed the rime address of the re-mote.

Wednesday, August 10, 2016

Generate an improved interfering node in Contiki OS

Objective

The objective of this post is to make an improved version of the interfering node that i made in a previous tutorial:

http://contiki-iot.blogspot.com.co/2016/08/objective-to-create-interfering-node.html

The previous tutorial just generates an unmodulated carrier as noise, i would like to mention that i got the idea and part of the code from the paper [2]. Now, in this tutorial i improved this version of interfering node adding a model of interference called Bursty Interference described in the section 3.3 of paper [1]. The model just turns the unmodulated carrier on and off with different time periods (t1 and t2). For example, it turns the carrier on for 240ms (t1 = 240ms) and then it turns the carrier off for 510ms (t2 = 510ms); the times t1 and t2 follow a uniform distribution between 0 seconds and 1,5 seconds. I strongly recommend you to read the paper [1].

Code for the sky mote

Below i show you the code that implements the improved interfering node. I order to understand the code you must read section 3.3 of the paper [1], i try to add comments to the code and use the same variables that the paper did.

/*
 * 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
 *       Improved example of an interfering node
 * \author
 *        Sergio Diaz
 */


/*INCLUDES*/
#include "contiki.h"
#include "/home/sink/Desktop/contiki-3.0/dev/cc2420/cc2420_const.h" // Include the CC2420 constants 
#include "/home/sink/Desktop/contiki-3.0/core/dev/spi.h" // Include basic SPI macros
#include "dev/leds.h" // Include Leds to debbug
#include "sys/rtimer.h" //Include the real time library

/*DEFINES*/
#define INTERFERENCE  0x01 // I set the less significant bit to indicate there is interference (0x01 = 00000000 00000001)
#define CONSTANT_MICROS 300 // 300 us was defined by the paper [1]
#define TIME_TICK 31 // The time of 1 tick is 30,51 us in rtimer for sky motes in Contiki v3.0. TIME_TICK = 1 / RTIMER_ARCH_SECOND = 1 / 32768 s


/*STRUCT DEFINITIONS*/
struct states{
 unsigned char carrier; // Defines the state of the carrier: Either INTERFERENCE = 0x01 or Not INTERFERENCE = ~0x01
};

struct states state; //Create the state of the carrier
static struct rtimer rtimer; // Create the rtimer variable

/*FUNCTION DEFINITIONS*/

/*---------------------------------------------------------------------------*/
/*
* Generate a random number between 0 and (MaxValue - 1)
*/
unsigned int random_number(unsigned int MaxValue){
       return  rand() % MaxValue;
}
/*---------------------------------------------------------------------------*/
/** 
 * Writes to a register.
 * Note: the SPI_WRITE(0) seems to be needed for getting the
 * write reg working on the Z1 / MSP430X platform
 */
static void
setreg(enum cc2420_register regname, uint16_t value)
{
  CC2420_SPI_ENABLE();
  SPI_WRITE_FAST(regname);
  SPI_WRITE_FAST((uint8_t) (value >> 8));
  SPI_WRITE_FAST((uint8_t) (value & 0xff));
  SPI_WAITFORTx_ENDED();
  SPI_WRITE(0);
  CC2420_SPI_DISABLE();
}

/* Sends a strobe */
static void
strobe(enum cc2420_register regname)
{
  CC2420_SPI_ENABLE();
  SPI_WRITE(regname);
  CC2420_SPI_DISABLE();
}

/*
* Function called by the rtimer to turn the carrier on and off.
*/
static void carrier_OnOff(struct rtimer* timer, void* ptr)
{

    unsigned int R; // Uniformly distributed over [1,100]
    unsigned int Qx;  // Uniformly distributed over [1,x], where x = 50
    unsigned int randNum; // Random number between [1-10]
    uint32_t time_next_period; // Next time period. The duration of the interference or not interference state.
    uint32_t num_ticks; // Number of ticks of the time_next_period

    // Calculate a random number between [1-10]
    randNum = 1 + abs( random_number(10) ) ;
    
    // Decide whether to produce interference or not with equal probability (0.5)
    if( randNum <= 5) // If the random number is less than 5 generate no interference 
    {
        // In this case there will be no interference
        state.carrier &= ~INTERFERENCE; // Set the carrier state to no interference (NOT INTERFERENCE)
    }else{
        // In this case there will be interference
        state.carrier |= INTERFERENCE; // Set the carrier state to interference
    }

    // Turn the unmodulated carrier on or off depending on the carrier state (state.carrier)
    if( state.carrier & INTERFERENCE) // should the node generate interference?
    {
       //The node must generate interference. Turn the carrier on.
       // Creates an unmodulated carrier by setting the appropiate registers in the CC2420
       setreg(CC2420_MANOR, 0x0100); 
       setreg(CC2420_TOPTST, 0x0004);
       setreg(CC2420_MDMCTRL1, 0x0508);
       setreg(CC2420_DACTST, 0x1800);
       strobe(CC2420_STXON);
       // Turn the leds for debug. LEDS_RED on means there is interference
       leds_on(LEDS_RED);
       leds_off(LEDS_GREEN);

    }else{
       //The node must not generate interference. Turn the carrier off.
       //Reset the changes and set back the CC2420 radio chip in normal mode.
       //Not generate unmodulated carrier
       setreg(CC2420_MANOR, 0x0000);
       setreg(CC2420_TOPTST, 0x0010);
       setreg(CC2420_MDMCTRL1, 0x0500);
       setreg(CC2420_DACTST, 0x0000);
       strobe(CC2420_STXON);
       // Turn the leds for debug. LEDS_GREEN on means there is no interference
       leds_on(LEDS_GREEN);
       leds_off(LEDS_RED);
    }
    // Calculate the time of the next period ( time_next_period = R*Q(x)*CONSTANT_MICROS ) 
       R  = 1 +  abs( random_number(100) )  ; // Generate random numbers between [1,100]
       Qx = 1 +  abs(random_number(50))   ; // Generate random numbers between [1,50]
       time_next_period = R * Qx ; // Compute the next time period according to the paper [1]
       time_next_period = time_next_period * CONSTANT_MICROS ;  // Compute the next time period according to the paper [1]


    // Set the rtimer to the time_next_period (num_ticks)
       num_ticks = time_next_period / TIME_TICK; // Compute the number of ticks that corresponds to time_next_period
       printf("Interference = %d ,R = %d, Qx = %d, time = %lu, ticks =  %lu \n", state.carrier & INTERFERENCE, R, Qx, time_next_period, num_ticks); // View the results in console
       rtimer_set(&rtimer, RTIMER_NOW() + num_ticks , 1, carrier_OnOff, NULL);// Set the rtimer again to the time_next_period (num_ticks)
}


/*---------------------------------------------------------------------------*/

PROCESS(turn_carrier_OnOff, "Turn Carrier On Off"); // Declares the process to turn the carrier on and off
AUTOSTART_PROCESSES( &turn_carrier_OnOff); // Load the process on boot

PROCESS_THREAD(turn_carrier_OnOff, ev, data) // Process to turn carrier on and off
{ 
   
  PROCESS_BEGIN(); // Says where the process starts

  rtimer_set(&rtimer, RTIMER_NOW() + RTIMER_ARCH_SECOND, 1, carrier_OnOff, NULL); //Initiates the rtimer 1 second after boot

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

/*---------------------------------------------------------------------------*/


Video

I created an unmodulated carrier at channel 20 and to visualize the signal i am using the rssi-scanner provided by Contiki. The vertical node is the interfering one. When the interfering node's red led is on, then the carrier at channel 20 appears; and when the interfering node's green led is on, then the carrier at channel 20 disappears. The time of carrier on/off is a uniform distribution between 0 and 1,5 seconds.

References

[1] Boano, Carlo Alberto; Voigt, Thiemo; Tsiftes, Nicolas; Mottola, Luca; Römer, Kay; Zúñiga, Marco Antonio. Making Sensornet MAC Protocols Robust against Interference. Proceedings of the Wireless Sensor Networks: 7th European Conference - EWSN, Coimbra, Portugal, February 17-19, 2010, pp. 272-288.

[2] C. A. Boano, Z. He, Y. Li, T. Voigt, M. Zúñniga and A. Willig, "Controllable radio interference for experimental and testing purposes in Wireless Sensor Networks," 2009 IEEE 34th Conference on Local Computer Networks, Zurich, 2009, pp. 865-872.

Timers: etimer and rtimer - lowest resolution in us and ms

Objective

The objective of this tutorial is to understand which is the lowest resolution that etimer(ms) and rtimer(us) can provide. In order to do this tutorial i used sky motes, however, the same procedure applies to other architectures. I tested the code in Contiki v3.0 and lubuntu 16.04.

Some Background

The lowest resolution of the etimer is given by the CLOCK_SECOND constant, and for the rtimer is given by the RTIMER_ARCH_SECOND constant. The formula for obtaining the lowest etimer resolution is 1 / CLOCK_SECOND seconds, and for obtaining the lowest rtimer resolution is 1 / RTIMER_ARCH_SECOND seconds. Or in Adam Dunkels' words "The only constant is the RTIMER_ARCH_SECOND. I.e., if you have a hardware timer that runs at 32768Hz, the rtimer units is 1/32768 s and RTIMER_ARCH_SECOND is 32768" (See Reference [1] below).

Check the CLOCK_SECOND and the RTIMER_ARCH_SECOND value

So, in order to know the lowest etimer and rtimer resolution you need to know the value of the CLOCK_SECOND and RTIMER_ARCH_SECOND constants, respectively. Following this, to print that values in console you must run the following code in one node. The code creates the #define SHOW_DEFINE(x), which is used to print the values of the constants CLOCK_SECOND and RTIMER_ARCH_SECOND

/*
 * 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
 *       Show CLOCK_SECOND and RTIMER_ARCH_SECOND values
 * \author
 *        Sergio Diaz
 */


/*INCLUDES*/
#include "contiki.h"

//Show #define values: To USE them put it in the process like this: // SHOW_DEFINE(CLOCK_SECOND); // SHOW_DEFINE(RTIMER_ARCH_SECOND);
#define STR(x) #x
#define SHOW_DEFINE(x) printf("%s=%s\n", #x, STR(x))


/*---------------------------------------------------------------------------*/

PROCESS(show_define_values, "Show define values"); // Declares the process to show the #define values
AUTOSTART_PROCESSES( &show_define_values); // Load the process on boot

PROCESS_THREAD(show_define_values, ev, data) // Start of the process to show the #define values
{ 
  static struct etimer et;
  PROCESS_BEGIN(); // Says where the process starts

  while(1)
  {
    //Printf value every 1 second
    etimer_set(&et, CLOCK_SECOND);

    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); //Wait for etimer (et) to expire

    SHOW_DEFINE(CLOCK_SECOND); // Show the value of the CLOCK_SECOND in console. To be aware of the etimer resolution
    SHOW_DEFINE(RTIMER_ARCH_SECOND); // Show the value of the RTIMER_ARCH_SECOND in console. To be aware of the rtimer resolution
    printf("\n"); //Printf a "\n"
  }

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

/*---------------------------------------------------------------------------*/

When you run this code in a Sky mote and view the messages in the console, then you will see this:

CLOCK_SECOND=128UL
RTIMER_ARCH_SECOND=(4096U*8)

That means that the CLOCK_SECOND value is 128 Unsigned (U) Long (L), and that the RTIMER_ARCH_SECOND value is 4096 Unsigned (U) * 8, it means RTIMER_ARCH_SECOND value is 32768. So the lowest resolution for etimer is 1 / CLOCK_SECOND = 1 / 128 s = 7,8125 ms. Besides, the lowest resolution for rtimer is 1 / RTIMER_ARCH_SECOND = 1 / 4096U*8 = 1 / 32768 = 30,5175 us.

Example Setting etimer and rtimer

If you want to set the etimer and rtimer to the lowest resolution in the sky mote you can do the following.

etimer_set(&et, (CLOCK_SECOND / 128) ); //The etimer expires in 7,8125 ms
rtimer_set(&rtimer, RTIMER_NOW() + (RTIMER_ARCH_SECOND / 32768) , 1, carrier_OnOff, NULL);// The rtimer expires in 30,5175 us

You can not use a bigger number than 128 to divide the CLOCK_SECOND, and you can not use a bigger number than 32768 to divide the RTIMER_ARCH_SECOND; because you can not have a bigger resolution without changing the default behaviour of the sky node. If you want the timers to expire in 0,5 seconds you can do this:

etimer_set(&et, (CLOCK_SECOND / 2) ); //The etimer expires in 0,5 s
rtimer_set(&rtimer, RTIMER_NOW() + (RTIMER_ARCH_SECOND / 2) , 1, carrier_OnOff, NULL);// The rtimer expires in 0,5 s

References

[1] https://sourceforge.net/p/contiki/mailman/message/18577635/

Sunday, August 7, 2016

Generate an interfering node in Contiki OS

Objective

To create an interfering node using a sky CM5000 node that has a CC2420 radio. The interference will be created using an unmodulated carrier. I used the paper [1] to get the code and the idea. I strongly recommend you reading the paper [1] if you want to make a serious study of interference in WSN. I tested the code using Contiki v3.0 and lubuntu 16.04.

Step 1: To disable the MAC layer of the node

The first step in order to create an unmodulated carrier (interference) is to disable the MAC layer of Contiki. To that end, you must create a file named project-conf.h. I am going to create that file in the RIME directory because that is where i am working:

/home/YOURUSER/contiki-3.0/examples/rime/project-conf.h

Within project-conf.h you must disable the MAC by selecting the null mac driver and the null rdc driver. If you want more information about the Contiki communication stack please read the information provided by the following link:

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

Then, your project-conf.h must look like this:

#define NETSTACK_CONF_MAC     nullmac_driver // Define the MAC driver to use
#define NETSTACK_CONF_RDC     nullrdc_driver // Define the RDC driver to use
In order that Contiki reads the information that your project-conf.h file contains, then you must insert the following line CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" in the Makefile, which is located in the rime directory (where we are working). Consequently, 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
Now, you have disabled the MAC layer of your interfering node. If you load the Rime broadcast example in your node (example-broadcast.c), then you will see the nullmac and the nullrdc configured (see the code below). The following link explains in detail how to create the project-conf.h file, but this example changes the radio channel, not the MAC layer.

http://contiki-iot.blogspot.com.co/2016/07/project-configuration-example.html

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 nullmac nullrdc, channel check rate 8 Hz, radio channel 20           
Starting 'Broadcast example'

Step 2: To generate an unmodulated carrier

In order to generate an unmodulated carrier i used the idea and the code from the paper [1]. I show you the complete Contiki code:
/*
 * 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 an interfering node
 * \author
 *        Sergio Diaz
 */

#include "contiki.h"

#include "/home/sink/Desktop/contiki-3.0/dev/cc2420/cc2420.h" // Include the CC2420 library
#include "/home/sink/Desktop/contiki-3.0/dev/cc2420/cc2420_const.h" // Include the CC2420 constants 
#include "/home/sink/Desktop/contiki-3.0/core/dev/spi.h" // Include basic SPI macros

/*---------------------------------------------------------------------------*/
PROCESS(unmodulated_carrier, "CC2420 Unmodulated Carrier"); // Declares the process unmodulated_carrier
AUTOSTART_PROCESSES(&unmodulated_carrier); // Load the process on boot

/*---------------------------------------------------------------------------*/
/** 
 * Writes to a register.
 * Note: the SPI_WRITE(0) seems to be needed for getting the
 * write reg working on the Z1 / MSP430X platform
 */
static void
setreg(enum cc2420_register regname, uint16_t value) // Set the register of the cc2420 radio
{
  CC2420_SPI_ENABLE();
  SPI_WRITE_FAST(regname);
  SPI_WRITE_FAST((uint8_t) (value >> 8));
  SPI_WRITE_FAST((uint8_t) (value & 0xff));
  SPI_WAITFORTx_ENDED();
  SPI_WRITE(0);
  CC2420_SPI_DISABLE();
}

/* Sends a strobe */
static void
strobe(enum cc2420_register regname)
{
  CC2420_SPI_ENABLE();
  SPI_WRITE(regname);
  CC2420_SPI_DISABLE();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(unmodulated_carrier, ev, data) // Defines the process unmodulated_carrier
{

  PROCESS_BEGIN();  // Says where the process starts

  // Creates an unmodulated carrier
  setreg(CC2420_MANOR, 0x0100);
  setreg(CC2420_TOPTST, 0x0004);
  setreg(CC2420_MDMCTRL1, 0x0508);
  setreg(CC2420_DACTST, 0x1800);
  strobe(CC2420_STXON); 

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


I tested the interfering node in the following set up. I have three nodes: a sink, a temperature node and an interfering node. The temperature node sends its data to the sink via radio, then i observe in the sink that the messages arrive without problem. Then, i turn the interfering node on and i suddenly observe that no more packets arrive. If i turn the interfering node off then the packets arrive again with no problem. Consequently, the interfering node introduces noise in the communication between the sink and the temperature node. This noise (an unmodulated carrier) is so strong that no more packets arrive to the sink. If you want a more sophisticated interfering node i strongly recommend you to read the paper [2] and make my tutorial named Generate an improved interfering node in Contiki OS located in the following link.

http://contiki-iot.blogspot.com.co/2016/08/generate-improved-interfering-node-in.html

Reset the CC2420 to normal behaviour

When you are done using your interfering node, then you must reset the CC2420's register to normal behaviour. To that end, you must run the following code in your node:
/*
 * 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 an interfering node
 * \author
 *        Sergio Diaz
 */

#include "contiki.h"

#include "/home/sink/Desktop/contiki-3.0/dev/cc2420/cc2420.h" // Include the CC2420 library
#include "/home/sink/Desktop/contiki-3.0/dev/cc2420/cc2420_const.h" // Include the CC2420 constants 
#include "/home/sink/Desktop/contiki-3.0/core/dev/spi.h" // Include basic SPI macros

/*---------------------------------------------------------------------------*/
PROCESS(reset_cc2420_registers, "CC2420 Reset Registers"); // Declares the process reset_cc2420_registers
AUTOSTART_PROCESSES(&reset_cc2420_registers); // Load the process on boot

/*---------------------------------------------------------------------------*/
/** 
 * Writes to a register.
 * Note: the SPI_WRITE(0) seems to be needed for getting the
 * write reg working on the Z1 / MSP430X platform
 */
static void
setreg(enum cc2420_register regname, uint16_t value) // Set the register of the cc2420 radio
{
  CC2420_SPI_ENABLE();
  SPI_WRITE_FAST(regname);
  SPI_WRITE_FAST((uint8_t) (value >> 8));
  SPI_WRITE_FAST((uint8_t) (value & 0xff));
  SPI_WAITFORTx_ENDED();
  SPI_WRITE(0);
  CC2420_SPI_DISABLE();
}

/* Sends a strobe */
static void
strobe(enum cc2420_register regname)
{
  CC2420_SPI_ENABLE();
  SPI_WRITE(regname);
  CC2420_SPI_DISABLE();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(reset_cc2420_registers, ev, data) // Defines the process reset_cc2420_registers
{

  PROCESS_BEGIN();  // Says where the process starts

  // Reset CC2420's register to normal behaviour
   setreg(CC2420_MANOR, 0x0000);
   setreg(CC2420_TOPTST, 0x0010);
   setreg(CC2420_MDMCTRL1, 0x0500);
   setreg(CC2420_DACTST, 0x0000);
   strobe(CC2420_STXON);

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


Video

I created an unmodulated carrier at channel 20 and to visualize the signal i am using the rssi-scanner provided by Contiki. When i press the restart button of the sky mote the carrier at channel 20 disappears, then it appears when the program starts running again.

References

Notice that the author from papers [1] and [2] is the same guy (Carlo Alberto Boano ).

[1] C. A. Boano, Z. He, Y. Li, T. Voigt, M. Zúñniga and A. Willig, "Controllable radio interference for experimental and testing purposes in Wireless Sensor Networks," 2009 IEEE 34th Conference on Local Computer Networks, Zurich, 2009, pp. 865-872.

[2] Boano, Carlo Alberto; Voigt, Thiemo; Tsiftes, Nicolas; Mottola, Luca; Römer, Kay; Zúñiga, Marco Antonio. Making Sensornet MAC Protocols Robust against Interference. Proceedings of the Wireless Sensor Networks: 7th European Conference - EWSN, Coimbra, Portugal, February 17-19, 2010, pp. 272-288.

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

}

Tuesday, June 14, 2016

Setting node ID for sky motes

Objective

The objective of this tutorial is to set up the id of sky motes using Contiki-3.0

Procedure

In the below directory you will find an archive called node-id.c which has two functions referred as node_id_burn and node_id_restore. The former is used to burn an id number to the node, and the latter is used to restore the default id.

/home/YOUR_USER/contiki-3.0/platform/sky

In order to used the functions node_id_burn and node_id_restore you must add following library to your code.

#include "sys/node-id.h"

Then, you must define a unsigned short variable which will store the id. Finally, you must call the function node_id_burn if you want to burn the defined id, or you must call the function node_id_restore if you want to restore the default id. The following code is an implementation that sets the ID equals to 1 for a sky mote; this code is based on the example-broadcast.c archive from the rime stack.

/*
 * 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
 *         Testing the broadcast layer in Rime
 * \author
 *         Adam Dunkels 
 */

#include "contiki.h"

#include "sys/node-id.h" // Include this library in order to be able to set node's ID.

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

#include "dev/button-sensor.h"

#include "dev/leds.h"

#include 
/*---------------------------------------------------------------------------*/
PROCESS(example_broadcast_process, "Broadcast example");
AUTOSTART_PROCESSES(&example_broadcast_process);
/*---------------------------------------------------------------------------*/
static void
broadcast_recv(struct broadcast_conn *c, const linkaddr_t *from)
{
  printf("broadcast message received from %d.%d: '%s'\n",
         from->u8[0], from->u8[1], (char *)packetbuf_dataptr());
}
static const struct broadcast_callbacks broadcast_call = {broadcast_recv};
static struct broadcast_conn broadcast;
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_broadcast_process, ev, data)
{
  static struct etimer et;

  unsigned short id = 1; // This is the ID which will be set in your sky mote

  PROCESS_EXITHANDLER(broadcast_close(&broadcast);)

  PROCESS_BEGIN();

  broadcast_open(&broadcast, 129, &broadcast_call);

  node_id_burn(id); // Call this function to burn the defined id
 //node_id_restore(); // Call this function to restore the default id

  while(1) {

    /* Delay 2-4 seconds */
    etimer_set(&et, CLOCK_SECOND * 4 + random_rand() % (CLOCK_SECOND * 4));

    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));

    packetbuf_copyfrom("Hello", 6);
    broadcast_send(&broadcast);
    printf("broadcast message sent\n");
  }

  PROCESS_END();
}
/*---------------------------------------------------------------------------*/

Compile the code and burn it into a sky mote. When you type the command make login to open a serial connection with the mote, then you will see the lines below, which indicates that the node id is set to 1:

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 26
Starting 'Broadcast example'