Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / IoT

Data sharing between programming environments on Intel® Edison

5.00/5 (1 vote)
11 Jun 2015CPOL5 min read 8.9K  
In my blog today, I am going to talk about publisher-subscriber model for sharing data between various programs running in Linux.

This article is for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers

Get access to the new Intel® IoT Developer Kit, a complete hardware and software solution that allows developers to create exciting new solutions with the Intel® Galileo and Intel® Edison boards. Visit the Intel® Developer Zone for IoT.

There are many situations where we want to use multiple programming environments to to develop our IoT applications, for example,

  1. We prefer to do image processing using OpenCV* in C++ than doing it on NodeJS or Arduino. Mainly because, there are lot of examples on OpenCV written in C++.
  2. Let's say, our application written in Arduino needs to read the number of face in a camera footage. For this we need to use OpenCV to process the camera image and then pass the number of detected faces to Arduino.
  3. We prefer to use NodeJS to create a web server on the board, because it is relatively easy to create a webserver on NodeJS than other languages

There may be many more instances like this. However, in all these instances we always wish to have a simple mechanism to share data between various programming environments.

Han, Matthias has written a nice article on sharing memory between Arduino and C++. This approach is doable because, C++ and Arduino is running just like a process in Linux. However, for a beginner in C++, the process looks bit complex. Moreover, if you want to extend this to NodeJS, then you will have to write C++ code and write native bindings to access these variables in NodeJS.

Another approach is to create a common sharable file which can be read from all these programs. Each program will poll for data change in the file. In this case, there would be a thread or a loop looking for changes in the file. While reading, if there is a change, then you would read and process the data. This idea seems to be simple, however polling is not quite appreciated approach in software world.

In my blog today, I am going to talk about publisher-subscriber model for sharing data between various programs running in Linux. This model is very well adapted in software development. However, in embedded space, we achieve this model by combing both hardware and software.

Architecture

There are two parts to the message flow. One is notification of the change and another is to read the data. This is a pretty established, old approach in software. This approach is followed in some data warehouses applications (DW) for syndicating the data. In this DW, at first a tiny notification file is dropped onto a directory. This notification file will have information about the date and time of the change and reference to the location of the actual data file, which generally will be very huge. A demon will read this notification file and trigger the appreciate process to read the huge file. Here, I am trying to bring the same concept. But in this case, instead of notification file, we will trigger an interrupt.

Notification flow

Image 1

Message flow

Image 2

Let’s understand the notification and message flow -

Every programming environment will have its own output data container and a pin to trigger notification. Whenever some data needs to be sent out, that environment will first push the content to a container file. Then the environment will send a HIGH signal to its notification pin. Let’s see a strange kind of circuit diagram below. Surprisingly, these pins are shorted. Let me explain the details with an example.

Circuit

Image 3

Let’s see how an Arduino program can communicate with NodeJS and vice versa.
Image 4
Data and notification flow from Arduino to NodeJS

Image 5
Data and notification flow from NodeJS to Arduino.

Let’s assume that you have an Arduino program, which reads data from distance sensor. This distance sensor data needs to be sent to NodeJS for further processing.

In this case, Arduino needs a notification pin, which is nothing but one of the GPIO pin. According to our circuit diagram, let’s say this pin for Arduino is #3. Whenever there is any new data, Arduino will write this data into its own notification container file in root directory (refer message flow diagram) in this case, /arduino_notification_out.txt.

After successfully writing the content, Arduino will send HIGH signal to pin #3. Now, look at the circuit diagram above. The #3 is shorted with #1. That means, whenever pin#3 goes HIGH it sends that HIGH signal to pin #1.

Arduino code

C++
int notifier_pin 	= 3;
int js_subscriber_pin 	= 6;

FILE *fromarduino, *toarduino;
int i = 0;
int c;

