Skip to content

NodeJS plugin

Guillaume VILLEREZ edited this page Feb 14, 2016 · 1 revision

Installing and configuring nodeJS

To install Nodejs, simply download the last version from one of the existing depot. Do not use the default one with apt-get on raspbian, because you won't be able to compile node plugins.

wget http://node-arm.herokuapp.com/node_latest_armhf.deb 
sudo dpkg -i node_latest_armhf.deb

You should now be able to test if node is here with node -v and npm -v for its packet manager.

Installing node-gyp

node-gyp allows you to easily build C++ plugins to Nodejs on any platform (even if in our case it will only work on unix). It use its own 'kind of' Makefile, which it uses to generate every informations needed to compilation and linking.

npm install -g node-gyp

Using node-gyp

To use node-gyp and build your first plugin, the best is to follow the simple tutorial available on the Nodejs website https://nodejs.org/api/addons.html .

I won't talk much about the basic configuration, because nodejs' documentation is easy to read and provides a lot of useful examples.

Project configuration

From now, your binding.gyp file should looks like this (with a project name addon and only one source file) :

    {
      "targets": [
        {
          "target_name": "addon",
          "cflags": [ "-Wall" ],
          "sources": [ "test.cc" ]
        }
      ]
    }

C++ 11

This plugin will use C++11 and wiringPi. You should install wiringPi if not already done. WiringPi provides an interface to talk to the GPIO pins of the raspberry, and can be found here : http://wiringpi.com/download-and-install/

To use C++11 we need to add -std=c++0x to g++. We'll only add that to the cflag array. Every element here is added to each file defined in the sources array when compiled.

Wiring Pi

Binding with the project

Using wiringPi is a little more difficult. Once you've installed and compiled wiringPi it will be installed. Your first tough was certainly to simply add a -lwiringPi in the cflags array, but that won't work. Why? Because you only need to give it to the linker once, and clfags are used for every compiled file. Fortunately, you can add static libraries instead of shared one to your binding file.

First, you'll need to generate the .a you need. Go to the wiringPi directory, then in the wiringPi subdirectory. Here, simply run :

make install-static

To generate the static library. it will usually be generated at /usr/local/lib/libwiringPi.a. Now you can add an array named libraries with the previous path to add it to your project setup.

From now, your binding file should looks like this :

    {
      "targets": [
        {
          "target_name": "addon",
          "cflags": [ "-std=c++0x", "-Wall" ],
          "sources": [ "test.cc" ],
          "libraries": [ "/usr/local/lib/libwiringPi.a" ],
        }
      ]
    }

How to make it quit on error

As you may have noticed, the latest version of wiringPi performs an exit() if its launch fail. But since we are in a node plugin, we don't want this behavior. The problem is there is an easy way, defining an env variable, to overcome this new behavior, which don't work when used with a node plugin. I don't know why, but I suspect that nodejs may not give it access to the shell env variables.

The only way I've found is to actually comment the line 598 (which may change in future version) in the source file wiringPi.c of wiringPi (method wiringPiFailure) before generating the static library.

The first test

With the previous file, we will only use a small C++ file that will only launch wiring pi with wiringPiSetup and nothing else:

#include <node.h>
#include <iostream>
#include <stdlib.h>

#include <wiringPi.h>

using namespace v8;

void RunCallback(const FunctionCallbackInfo<Value>& args) {
        Isolate* isolate = Isolate::GetCurrent();
        HandleScope scope(isolate);

        int ret = wiringPiSetup();

        Local<Number> num =  Number::New(isolate, ret);
        args.GetReturnValue().Set(num);
}

void Init(Handle<Object> exports, Handle<Object> module) {
        NODE_SET_METHOD(module, "exports", RunCallback);
}

NODE_MODULE(demo, Init)

The JavaScript file will only launch the demo, get the result, and show a short text:

var demo = require('./build/Release/demo');

ret = demo();

if(ret == -1)
        console.log("Error with wiringPi");
else
        console.log("Everything works fine :)");

And you should be able to use test everything. Note that wiringPi need root right :