Repository
https://github.com/rust-lang-nursery/embedded-wg
Introduction
On the introduction post I mention that the current state of doing web development is easier than doing embedded development, especially in programming firmware. There is a huge gap in productivity between web development and firmware development mainly because of the tooling. In this post, I will lay out some concept system that can make firmware development fast (Agile) and also error-free (Fearless).
Post Body
The biggest reason why web (and recently mobile) development easier (Agile) is because of Hot Reload. This makes the development cycle from making a change to seeing the change in action is fast[1]. However, in embedded development, this advantage is initially lost because you need to compile the code and flash the .hex
file to the device. If you ever programming FPGA using Xilinx software you can synthesis your RTL then run it to see the signal diagram to verify your script before loading programs to FPGA. Now let's say when you programming Arduino to verify that your program is correct you need to run it in...Arduino. So why not simulate your program on your laptop?
Well, the concept is derived from Logic Synthesis but with special trick utilizing cross-compiling and some specific feature in some programming language. Now I will lay out how to make developing a firmware microcontroller not only Agile (by compiling to became simulated app) but also Fearless (using a programming language that has strong safety feature).
Cross Compiling
Some way to make the source code can be compiled into the different target is by separating the logic on each target. In Rust you can do it using conditional compilation attribute .
#[cfg(any(unix, windows))]
fn configureWifi() {
// code that can be run on windows or unix OS
println!("call specific OS Syscall for configuring wifi");
}
#[cfg(target_arch = "avr"]
fn configureWifi() {
// code that can be run on Arduino Uno, mega, etc (as long as it based on AVR microcontroller chip)
println!("sending command to configure wifi shield");
}
In that snippet function configureWifi
will be compiled based on the target you choose. Let's say you have myprogram.rs
that call configureWifi();
then run the code using cargo
cargo run myprogram.rs
will output
call specific OS Syscall for configuring wifi
And if you specify the target (which will be cross-compile to that target)
cargo run myprogram.rs --target=avr-unknown-arduino
will output (assuming println!
will behave like Serial.println
in Arduino)
sending command to configure wifi shield
The reason why I choose Rust is that you can utilize macros to make safety port check that it will not compile when the I/O port is in use[2].
In this concept, I will try to use JSON-RPC for sending simulated GPIO data and use macros for some abstraction. I will explain this more in another post including the Simulated App.
Hardware Server Protocol
Well, the concept for hardware-server-protocol is more like a ripoff of language-server-protocol. Here I use RPC to send simulated data for GPIO (SPI, UART, etc) to hardware-server-protocol via IPC. One of the easiest RPC protocol that I can think of is JSON-RPC. The implementation needs to bridge between IPC (which use different implementation depending on OS) and Websocket. The programming language that I can think of mainly because I don't want manually implementing different IPC based on running OS is:
- C# (.NET Core) : using function
NamedPipeServer()
for IPC and vs-streamjsonrpc package for JSON-RPC - NodeJs: using class
net.Socket
for IPC and jayson package for JSON-RPC
Web Component
This is the trickiest part. After implementing hardware-server-protocol, we can build hardware UI component that simulates the behavior of hardware real part (in this case are LED). The Hardware UI Component parts are implemented as WebComponent to make it shareable and can be used in many web-framework. To implement this kind of WebComponent it need to utilize UoM (Unit of Measurement) and CoU (Conversion of Unit) concept/paradigm. This is needed to make an accurate animation based on real-world scale mapped to pixel scale (also to make it Fearless 😆). Some programming language and library that I can think of to do UoM and CoU are:
- Javascript: using mathjs
- F#: no need library because it's built in. Waiting for gh:dotnet-websharper/issue #786 to be resolved
- Rust: using uom. The implementation needs to be mixed with Javascript using rust-native-wasm-loader
The benefit of UoM and CoU are real when you define the usage of your WebComponent like this
<led size="5mm" input-voltage="3.3V" input-current="30mA" scale="10px/mm" />
that will give you SVG of LED which the Lightness (in term of HSL) depend on input-voltage
and input-current
with the SVG width="50"
and height=50
(because size
*scale
=50). To implement this, I need to wait webpack 4 webassembly/experimental
[4] to be stable to avoid unnecesery troubleshooting.
Resources
[1] : https://www.zephyrproject.org/introducing-javascript-runtime-for-zephyr-os/
[2] : http://blog.japaric.io/brave-new-io
[3] : https://www.webcomponents.org/introduction
[4] : https://medium.com/webpack/webpack-4-released-today-6cdb994702d4
[5] : https://github.com/BugReproduction-and-Proposal/BlazorProposal/blob/master/BlazorCli.md#with-usage