Bringing JavaScript to mbed OS


Information

For more information, visit JavaScript on mbed.

People may come to IoT development from a variety of software backgrounds, many of them based on high-level languages, and the transition to using a C++ SDK like mbed OS may prove a challenge. Of course, there will be others who may just enjoy the expressiveness and quick design iterations that you get with languages like JavaScript. For these reasons, we're interested in providing access to mbed OS development in high-level languages.

JavaScript for embedded development

Today we'll be looking at bringing support for JavaScript to mbed OS. Imagine the difference in writing a simple program where a button toggles an LED, when you can easily create the function at the point where you pass it as a callback argument:

var led = DigitalOut(LED1);
var button = InterruptIn(SW2);
button.fall(function() { led.write(led.read() ? 0 : 1); });

The equivalent code in the C++ SDK:

DigitalOut led(LED1);
InterruptIn button(SW2);
void toggle_led()
{
    led = !led;
}
int main()
{
    button.fall(&toggle_led);
}

The above example may not exactly inspire you to want to run out and embrace JavaScript just yet, but consider also that this implementation is designed so that interrupt-triggered callbacks are actually executed outside of the interrupt context. This means that you don't have to worry about what you can or cannot do in your callback. You're free to do things like print to the console:

var led = DigitalOut(LED1);
var button = InterruptIn(SW2);
button.fall(function()
{
  led.write(led.read() ? 0 : 1);
  print("Normally you're not allowed to print to the console in an Interrupt Service Routine!");
  print("(but this isn't being executed in an ISR...)");
});

The equivalent code in C++ would require you to use a Mailbox or Queue to mark whenever the button is pressed, and then the main() function will need to wait for messages to appear in the Mailbox, and perform the printing there, in an infinite loop. The JavaScript code might look more appealing now.

Using JerryScript on mbed OS

In order to support JavaScript on mbed OS, we have been working on integrating the JerryScript VM into mbed OS 5. JerryScript is an ECMAScript 5.1 compatible implementation of JavaScript. It's designed to fit within 200KB of ROM, and needs at least 64KB of RAM; it can easily fit into many mbed Enabled boards - including the NXP FRDM-K64F, Nordic Semiconductors NRF52-DK, or ST Nucleo-F401RE. Our initial porting effort has been made available in JerryScript, but it is not an officially supported mbed OS 5 project.

The integration of JavaScript with mbed OS is available as a new target in the JerryScript project, under the 'mbedos5' name. Integration in this case means that the JavaScript engine runs within an mbed RTOS thread, and you have access to the familiar mbed classes within your JavaScript code like DigitalOut, I2C, InterruptIn, etc.

Integration details

The majority of our port of JerryScript to mbed OS 5 - including the HAL, build scripts and core libraries - have been submitted as a pull request to the official JerryScript repository. All changes can be found under the 'target/mbedos5' directory. You can check out our fork of JerryScript support on mbed OS here. Other libraries, like js-mbed-easy-connect and js-mbed-simple-cloud-client that provide networking and integration with mbed Device Connector, are hosted as separate projects outside the JerryScript repository.

The targets/mbedos5 directory in ARMmbed’s JerryScript forked repository is set up to resemble any other mbed OS 5 project. The integration between JerryScript and mbed OS lives in jerryscript-mbed, while the C++ code that simply launches the JerryScript engine is in source, and your JavaScript code itself can be found in the js directory.

jerryscript-mbed directory

This project is the heart of the integration between JerryScript and mbed OS. It's important to know that any C/C++ API that you wish to access from JavaScript code needs to first have wrapper code written for the relevant functions and classes. Developers of any C++ libraries are welcome to provide a JS-wrapper library that presents a nice JS interface to their library.

The most important parts of this project are:

  1. The entrypoint for starting a JerryScript engine in your project (for example, the jsmbed_js_launch() function).
  2. The API that wrappers should use to provide JavaScript access to the code they are wrapping.
  3. The wrappers for the mbed HAL API (giving you access to classes like DigitalOut and InterruptIn).

source directory

This folder is an example of how to integrate the JerryScript engine into your mbed OS project. In this case it simply indicates that the mbed-drivers base wrappers should be loaded, by calling JERRY_USE_MBED_LIBRARY(base). Then it launches the JerryScript engine by calling jsmbed_js_launch(). You can extend this if you wish to implement any extra functionality outside of JavaScript, as it is a completely normal mbed OS 5 project.

js directory

Finally we have the js directory, where your JavaScript code lives.

The files in the js directory must be processed into a C++ source array of bytes in order to be loaded by JerryScript when it initialises. You can do this manually by running the provided tools/js2c.py script. This script will process the JavaScript code in such a way that the JerryScript engine will execute main.js first, and then all other scripts. Note however that the normal method of building your JavaScript project as described below will automatically run the tools/js2c.py script for you.

The js directory will also contain a pins.js file once tools/js2c.py has been run. This will contain the definitions of all pins available on your board.

After building and flashing your program onto the board, you can reset the board to run your JavaScript application. At this point, the engine will:

  1. Run all of the code found in main.js.
  2. Run all of the code found in all other files in _alphabetical order_ (case-insensitive).
  3. The engine will loop, waiting to receive callbacks. This means that if you want to periodically execute a function, you can achieve this easily with the use of setInterval():

setInterval(function() {
    print("This is called every 3.5 seconds!");
}, 3500);

NOTE: pins.js will be not be executed like other JS files. Any variables defined in this file are available for use in all other files, but are loaded in a special way by JerryScript, ensuring that you have more memory available for writing your application. This file should only contain lines like var VARIABLE = VALUE;. Any other code will not be executed!

How to quickly run some JavaScript on your device

  1. Clone or download the JerryScript project.
  2. From your terminal, navigate to targets/mbedos5.
  3. Run make getlibs to pull in the mbed OS dependencies. - On Windows you will need GNU Make or Cygwin installed.
  4. Make any changes you wish to the JavaScript found in the js directory. - main.js should always exist, and is always executed first. - All files (apart from main.js and pins.js) are executed in alphabetical order.
  5. Compile your project using make BOARD=boardname. For FRDM-K64F, use K64F. For the NRF52 development kit, use NRF52_DK. - To find out the name of your board, connect your development board to your computer and run mbed detect.
  6. The compiled firmware is located at .build/[BOARDNAME]/GCC_ARM and is either named mbedos5.bin or mbedos5.hex. Drag the firmware file onto your development board - which mounts as a USB mass storage device.

Conclusion

We have produced a prototype that provides access to mbed APIs within JavaScript code. So far we have the JerryScript VM running within the mbed RTOS, with access to some mbed HAL API classes available from JavaScript.

By closely following the classes and functions provided by the mbed C++ API in JavaScript, first-time IoT app developers (who may be coming from a web background) can get started with JavaScript mbed OS development, and then may feel more comfortable transitioning to the C++ SDK later.

In the coming week we will publish a number of new blog posts and libraries related to JavaScript on mbed OS 5. First, we will publish instructions on porting existing C++ mbed libraries to JerryScript. Second, we will publish a JavaScript library for mbed Client - allowing you to write connected IoT applications using mbed Device Connector. And third, we will publish a JavaScript library for BLE - allowing you to access the mbed Bluetooth stack from JS. Keep a close watch to this blog for updates.

We'd really like to take this work further, so if you're a developer who is itching to write your IoT projects in JavaScript, we're keen to hear from you!

-

This blog post was written by Stephen Kyle, Software Engineer at ARM, and one of the driving forces behind JerryScript on mbed OS.