// the setup routine runs once when you press reset:
void setup() {                
  pinMode(notifier_pin, OUTPUT); //Notification pin     
  pinMode(js_subscriber_pin, INPUT_PULLUP); //interrupt pin for reading message from JS    
  attachInterrupt(js_subscriber_pin, subscriberEvent, RISING); //Subscribe to interrupt notifications from JavaScript
  Serial.begin(9600);
}

//Read message from js notification file
void subscriberEvent() {
  
   toarduino = fopen("/js_notification_out.txt","r");  //Opening message from JS
   if (toarduino)
   {
    while ((c = getc(toarduino)) != EOF)
    {
      if(c != 10)//new line
      {
           Serial.print((char)c);
      }
    }
    Serial.println("");
    Serial.println("----------------");
    fclose(toarduino);
   }  
}

// the loop routine runs over and over again forever:
void loop() {
  if(i < 50)
  {
    i = i + 1;
  }
  else
  {
    i = 0;   
  }
  
  publishData();
  notifyWorld();  
  delay(1000);               // wait for a second
}

void publishData()
{
  fromarduino = fopen ("/arduino_notification_out.txt", "w+");
  fprintf(fromarduino, "[%d]", i);
  fclose(fromarduino);  
}

//Nofity any body connected to this interrupt  (C++ program and NodeJS) program
void notifyWorld()
{
    digitalWrite(notifier_pin, HIGH);
    delay(200);
    digitalWrite(notifier_pin, LOW);
}

In the NodeJS program, we will attach an interrupt to pin #1. Whenever it goes high, that means a new data is available in Arduino notification container file. Now, NodeJS will read that file and process the data. Refer “Data and event flow from Arduino to NodeJS” diagram for more clarity.

NodeJS Code

JavaScript
var mraa = require("mraa");
var fs = require('fs');


/**********Read notification from arduino*************/
var subscriber_pin = new mraa.Gpio(1);
    subscriber_pin.dir(mraa.DIR_IN);
    subscriber_pin.isr(mraa.EDGE_RISING, subscriberEvent); //Subscribe to interrupt notifications from Arduino
    
function subscriberEvent() {
    var contents = fs.readFileSync('/arduino_notification_out.txt').toString();
    console.log("Message from Arduino:" + contents);        
}

/********** Trigger message sending interrupt every 20 seconds *************/
var counter = 0;
var notifier_pin = new mraa.Gpio(5);
notifier_pin.dir(mraa.DIR_OUT);

setInterval(function(){
    counter++;
        fs.writeFileSync("/js_notification_out.txt", "NodeJS: [" + counter + "]\n");
        notifyWorld();
        counter = 0;
},20000);


function notifyWorld()
{
    notifier_pin.write(1);
    setTimeout(function(){
        notifier_pin.write(0);
    },200);
}

You can even send data from NodeJS to Arduino in the similar manner. Refer “Data and event flow from NodeJS to Arduino” for more clarity.

We can extend this approach to any programming environments which support interrupts.

Advantages of this approach:
In this approach, you are avoiding unnecessary polling for file change and also you don’t have to develop any C++ binding to share the data with NodeJS. The programming is fairly easy as well.

Disadvantages of this approach:
However, there is one disadvantage with this approach. Every direction of data flow needs a pair of GPIO pins. If you have to exchange data with multiple programing environments, then you would run out of GPIOs. However, we can achieve the same result with similar architecture by spending just one GPIO pair. But then you will have to manage your logic with single JSON file with proper properties like eventsource, event data and so on. You will have to take care of file lock situations as well. However, it is doable.

Intel® Developer Zone for IoT

Start inventing today with the Intel® IoT Developer Program which offers knowledge, tools, kits and a community of experts to quickly and easily turn your innovative ideas into IoT Solutions.

Dream it, Build it with the Intel® IoT Developer Kit for Intel® Edison and Intel® Galileo platforms. These kits are versatile, performance-optimized and fully integrated end-to-end IoT solutions supporting a variety of programming environments, tools, security, cloud connectivity and hardware.

For more resources and to learn how the new Intel® IoT Developer Kit v1.0 can help streamline your IoT projects:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)