Visual Programming with Embedded Rust? Yes we can with Apache Mynewt and Google Blockly!
I gotta admit — Embedded Programs are getting darned hard to code on modern microcontrollers, sensors and networks. Faced with the ultra-daunting task of coding a readable, reusable, open-source NB-IoT application for STM32, I asked myself… Could Visual Programming with Embedded Rust solve this problem? Like this…
Try it for yourself here:
Let’s talk about the components necessary for this visual Rust solution…
1️⃣ Google Blockly, the visual coding tool
2️⃣ Apache Mynewt, the embedded OS
3️⃣ And all the integration bits: Custom code blocks, code generation, safe wrappers, …
The source code is available here…
It’s easy to clone the Blockly repository, open in a web browser and test the visual programming tool ourselves. Unfortunately Blockly doesn’t generate Rust code today. We’ll discuss Rust code generation in a while.
Recall the problem we are solving… Creating Embedded Apps easily for Bare Metal microcontrollers (like STM32 Blue Pill). Our Embedded Rust Apps will have to access Bare Metal functions like GPIO, I2C, SPI, … And network peripherals like ESP8266, nRF24L01, BC95-G, …
Can we use Rust drivers to access these functions? Not quite — today we don’t have a comprehensive collection of Embedded Rust drivers. Given that the Embedded Rust platform is still in flux, it may be risky to adopt Embedded Rust drivers now.
So let’s pick a modern embedded real-time OS (built with C) and build Rust wrappers around it. I have chosen Apache Mynewt. We’ll talk about the Rust Safe Wrappers in a while. Meanwhile find out how I integrated Rust with Mynewt in this article.
A visual program in Blockly consists of Blocks connected together.
The screenshot here shows three GPIO Blocks that we have created specially for creating Embedded Rust apps.
How are Blocks created? Through the Block Factory, which looks like another Blockly app. The Block Library we have created is located at
After building the Blocks, we click the Block Exporter to export the Blocks into two files…
generators/rust/mynewt_blocks.js: Block Definitions in JSON
generators/rust/mynewt_functions.js: Code Generator Functions for the Blocks
For more details on Blockly Custom Blocks, see…
Define Blocks | Blockly | Google Developers
Here’s the Block Definition for the
digital toggle pin Block. The Block toggles a GPIO pin from Low to High and vice versa. The Block was exported by the Block Exporter.
The Block is defined with one input named
PIN: a dropdown for a list of pins (like
PA1), which will be dynamically populated in the real visual programming tool.
In the Block Factory, the Block was defined as
top+bottom connections. Which means that it’s meant to be used like a program statement, with (optional) Statement Blocks preceding and following the Block.
Each Block requires a Code Generation Function to generate the code for the Block. More about this…
Rust Code Generation
When this demo was created, Blockly did not have a Rust Code Generator. So I copied the Dart Code Generator into these locations…
generators/rust.js: Main Code Generator for Rust
generators/rust: Rust Code Generators for the Standard and Custom Blocks
We have seen this code earlier in the demo — this is the
main() function that’s generated before all other Blocks.
Code Generators are really simple text processors in Blockly. We see here that it’s appending the
main() function to another chunk of code that was generated by other Blocks…
code = [ code, … ].join(‘\n’);
forever will use a similar Code Generator that embeds an inner chunk of code.
Every Block in Blockly needs a Code Generator Function to emit Rust code for the Block, even Common Blocks like
for, …. Here’s the Code Generator Function for
Remember that the Block accepts one parameter
PIN, the GPIO pin to be toggled? Here’s how we fetch the parameter and embed it into the code. The output looks like this…
// Toggle the GPIO pin
gpio::toggle(MCU_GPIO_PORTC!(13)) ? ;
For more details on Blockly Code Generation, check this article.
We isolate any changes to the Blockly source code so that we may enjoy future Blockly upgrades (via
generators/rust contains the Rust Code Generator
demos/code is the Blockly demo in HTML that we have customised for Rust
demos/code/index.html has been updated to load our Rust Code Block Definitions and Rust Code Generator
4️⃣ The Blocks Menu in
demos/code/index.html has been updated with our Custom Blocks
demos/code/code.js has been updated to load the Custom Blocks
Safe Wrappers in Rust
What makes a great Embedded Programming experience? Safe and simple coding…
1️⃣ Safe Coding: We shall prevent programmers from falling into traps that they don’t know how to escape. Pointers in Embedded C is a very serious trap.
2️⃣ Simple Coding: Coding shall look intuitive, even though in reality it’s complicated. Like automatically ensuring that all strings passed from Rust to C functions are null-terminated.
The solution: Create Safe Wrappers in Rust to wrap up the risky, complex parts of the Mynewt API. It’s possible to generate Safe Wrappers for Mynewt APIs automatically via
bindgen and Rust Procedural Macros. Learn more about this here.
And once we have implemented Visual Programming in Embedded Rust, coding can’t get any simpler!
Rusty Round Trip
“When she’s coming round the mountain… will she be the same?”
Ever since the 1980s, software engineers have been concerned about Round-Trip Engineering… If we make any changes to the generated Rust source code, can the Visual Programming Tool apply the same changes back into the original Visual Program? Such that both Visual and Textual Programs are always synchronised?
It’s a difficult problem — there are so many Rust Programs that can’t possibly be expressed as a Visual Program!
But it’s easier to solve in Rust. In my previous article I wrote about the
syn Crate that parses Rust source code. This could be used to discover changes in the generated Rust source code and (hopefully) make (sensible) updates (automatically) to the Visual Program.
This might work by embedding
Why Visual Rust?
3️⃣ Embedded C, hosted on a suitable RTOS, has zero bloat but it’s too unsafe for today’s embedded programmers.
Visual Programming with Embedded Rust + Apache Mynewt is the perfect compromise: safe and simple coding, compiles into compact Arm machine code, very little bloat. Yet it’s sufficiently sophisticated to support Round-Tripping, NB-IoT with CoAP and CBOR, …
So why aren’t we doing Visual Rust Programming today and moving out of Embedded C forever…?
Run The Demo
To run the Visual Rust demo, click here:
To make your own changes, clone this repository…
Web-based visual programming editor for Apache Mynewt Embedded OS and Embedded Rust - lupyuen/blockly-mynewt-rust
Then edit the files in Visual Studio Code and open the local copy of
demos/code/index.html in a web browser.
For this visual program…
The Rust code generated is below. The code calls the following C functions imported from Mynewt…
gpio::init_out: Configure a GPIO pin for output
gpio::write: Write to a GPIO pin
gpio::toggle: Toggle a GPIO pin from Low to High and vice versa
os::time_delay: Sleep a while and switch to other tasks
os::task_init: Start a background task
os::sysinit: Initialise Mynewt OS
os::eventq_run, os::eventq_dflt_get: Event loop for Mynewt OS
Are We There Yet?
This is the third article in the long journey for Embedded Rust on Apache Mynewt…
Hosting Embedded Rust apps on Apache Mynewt with STM32 Blue Pill
Build IoT devices the smarter, safer way with Rust and Apache Mynewt
Safer, Simpler Embedded Rust with Apache Mynewt on STM32 Blue Pill
Declarative and Procedural Macros (plus bindgen and tips for Visual Studio Code) to protect Embedded Rust coders
There is still some work to be done to make Visual Programming with Embedded Rust a reality: complete the Rust code generators, generate safe wrappers for the entire Mynewt API, automate the Rust build, test, test and test, …
This article outlines the remaining tasks, I welcome you to join me in making Visual Embedded Rust Programming a reality. Isn’t Visual Rust so darned cool and useful? Drop me a note today!