Intel-IoT_LogoImage courtesy of Intel iot-devkit GitHub account

UPM (Useful Packages and Modules) is a high-level library that relies on MRAA to talk to hardware peripherals over GPIO, SPI, UART, etc. Both libraries were created by Intel and come packaged with the Galileo and Edison boards. MRAA has support for other single board computers, like the Raspberry Pi and Beaglebone Black, according to the MRAA documentation.

MRAA is the low-level driver that controls the individual bits for the GPIO. UPM is a collection of libraries (modules) that provides the necessary software for various sensors, motor drivers, etc.

Using UPM is a relatively straightforward task. Instantiate an object with the name of the module you want to use, provide the necessary parameters, and call some functions. It is very similar to using libraries in Arduino.

However,  writing a custom module for a piece of hardware in UPM can be quite daunting. In this post, I will cover how to compile UPM from source, create a template for a module (lovingly named “mymodule”), and write a simple example that uses that module.

We write UPM modules in C++ and use SWIG to create interfaces to Python and JavaScript. That means libraries written in UPM can be used by C++, Python, and JavaScript. Java bindings are available, but I won’t cover them.

Note that I perform all of these steps on an Intel Edison. You can cross-compile on a different machine, but I decided that copying files back and forth was more of a pain.

Install and Configure Git

If this is your first time using the Edison, it’s recommended that you configure it:

configure_edison --setup

Follow the prompts. To install git, we need to enable the unofficial Edison packages as per AlexT’s blog. Add the following lines to /etc/opkg/base-feeds.conf:

src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32

Save and exit. Run the following commands:

opkg update
opkg install git

If you’re planning on making a new UPM module and then submitting your code via pull request back to the UPM repository, I recommend forking the original UPM to your GitHub account. You will also need to generate SSH keys for git on your Edison.

Build MRAA

We first need to build MRAA so we have access to the compiled libraries.

cd ~
git clone git@github.com:intel-iot-devkit/mraa
cd mraa
mkdir build
cd build
cmake ..
make

Install MRAA and update the pkg-config path:

make install
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig

Build UPM

We then need to build UPM, which links to the MRAA libraries. If you forked UPM, you will want to change intel-iot-devkit to your GitHub account name in the link below.

cd ~
git clone git@github.com:intel-iot-devkit/upm
cd upm

[Edit 01/20/2016] Now would be a good time to create a new branch for your module: git checkout -b mymodule

 

Prepare to build:

mkdir build
cd build
cmake ..

You can optionally build all of UPM. Note that this takes 2-3 hours, as the Edison is a relatively slow machine. This will build all modules and install them on your Edison:

make
make install

Initialize Module Source Directory

Create a directory for our module in the source directory:

cd ../src
mkdir mymodule
cd mymodule

Create a file named CMakeLists.txt with your favorite editor, and add the following:

set (libname "mymodule")
set (libdescription "Test UPM module for my learning")
set (module_src mymodule.cxx)
set (module_h mymodule.h)
upm_module_init()

[Edit 1/20/2016] Create a file named javaupm_mymodule.i (SWIG interface file for Java), and enter:

%module javaupm_mymodule
%include "../upm.i"
%include "typemaps.i"

%{
    #include "mymodule.h"
%}

%include "mymodule.h"

%pragma(java) jniclasscode=%{
    static {
        try {
            System.loadLibrary("javaupm_mymodule");
        } catch (UnsatisfiedLinkError e) {
            System.err.println("Native code library failed to load. \n" + e);
            System.exit(1);
        }
    }
%}

Create another file named jsupm_mymodule.i (SWIG interface file for JavaScript), and enter:

%module jsupm_mymodule
%include "../upm.i"

%include "mymodule.h"
%{
    #include "mymodule.h"
%}

Create yet another file named pyupm_mymodule.i (interface file for Python), and enter:

// Include doxygen-generated documentation
%include "pyupm_doxy2swig.i"
%module pyupm_mymodule
%include "../upm.i"

%feature("autodoc", "3");

%include "mymodule.h"
%{
    #include "mymodule.h"
%}

Write the Source Files

We’re going to create a simple C++ class that has one method: test() , which simply prints a message to the screen when called.

Create a file with the name mymodule.h and enter:

#pragma once

#include <stdio.h>

namespace upm {

    class MyModule {
        public:

            MyModule();
            void test();

        private:

    };
}

Create another file named mymodule.cxx and enter:

#include "mymodule.h"

using namespace upm;

MyModule::MyModule() {
}

void MyModule::test() {
    printf("Hello from my custom module\n");
}

In the end, our module directory should have the following files:

  • mymodule
    • CMakeLists.txt
    • jsupm_mymodule.i
    • mymodule.cxx
    • mymodule.h
    • pyupm_mymodule.i

Build and Install Your Module

We can build and install just mymodule, without needing to reinstall everything in UPM. We do this by invoking cmake , which sets up all the modules in the build/src directory. From within the build directory, we can call make <MODULE NAME> to build just our module:

