Conceived in 2014, the Eclipse MRAA project aims to deliver a high-level, easy-to-use set of APIs for I/O access on Linux* boards and systems, similar to Arduino* offerings for MCU boards. Initially, the project targeted support for platforms such as the Intel® Galileo, Intel® Edison and Raspberry Pi* boards, highly popular among IoT enthusiasts and makers. Over time, the project evolved substantially and won the appreciation of multiple IoT communities resulting in a number of new board and feature additions. In fact, the project’s success prompted Arduino* to adopt the use of the library in the Arduino Create* cloud-based IDE when targeting x86 IoT platforms.
Development on boards and kits in Linux* environments continues to present issues in key areas: access of I/O in a platform-independent manner, portability from platform-to-platform, and consistency from revision-to-revision.
Here is a detailed look at each issue:
- Access of I/O in a platform-independent manner: Kernel-level abstractions are low level and can be difficult to use for inexperienced developers. The Linux* kernel exposes the I/O interface through sysfs classes or device nodes. Depending on the implementation, the details can vary from one platform to another quite drastically. However, users expect to be able to use the I/Os at a much higher level of abstraction. For example, in order to initialize i2c bus on the Intel® Edison board, the following steps are needed:
- Set Tristate to 0
- Set GPIO14 to input
- Set GPIO165 to input
- Set GPIO236 to output and disable
- Set GPIO237 to output and disable
- Set tristate to 1
- Set GPIO213 to input
- Set GPI212 to input
- Change pinmode for pin27
- Change pinmode for pin28
These details vary from one board to another and among different revisions of the same board.
- Portability from platform-to-platform: In some situations, usually buses, device drivers provide access to I/O. Configuration of these drivers is done through Device Trees (ARM*) or ACPI tables (x86) and is usually provided by the vendor as part of the BSP. However, there are no set standards for exposing the capabilities of the underlying platform through device drivers. Consequently, developers make choices suitable for the particular platform. This leads to APIs that are not uniform across platforms and creates the need for customization of drivers for sensors connected to these platforms.
- Consistency from revision-to-revision: A development board and the SoC on the board typically undergo revisions either to add new features or to fix bugs. In that process some changes to the I/O interfaces creep in – typically the I/O pin numbering may change. Certain steps needed to enable the I/Os can change or become unnecessary.
Using system classes and devices for GPIO and bus access from software is usually not straightforward in Linux*, since the OS numbering scheme does not match the labeling on the board. MRAA presents a façade which makes the relationship between I/O and the hardware more intuitive to developers. Here are some example class and device paths on a typical board.
To overcome the lack of standards for exposing I/O on different maker and SBC platforms, we released the MRAA project, a C/C++ library with bindings to Java*, JavaScript* and Python* to interface the I/O on the Intel® IoT Developer Kit boards, Raspberry Pi*, and other platforms. With a structured and consistent API in which port names and numbering match the board, MRAA does not tie developers to specific hardware. With board detection done at runtime, developers create portable code that will work across the supported platforms. The main I/O API classes supported by MRAA are GPIO, AIO Analog*, PWM, SPI, I2C, and UART. Additionally, the library can also interface with 1-Wire*, Firmata*, IIO, and named LED devices. See the block diagram in Figure 1 to understand where MRAA fits in a typical software stack.
Figure 1. Hardware Abstraction MRAA
MRAA makes it easier for developers and sensor manufacturers to map their sensors & actuators on top of supported hardware and allows control of low level communication protocols from user-space using high level languages and constructs.
MRAA is supported on a large number of IoT platforms based on Intel® x86, ARM*, and MIPS processors. One FPGA developer kit is also supported. Further, MRAA introduces the concept of subplatforms for extending I/Os on existing boards or adding I/O capabilities to systems that have none. These I/O expanders are often offered in the form of an IC or an MCU, and they can be connected to the host device and utilized using the same MRAA APIs. In such cases, the user application runs on the host and communicates with the expander via device drivers or 3rd party communication libraries (e.g., Firmata*).
The current list of supported boards is as follows:
- X86: Intel® Galileo, Intel® Edison, Intel® Joule™, Intel® NUC DE3815, Intel® NUC5, MinnowBoard MAX*, MinnowBoard Turbot*, Aaeon*, UP*, UP2*, IEI* Tank 870
- ARM*: Raspberry Pi*, Banana Pi*, Beaglebone* Black, phyBOARD-Wega*, 96Boards* (Bubblegum, DragonBoard, HiKey, Rock, Ultra)
- MIPS: Linkit* Smart 7688, Onion* Omega2
- FPGA: Terasic* DE10-Nano
- Subplatforms: FTDI4222, Arduino 101*, GrovePi+, Generic Firmata* Boards
MRAA also provides the option to define boards or systems using a simple JavaScript* Object Notation (JSON) format. This feature is ideal for devices and systems derived from a reference design provided by Intel, but certainly not limited by it. For instance, developers working on an industrial gateway device, using the standard Linux pseudo devices known to MRAA for the exposed I/Os, can quickly add platform support by providing only the JSON board definition file. This eliminates the task of writing a dedicated board file in C and integrating it with the internals of the MRAA library. Examples of JSON defined platforms are provided for the MinnowBoard Turbot* and the Intel® Aero Compute Board.
NOTE: Unfortunately, the JSON format does not work in situations requiring pin muxing or custom steps to initialize I/Os on the platform. Those scenarios require writing problem-solving at the C level.
The developer community finds it useful to simulate or “virtualize” an IoT board. Currently MRAA implements this feature using a mock platform, allowing developers to write and run applications even on systems that have no exposed I/Os (e.g. a development laptop). This feature promotes early prototyping and development of application logic when hardware is unavailable. Once the intended target becomes available, the application can be migrated to run on the hardware without any changes. The mock platform feature also encourages unit testing among MRAA contributors and is used with the project’s continuous integration (CI) systems. A variation on the mock platform for JavaScript* that is mainly specific to Windows* is offered under the name mraaStub (jsstub).
The MRAA library offers a string initializer feature for the I/O classes. This eliminates the precondition for data type knowledge from higher level frameworks or services that need to initialize and interact with I/Os using the MRAA library. In short, MRAA I/O initializer functions generally use a combination of integers, booleans and strings to specify the required I/O resource. This feature introduces a generic MRAA init_io function which works exclusively on a string input, sending it to an internal parser for decoding and I/O initialization.
IMRAA, a platform configuration service that is part of MRAA, provides platform configuration before user applications initialize the MRAA library. This component has been used mainly for setting up user permissions in order to gain access to I/O resources on Linux systems and to detect and load connected subplatforms when an application is launched. IMRAA could be enhanced, if needed, to act as a daemon for dynamic platform configuration.
At a high level, the MRAA sources are organized as follows:
MRAA is open-source software offered through GitHub*. It can be installed on any Linux* system using the cmake build system, and the project has few dependencies on other system packages, the most notable being SWIG. This source translation framework is necessary if bindings for other supported languages are desired. The supported Operating Systems are:
- Standard Linux* Distributions: Fedora*, Debian*, Ubuntu*, Ubilinux*, Arch Linux*, OpenSUSE*
- Embedded Linux* Distributions and Projects: Yocto Project*, OpenEmbedded, 01.org, Wind River Linux*, Wind River Pulsar Linux*, Android Things*
- Real-time Embedded OS: Zephyr*
- Windows*: Only using Docker* containers and the mock platform
Contributions are checked through the use of the Travis CI system, unit testing, and static code analysis. A system running Doxygen* on a Jenkins* instance generates documentation. Packaging is done on demand on stable releases only. The community maintains most of the distribution channels for the supported OSes listed above.
Over the course of 2017, the project saw over 30K unique visitors and approximately 15K unique downloads according to GitHub* metrics. Good adoption occurred internally at Intel and externally from key companies such as IBM*, Linaro*/ARM*, Google*, Emutex*, Phytec*, GE*, Technexion*, Qualcomm*, STMicroelectronics*, u-blox*, Honeywell*, Siemens*, Mediatek*, and others. Adoption took place either directly, or through custom-designed Intel® IoT Developer Kit boards requested by some of these partners.
The project is still under active development from by Intel and the developer community. The MRAA project is also tightly integrated with Intel® System Studio, a free product that integrates multiple Intel® tools and libraries with the Eclipse* IDE.
*Other names and brands may be claimed as the property of others.
The content of this open source project is received and distributed under the license(s) listed above. Some source code and binaries may be distributed under different terms. Specific license information is provided in file headers and in NOTICE files distributed with the project's binaries.
Member companies supporting this project over the last three months.