Welcome to makesense’s documentation!

Makesense is a tool that can create, run and analyze WSN experiment. It’s designed to be modular.

fab new:foobar  # Will create a foobar experiment
fab make:foobar  # Will compile all nodes and simulations tools
fab launch:foobar  # Will run the experiment
fab analyze:foobar  # Will launch all analysis scripts
fab plot:foobar   # Will plot all the graphes

User Guide

This part of the documentation, which is mostly prose, begins with some background information about makesense, then focuses on step-by-step instructions for getting the most out of it.

Installation

Makesense could be set up very easily. It uses git to manage it source code. To get started do the following commands:

git clone https://github.com/sieben/makesense.git

Dependencies installation

Makesense leverages several Python libraries such as :

Once you have all the content you should get started by installing all python dependencies. If you have pip installer you can install of them in one hit by using this command:

pip install requirements.txt

If you prefer to have your python dependencies managed by your package manager on ubuntu for instance you can have :

sudo apt-get install fabric python-networkx python-pandas python-matplotlib python-jinja2

Quickstart

This page will walk you through a typical experiment. I suppose that you have installed all the required python libraries.

Configure the Contiki stack

To compile and execute WSN simulation we use the Contiki operating system. We need to set up the fabric file that will be the orchestrator of our experiments to know where is the contiki folder. For that simply put the address of your current contiki in the fabfile.py at the root of makesense:

# Modify in your fabfile this line
CONTIKI_FOLDER = "/my/path/to/contiki"

If you are satisfied with default you don’t need to modify anything in the fabfile to get started.

Creating a simulation

Makesense is shipped with a little experiment to quickly get started and get a grasp of what the framework can do. To get started with a dummy experiment simply run the following command in the makesense directory:

fab new:dummy  # Will create a dummy experiment

This command will create a folder in experiments/dummy containing:

  • Contiki source code for server and a client
  • A Cooja Simulation Config file (CSC) that will be used to create a simulation
  • A Makefile that will help relaunch the

Compiling a simulation

Because makesense know all the path to the Contiki source code and to the simulation file we can simply make all the firmware by typing this command:

fab make:dummy

This command will compile all the firmware for the dummy experiment and will compile also the simulator if it’s not already done.

Launching an experiment

Launching an experiment is pretty straightforward. Simply type:

fab launch:dummy

The dummy experiment is designed to produce log files that will be analyzed later on. The goal here is to produce as much results as possible.

Makesense organization

This page is a little description of the organization of makesense.

  • docs/ is where all the documentation is stored
  • fabfile.py is the fabric command file. This is were the command line tool fab is going to fetch the code it needs
  • makesense/ is the folder countaining most of the function doing the work. It’s organized as a python package to be able to share variables easily
  • templates/ this is where all the templates used during the making of source code are stored.
makesense
├── AUTHORS.rst
├── CONTRIBUTING.rst
├── docs
│   ├── campaign.rst
│   ├── conf.py
│   ├── example_fabfile.py
│   ├── example_firmware.c
│   ├── example_makefile
│   ├── index.rst
│   ├── installation.rst
│   ├── iotlab.rst
│   ├── Makefile
│   ├── quickstart.rst
│   ├── README
│   └── remote.rst
├── fabfile.py
├── LICENSE
├── makesense
│   ├── analyze.py
│   ├── bootstrap.py
│   ├── graph.py
│   ├── __init__.py
│   ├── make.py
│   ├── parser.py
│   ├── plot.py
│   ├── report.py
│   ├── run.py
│   ├── sampling.py
│   ├── traffic.py
│   └── utils.py
├── README.md
├── requirements.txt
└── templates
    ├── dummy_client.c
    ├── dummy_main.csc
    ├── dummy_makefile
    ├── dummy_script.js
    ├── dummy_server.c
    ├── exp.json
    ├── lambda_bootstrap.js
    ├── readme.md
    └── report.html

Iotlab

Makesense can perform and deploy code to the iotlab infrastructure.

Let’s suppose that you have in your .ssh/config the following

Host grenoble
HostName grenoble.iot-lab.info
User leone

The you can use commands such as :

fab push_iotlab:dummy # Will launch a experiment fab pull_iotlab:dummy # Will fetch the results of an experiment done on iotlab

Remote server

There is several tricks and nice features to know when dealing with ssh and remote servers.

Let’s suppose that you want to access the grenoble server through ssh. It would be really easy to type just ssh grenoble for instance and get it working. Good news, ssh can do that! Just write in your ~/.ssh/config the following snippet:

