Recently one of my customers brought to my attention Nerves. It aims to simplify use of Elixir (functional language leveraging Erlang VM) in embedded systems. This system has couple interesting features that are worth of research and blog post.
First is booting directly to application which is running in BEAM (Erlang VM). Nerves project replace systemd process with programming language virtual machine running application code. Concept is very interesting and I wonder if someone tried to use that with other VMs ie. JVM.
Second Nerves seems to utilize dual image update procedure. In my opinion any development of modern embedded system should start with update system. Any design that you can to your system update arsenal will be useful.
Third, Nerves use Buildroot as build system, which will I’m familiar with. Using popular build systems means simplified support for huge set of platforms (at point of writing this article Buildroot have 142 config files).
Let’s start with documentation
If you don’t want to go through all installation steps and you use Debian testing, you can run:
|
|
Erlang
Checking exact Erlang version for non Erlang developers is trivial:
|
|
Elixir
Checking Elixir version:
|
|
Unfortunately Nerves Project requires at least 1.4.0
, what can be solved by:
|
|
fwup
fwup
have to be installed from deb
package:
|
|
I don’t understand why Nerves Projects used fwup
, when software like
swupdate
from Denx is available. I don’t see difference in feature set and
would say that swupdate
is more flexible and covers more use cases. It looks
like Nerves Project is main user of fwup
.
Maybe it would be worth to consider comparison of fwup
and swupdate
?
nerves_bootstrap
|
|
hello_nerves for BeagleBone Black
|
|
Flashing to SD card
|
|
booting
|
|
It look that things work out of the box and Elixir started and D2 LED blinks continuously.
Nerves booting
It looks like developers configured Linux kernel bootargs
used by U-Boot to
run elrinit
as init process. erlinit
is relatively simple application that
can parse configuration file and do some basic system initialization. Depending
on needs this may be considered quite weird approach. Of course adding systemd
is not best approach for all solutions. For sure having custom init binary
remove need for complex init system and makes updates much smaller. Also this
solution targets dedicated embedded systems that whole purpose is running Elixir
application.
Using custom init binary also limit attack vector to small amount of code. In typical build from Buildroot or Yocto final image contain quite a lot of process run by default. Nerves limit that to one that is needed for very specific use case that can be fully handled by Elixir application. Of course still some hardware setup is needed. In that case only Linux kernel or Elixir application can be attacked.
As one of my associate mention this is very similar approach to Busybox
although here we replace shell with Elixir interpreter, but idea is similar to
have one application that is entry point to the system.
From performance perspective this is also good solution since there a no daemons working in background that consuming resources. Lack of additional processes means that all server type of work have to be written in Elixir.
It would be very interesting to see how this approach can work for other VMs and if there are real world use cases for that.
erlinit & erlexec
erlinit
is MIT licensed /sbin/init
replacement. In general it:
- setup pseudo-filesystems like
/dev
,/proc
and/sys
- setup serial console
- register signal hendlers (
SIGPWR
,SIGUSR1
,SIGTERM
,SIGUSR2
) - forks into cleanup process and new that start
erlexec
elrexec
is mix of C++ and Erlang that aim to control OS processes from Erlang
application.
Source code can be found on Github: erlinit and erlexec.
Note about building natively
Recently I’m huge fan of containers and way this technology can be utilized by
embedded software developers. Installing all dependencies in your environment is
painful and can cause problems if you do not pay attention. Containers give you
ability to separate tools for each project. In that way you create one
Dockerfile
for whole development environment and then share it with your
peers. I believe Nerves Project shall share containers to build system images
instead of maintaining documentation explaining how to setup development for lot
of various environments.
For example steps for Debian required more of jumping between pages and googling then it was worth since correct set of packages solve issue.
Summary
Do you plan to use Nerves in your next embedded systems project ? Maybe you struggle with adapting similar approach for different VM ? Feel free to share your ideas and issues in comments. If you think content valuable please share this help us in providing more content to our blog.