cd ../../build
cmake ..
make mymodule
cd src/mymodule
make install

[Edit 1/2/16] Note: if you make a change to your source code, especially the interface (e.g. number of arguments in the constructor), you will need to clean the build/src/mymodule directory. From upm/build, run rm -rf src/mymodule before calling make mymodule .

Write a C++ Test Program

Now, let’s write a quick C++ program to test our module. Back in our home directory (i.e. cd ~ ), create a file named my_mod_test.cpp and enter:

#include "mymodule.h"

int main(int argc, char **argv) {

    upm::MyModule * mod = new upm::MyModule();
    mod->test();

    delete mod;
    return 0;
}

Save and exit. Add /usr/local/lib to the linker path, build, and run:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
g++ my_mod_test.cpp -lupm-mymodule -I/usr/local/include/upm
./a.out

You should get a nice little message (“Hello from my custom module”) appear in the console.

Write a Java Test Program

[Edit 1/20/2016] Added this section on writing a Java test program. Right now, it doesn’t work, and I’m trying to figure out why. For now, just skip this section.

Likely, your Edison didn’t come with JDK, so we can’t write test programs yet. To install the JDK (here to see the latest versions):

mkdir /home/root/java
cd /home/root/java
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u71-b15/jdk-8u71-linux-i586.tar.gz"
tar -zxvf jdk-8u71-linux-i586.tar.gz
mkdir /home/root/bin
cd /home/root/bin
ln -s /home/root/java/jdk1.8.0_71/bin/java java
ln -s /home/root/java/jdk1.8.0_71/bin/javac javac

Now, we can write a simple Java program to test our module. In the home directory (cd ~ ), create a file named MyModuleSample.java and enter:

public class MyModuleSample {
    public static void main(String[] args) throws InterruptedException {
        upm_mymodule.MyModule module = new upm_mymodule.MyModule();
        module.test();
    }
}

Save and exit. Add /usr/local/lib/pkgconfig to the Java path, build, and run:

CLASSPATH=$CLASSPATH:/home/local/lib/pkgconfig
./bin/javac MyModuleSample.java
./bin/java MyModuleSample.jar

Write a JavaScript Test Program

Much like our C++ program, we can also write a simple JavaScript program that uses our new library. In our home directory (i.e. cd ~ ), create a file named my_mod_test.js and enter:

var module = require('jsupm_mymodule');
var mod = new module.MyModule();
mod.test();

Add /usr/local/lib/node_modules/ to the Node path and run:

NODE_PATH=$NODE_PATH:/usr/local/lib/node_modules/
node my_mod_test.js

Once again, you should see the same message appear in your console.

Write a Python Test Program

Finally, we can test our module with Python. In our home directory (i.e. cd ~ ), create a file named my_mod_test.py and enter:

import pyupm_mymodule as mymodule

mod = mymodule.MyModule()
mod.test()

Add /usr/local/lib/python2.7/site-packages/ to the Python path and run:

PYTHONPATH=$PYTHONPATH:/usr/local/lib/python2.7/site-packages/
export PYTHONPATH
python my_mod_test.py

Our message should appear once more in the console.

Conclusion

If you follow these steps, you will have created a nice template for writing your UPM module. Feel free to use a different name instead of mymodule, say, the name of your hardware component.

If you would like more information on creating your own UPM module, see these documents:

[Edit 2/3/2016] Added make install  to the MRAA build process and corrected the pkg-config path variable export.

7 thoughts on “Writing Your Own UPM Module: Getting Started

  1. Elvis Fernandes on January 30, 2016 at 5:22 pm Reply

    Very clear and precise information. This helped a lot! Thanks!

  2. […] 原文来自:https://shawnhymel.com/756/writing-your-own-upm-module-getting-started/ […]

  3. Wojciech on February 12, 2016 at 1:43 pm Reply

    hello, W did all steps from this lesson 🙂 On the end when I cmake mymodule I am getting error:
    CMake Error at CMakeLists.txt:5 (upm_module_init):
    Unknown CMake command “upm_module_init”.
    CMake Warning (dev) in CMakeLists.txt:
    No cmake_minimum_required command is present. A line of code such as
    cmake_minimum_required(VERSION 2.8)

    1. Wojciech on February 12, 2016 at 1:44 pm Reply

      Do You know how to fix it ? 🙂

      1. ShawnHymel on February 12, 2016 at 4:38 pm Reply

        Make sure your Edison image is up to date (build v2.1). Additionally, what commands did you use? It should be:

        cmake ..
        make mymodule

  4. Wojciech on February 13, 2016 at 11:28 am Reply

    Hi, I re-flashed my Edison and now all is working prefect 🙂
    Thx!

    BR
    Wojciech

  5. […] Hymel wrote this straightforward getting started guide for building custom modules for hardware in […]

Leave a Comment

Your email address will not be published. Marked fields are required.