Host grenoble
HostName grenoble.iot-lab.info
User leone

Don’t forget to replace leone with your real user name ;-) Then simply do a ssh-copy-id grenoble enter your password and you are all set!

Next you can connect to the server in Grenoble by simply typing ssh grenoble.

An other feature is that it allows to simplify the fabric file. For instance let’s suppose that you want to download all the content of a precise folder on your local machine. You can use snippet in your fabric file such as:

from fabric.api import env
env.use_ssh_config = True

@task
@hosts("grenoble")
def push(name):
    path = pj(EXPERIMENT_FOLDER, name)
    put(path,
        remote_path="~/html/results/")

For more information just check the fabric documentation

How to make a campaign of simulation?

A campaign of simulation usually involve making a variable change through several run or several nodes.

Makesense leverages Jinja2 to create very easily as many firmware as necessary by using templating. Instead of writing a C code directly we will write C code replacing the variables and function by templates variables that jinja2 will remplace by variables existing in a python code. By doing so we can for instance create very easily a loop iterating through a list of desired values for a variable and let makesense handle all the trouble of creating those files, compile them and deploy them on a testbed.

Step 1: Creating a C template

First we will create a simple C code that print a message through a loop.

#include <stdio.h>
#include "contiki.h"

static int my_value = {{ my_value }};

/*---------------------------------------------------------------------------*/
PROCESS(dummy_hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&dummy_hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(dummy_hello_world_process, ev, data)
{
  PROCESS_BEGIN();

  while(1) {
    printf("Hello, world. My value is %d\n", my_value);
  }

  PROCESS_END();
}
/*---------------------------------------------------------------------------*/
static int my_value = {{ my_value }};

It’s at this place that jinja2 will put the my_value variable. For more information check out the Jinja2 documentation.

This makefile will compile all the nodes.

SRC=$(wildcard [!symbols]*.c)
PROGS = $(patsubst %.c,%,$(SRC))
all: $(PROGS)

CONTIKI={{ contiki }}
TARGET={{ target }}

include $(CONTIKI)/Makefile.include

# vi:filetype=make:ts=4:sw=4:et

Step 2: Let’s loop

Suppose that you want to create firmware for 42 different values we would do it in the fabfile:


import os
import json
from os.path import join as pj

from fabric.api import task
from jinja2 import Environment, FileSystemLoader

# Default values
ROOT_DIR = os.path.dirname(__file__)
EXPERIMENT_FOLDER = pj(ROOT_DIR, "experiments")
TEMPLATE_FOLDER = pj(ROOT_DIR, "templates")
TEMPLATE_ENV = Environment(loader=FileSystemLoader(TEMPLATE_FOLDER))

@task
def my_special_function(name):
    """ This function will create 42 C files. """
    path = pj(EXPERIMENT_FOLDER, name)
    if not os.path.exists(path):
        os.makedirs(path)

    c_template = TEMPLATE_ENV.get_template("dummy_template.c")
    # We make the id start at 1 and finish at 42
    for value in range(1, 43):
        with open(pj(path, "dummy_%d.c" % value), "w") as f:
            f.write(c_template.render(my_value=value))

    # If you change the platform target and want to push to iotlab
    # don't forget to update the nodes names
    makefile_template = TEMPLATE_ENV.get_template("dummy_makefile")
    with open(pj(path, "Makefile"), "w") as f:
        f.write(makefile_template.render(contiki=CONTIKI_FOLDER,
                                             target="iotlab-m3"))

    config_template = TEMPLATE_ENV.get_template("dummy_iotlab.json")
    res = [
        {"nodes": ["m3-%d.grenoble.iot-lab.info" % num],
         "firmware_path": pj(path, "dummy_%d.iotlab-m3" % num)
       } for num in range(1, 43)]
    with open(pj(path, "iotlab.json"), "w") as f:
        f.write(json.dumps(res, sort_keys=True,
                  indent=4, separators=(',', ': ')))

Then we would call this function like any other fabric function

fab my_special_function:dummy

You should have files like:

  • dummy_1.iotlab-m3
  • ...
  • dummy_42.iotlab-m3

created in experiments/dummy

You should also have an iotlab.json looking like:

[
    {
        "firmware_path": "/home/sieben/Dropbox/workspace/makesense/experiments/prout/dummy_1.iotlab-m3",
        "nodes": [
            "m3-1.grenoble.iot-lab.info"
        ]
    },
    ...
]

Step 3: Push to iotlab

Then we simply have to push to iotlab:

fab push_iotlab:dummy

Indices and tables