Embedded Linux engineers have a choice to make in June

At Konsulko Group, we’ve participated in the “virtual” developer conferences created out of necessity over the past couple of years. We eagerly awaited the return of the face-to-face meetings of the embedded community.

Our first opportunity was the Embedded Linux Conference in Seattle last September. Although major components were still virtual, those who where able to attend in person experienced the event “together“ in ways that even the best remote simulation cannot achieve.

So we are very much looking forward to ELC (part of Open Source Summit North America 2022) in Austin, Texas, and the return of Embedded World in Nuremberg, Germany. Unfortunately, the pandemic initially forced rescheduling of both. Now they will occur on exactly the same dates (starting June 21, 2022) half a world apart, making it impossible to attend both onsite.

Which conference should you attend?

Unless you live in Texas or Germany, choosing by geography may not be the best option. The conferences are very different.

ELC is the premier event for companies and developers using Linux in embedded products. It gathers the technical experts working on embedded systems and applications for education and collaboration, historically paving the way for transformation in these far reaching areas.

ELC is also always a good time.

For 20 years, Embedded World has combined

  • an exhibition for engineers and technical management, and
  • a world-leading conference at the intersection of applied research and industrial applications.

The trade show is massive, filling several halls, with many of Konsulko’s friends and partners exhibiting year after year. (If you go, be sure to stop by the Automotive Grade Linux stand in Hall 4.)

We hope to see you at one of these important events in June.

Using kernel config fragments to remove an unwanted feature

Adding a feature to a linux-yocto based kernel is fairly well documented. This makes sense because it is the most common thing you might want to do: “My board needs support for this sensor added to our BSP.”

Konsulko Group recently helped a customer that had exactly the opposite problem, a standard feature in linux-intel (which includes linux-yocto.inc and inherits the kernel-yocto class) needed to be removed. The SoC (in the Intel™ “Bay Trail” family) and the off-the-shelf industrial PC had a problem. When USB 3.0 (xHCI) support is enabled, the default BIOS settings (xHCI Mode = Auto) would cause the system to lock-up upon either warm reboot or shutdown. Given that these systems are deeply embedded in the field—where simply “hooking up a display, keyboard and mouse” is cost prohibitive—we needed to find an option that would not prevent OTA updates.

You might think you could apply a patch via SRC_URI to kmeta (yocto-kernel-cache), but this isn’t supported in the Yocto Project kernel tooling. Instead we can apply kernel config fragments that disable the problematic xHCI feature. The trade off is that USB 3.x devices won’t be able to run at full speed, but the systems in question have no need for USB 3.0 (they are a classic IoT gateway use case).

Determining your existing kernel configuration

The first thing you want to do in this situation is determine what your (default) kernel configuration is. In our case, Konsulko and our customer are using the ‘dunfell’ (3.1.x) branch of meta-intel with MACHINE="intel-corei7-64". Upon building an image or the kernel (e.g. bitbake virtual/kernel or bitbake linux-intel), the kernel configuration can be found at the following path:

<build>tmp/work/corei7-64-intel-common-poky-linux/linux-intel/5.4.170+gitAUTOINC+98cce1c95f_36f93ff941-r0/linux-corei7-64-intel-common-standard-build/.config

Where the kernel version is 5.4.170, the (shortened) git commit hash of the kernel cache is 98cce1c95f and the (shortened) git commit hash of the kernel source is 36f93ff941.

Modifying the kernel configuration with menuconfig

The documented way to modify the kernel configuration is with:

bitbake -c menuconfig linux-intel

This approach works fine, but you must remember to copy the resulting .config to defconfig in your recipe’s SRC_URI.

Alternatively you can create your kernel config fragments in the kernel build directory and then add them to your kernel recipe. The fragments can be created with the help of the diffconfig script in the kernel source tree.

Also note that you must have already run:

$ bitbake -c kernel_configme -f linux-intel

or previously built the kernel in order for the .config to be present.

Modifying the kernel configuration with devtool

It will come as no surprise that my preferred way to modify the kernel configuration is to run:

$ devtool menuconfig linux-intel

But you will get an error:

ERROR: No recipe named 'linux-intel' in your workspace

So first we must get the kernel recipe into our workspace:

$ devtool modify linux-intel

Now we are able to run:

$ devtool menuconfig linux-intel

One benefit of this approach is that devtool will run the required steps that need to happen before menuconfig can be run (most notably the do_kernel_configme task).

Determining the changes needed

Regardless of which method you used to run menuconfig, you will now be presented with the text UI:

Since Konsulko and our customer already knew we needed to change the xHCI enablement, we can quickly </> for Search and then enter xHCI.

This gives us several results, but the ones that we care about have [=y](built-in) next to them:

  1. CONFIG_USB_XHCI_HCD
  2. CONFIG_USB_XHCI_PCI
  3. CONFIG_USB_XHCI_PLATFORM

The top level item that needs to be disabled (set to N) is CONFIG_USB_XHCI_HCD:

After this we can spot check the other values are also disabled (by using </> for Search again):
CONFIG_USB_XHCI_PCI and CONFIG_USB_XHCI_PLATFORM:

Satisfied that we have the needed change, we can save our configuration. Press the <E> key or click on < Exit > to exit the sub-menus until you are at the top of the stack. Press the <S> key or click on < Save > to save the configuration. At they prompt, press enter or click on <Yes>.

Now, the benefit of the devtool workflow comes into play, because we are rewarded with:

INFO: Updating config fragment <build>/workspace/sources/linux-intel/oe-local-files/devtool-fragment.cfg

The contents of this file are what you might expect:

# CONFIG_USB_XHCI_HCD is not set

Applying our configuration change

If we don’t already have one, we need a layer into which to put our changes:

$ bitbake-layers create-layer ~/Projects/meta-awesome-bsp

Add the layer to our active layers:

$ bitbake-layers add-layer ~/Projects/meta-awesome-bsp

Create a directory–following the pattern in openembedded-core–for our kernel changes:

$ mkdir -p ~/Projects/meta-awesome-bsp/recipes-kernel/linux

Finish our recipe:

$ devtool finish linux-intel ~/Projects/meta-awesome-bsp

Examine the resulting directory structure:

$ tree ~/Projects/meta-awesome-bsp
/home/<user>/Projects/meta-awesome-bsp
├── conf
│&nbsp;&nbsp; └── layer.conf
├── COPYING.MIT
├── README
├── recipes-example
│&nbsp;&nbsp; └── example
│&nbsp;&nbsp;     └── example_0.1.bb
└── recipes-kernel
    └── linux
        ├── linux-intel
        │&nbsp;&nbsp; └── devtool-fragment.cfg
        └── linux-intel_%.bbappend

Since this might not be the only change to the kernel we will need to make, let us give the fragment a better name:

pushd ~/Projects/meta-awesome/recipes-kernel/linux/linux-intel
mv devtool-fragment.cfg disable-xhci-hcd.cfg

And create an .scc file to give the Yocto Project kernel tooling better hints of how to apply our change:

cat << EOF >> disable-xhci-hcd.scc
# SPDX-License-Identifier: MIT
define KFEATURE_DESCRIPTION "Disable options for xhci (USB 3.0)"
define KFEATURE_COMPATIBILITY board

kconf hardware disable-xhci-hcd.cfg
EOF

And finally make changes to our linux-intel_%.bbappend to reflect these files:

$ cd ..
$ cat linux-intel_%.bbappend
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"

SRC_URI += "\
    file://disable-xhci-hcd.cfg \
    file://disable-xhci-hcd.scc \
"

Now—as long as our layer has high enough priority and no other recipes add kernel config fragments which conflict with our change—we should be able to build the kernel and inspect the resulting .config:

$ popd
$ bitbake linux-intel
$ grep -R XHCI tmp/work/corei7-64-intel-common-poky-linux/linux-intel/5.4.170+gitAUTOINC+98cce1c95f_36f93ff941-r0/linux-corei7-64-intel-common-standard-build/.config
# CONFIG_USB_XHCI_HCD is not set
# CONFIG_USB_ROLES_INTEL_XHCI is not set

We should also be able to run dmesg | grep xhci on the target and we would not expect to see any messages.

Summary

A Konsulko Group customer had a hardware problem that required us to remove a kernel feature. By using tools like devtool, we were able to fairly easily make a change to the kernel configuration and capture those changes in a persistent way with a .cfg fragment and a .bbappend. This approach solved the problem and allowed OTA updates to proceed to these deeply embedded devices in the field. Please contact us to discuss how Konsulko can help you with the unique requirements of your commercial project.

Konsulko Group: The Year in Review 2021

Thanks to our customers, our partners and our dedicated team of engineers, 2021 was a very successful year for Konsulko Group. 

We’ve been chosen to work on important projects in consumer electronics, automotive, medical devices, agriculture, mining, finance, and autonomous vehicles. Our engineers helped our clients, new and old, build outstanding commercial products with Embedded Linux, Yocto Project and OpenEmbedded, as well as deploying Over-the-Air (OTA) software updating.

Partnerships

“Konsulko is a recommended and trusted partner for helping Mender customers and prospects succeed in the Embedded Linux space. They have an excellent team of professionals who will deliver on time and as agreed.”

Thomas Ryd, CEO, mender.io

We continued our strong relationships with mender.io, and with the Linux Foundation and Automotive Grade Linux (AGL). 

We also launched a new partnership with PHYTEC at the Embedded Linux Conference (ELC) in Seattle. Konsulko is providing support and development for PHYTEC customers using their Systems on Modules (SOMs) and Yocto Project Linux distribution.

Conferences

As in previous years, Konsulko engineers were active participants (often virtually) in conferences and developer gatherings, making presentations at ELC and Yocto Project Summits, and writing technical papers on Yocto Project, security, and OTA. We hope for a time in the not-too-distant future when it makes sense for developers from all over the world to gather again face-to-face to share ideas. 

Contributions

As many of our engineers have been working (and playing) with Open Source Software (OSS) for over 20 years, Konsulko Group is proud of our continuing commitment to contribute to the community. Last month we were happy to hear that Konsulko is #3 in contributions to Yocto Project “Non Core,” just behind industry giants ARM and Fujitsu, and ahead of every other software or hardware company.

This was even before we welcomed OSS veteran Tim Orling to the team in December. Tim was recently Core OS Architect and Yocto Project Architect for Intel Corporation, and serves as a maintainer of meta-python and many recipes in openembedded-core. He has authored hundreds of applied patches for openembedded-core and meta-openembedded. 

Doing business with Konsulko Group

As a team we have found that the best way to work with our customers and prospective customers is to provide a high level of transparency about our business processes. This year, we’ve published blogs on scoping the effort required to successfully complete a customer project, and another describing our two models of engagement

  • Konsulko Continuous Time Engagement™ for dedicated engineering resources
  • Konsulko OnDemand Time Engagement™ for high level consulting, on-demand support, and specific tasks within a larger project.

We hope you have found these useful, and we look forward to working with you in 2022.

Choosing the best model to engage with Konsulko Group

As a consulting and services company, Konsulko Group is committed to acting as our customer’s trusted advisor. That extends across our entire business – from the technologies and services we recommend, to our time tracking and billing practices. We’re committed to running our business with the utmost integrity and transparency, following the best industry practices. 

Over the past couple of years, we have written about Konsulko’s Globally Employable Engineers™ based throughout the world and working together remotely (something we have done successfully long before the pandemic). Members of our team have years of software engineering experience, excellent English language skills, and are comfortable working directly with our customers. 

Konsulko engineers could get good jobs anywhere, but they choose to live in their home country, or elsewhere in North America or Europe. Demand for their skills is strong and tapping their talent does not come at an offshore salary cost, so understanding Konsulko’s engagement models can be crucial to matching resources to the job at hand.

Konsulko Continuous Time Engagement™ 

Under this model, sometimes referred to as “dedicated engineering” or “staff augmentation” in the industry, Konsulko provides dedicated and thus guaranteed engineering time for an agreed period. We will allocate the resource(s) to you, whether it is on a full time basis or some other number of hours per week, and those resources will be dedicated to you. 

As such, we will start invoicing for our time as soon as the resources are allocated to you and there is a signed Master Service Agreement (MSA), Statement of Work (SOW) and purchase order (PO) in place. We will not accrue billable time if any of these resources are out for personal reasons, holidays or vacation.

We will, however, accrue all other time, even if we’re blocked from making progress for reasons outside of our control, such as, hardware problems, VPN or other IT issues, access to your internal infrastructure when necessary, or lack of adequate documentation. This guarantees that our engineering resource stays dedicated to your project, so as soon as we get “unblocked” the work can immediately resume.

The Continuous Time Engagement model works well for larger projects with multiple requirements and deliverables,  projects where the requirements are fluid and you need maximum flexibility, or any project where the schedule calls for dedicated resources for the duration of the work. Customers who are willing to get directly involved in managing the hand-offs and task alignment between their own engineering team and Konsulko engineers often find this an efficient way to work with us.

Konsulko OnDemand Time Engagement™

Under this model of engagement, you will be invoiced only for actual time we spend on the project. If we estimate a job will take six engineer weeks and it only takes five, you pay for five weeks not six. Startup time setting up your hardware or working with your IT department to enable access to your infrastructure is considered part of the project and thus billable hours. 

If we get blocked from making progress for reasons such as those mentioned above, we stop accruing time until we are unblocked, and our resources will likely be reassigned to another project. Although we’ll do our best to switch them back to your project as soon as we’re re-enabled, we cannot guarantee the length of the delay, or the time required to get back up to full speed. 

The OnDemand Time Engagement can be best for a large number of projects:

  • Specific tasks within your larger project 
  • Longer term projects without a hard deadline that can be stopped and started as necessary
  • Projects where you reasonably expect to stop and restart the work (such as bring-up of new hardware which almost always results in a respin of the PCB)
  • On-demand support
  • High level consulting

Which is best for you? When you contact us, we will work with you to determine which model works for your requirements and timeline, and do our best to make your engagement with Konsulko Group efficient and memorable for all the right reasons.

The black magic of scoping the effort in software projects

The software industry is notorious for missed schedules and project budgets that end up being double, triple or even higher than original estimates. One of the first managers I worked for, early in my career, joked that when an engineer gives you an estimate, you should double it and then move to the next unit of measure. In his mind, a two weeks estimate thus became four months. This was obviously an exaggeration, but it does point to the magnitude of the problem.

Three reasons for missing an estimate

There are multiple sources for missed estimates. First, there’s the shear complexity of scoping the effort of large projects. 

Second, engineers often think “dev done / it sort of works” as the end point when estimating the time it will take them. 

Lastly, there is the explicit or implicit pressure most engineers feel to come up with an estimate that will be palatable to upper management. The problem is even greater, I believe, if you consider the long hours engineers put in every day, plus many weekends and sometimes even holidays, in order to attempt to make the impossible schedules they’ve signed up for.

Missing schedules and blowing up budgets is not a luxury a professional services company has. Roughly 85%-90% of our projects end up under budget, and even the few that end up over budget are for reasons outside of our control. While there is no precise formula to use to properly scope the effort, I’ll share just a few notes that developers in our space may find useful.

Make sure you make the right assumptions

Your estimates are based on assumptions: 

  • working hardware (no glitches with the components or the PCB itself), 
  • deliverables owed to you by the customer, 
  • documentation that you might not be able to obtain easily and the customer will have to get it for you (due to strict NDAs, for example), 
  • any possible software deliverables by the customer to you, and so on. 

Start by listing your assumptions and make it known that if any of them prove wrong, additional time and budget will likely be required.

Look at specific tasks in the project and lean on past experience when you can

Break down the project into manageable tasks that you think you can estimate but lean back on past experiences with similar projects. One example that developers in the embedded Linux space will recognize is uplifting a BSP from a certain kernel version to the latest stable (same hardware, no new board spins to deal with). It’s easy to look at the list of, say, 10 device drivers that “should just work” and estimate that each one will take a day or two only, and 90% of the time you’ll probably be wrong. 

What we know from experience is that when doing similar work, it took on average, for example, one week per driver. Some may take a few hours; but others will take two weeks, and you don’t know which ones ahead of time. Don’t let the customer pick your estimates apart. Group this effort into a single task, “Uplifting the following device drivers:” and provide only a single estimate for the task.

Take a high level view

If you can’t break down the project into small tasks or perhaps it’s hard or impossible to estimate them, then step back and take a very high level view, or use a mix of approaches. 

We recently completed a project that included, among other tasks, bring-up of brand new hardware and writing some new, rather complex, Linux device drivers from scratch. The drivers we estimated separately, based on prior experience with these types of drivers and the corresponding Linux subsystem. As always, we listed our assumptions. 

The hardware bring-up, on the other hand, is impossible to estimate with precision. Instead, we used completely different high level heuristics once again based on 20+ years of industry experience: looking at past projects of similar complexity, how much time the customer took to go from first board spin to production, how much time we needed to get our work done, how much time the customer required for support and so on. 

Using such heuristics, we came up with an estimate for bringing up the hardware through the first spin (there is always a respin of new boards) and the writing the new drivers. We beat that estimate by a couple of weeks. 

Consider making the estimate Phase 0 of the project

Sometimes you just don’t know until you start working on the project and you’re two or four or more weeks into it. If that’s the case, make that a Phase 0 with the deliverable being a well defined and fleshed out effort estimate and project schedule, one that you can sign up for with a higher degree of confidence. 

These are a few of the ways we look at estimating a software project. As you can see, it’s not “black magic” after all but a multi-faceted approach to accurately scoping the effort. Contact us to learn more and prepare an estimate for your project.

Building Platforms with Secure Over-the-Air Updating

Almost every device in development today requires both over-the-air (OTA) updating capabilities, and up-to-date security with authentication of the device filesystem and encryption of application data storage.

At Konsulko Group, we find that the best approach is to build a secure platform first, starting with the hardware root of trust and establishing a chain of trust by extending the root of trust through each successive component in the system.

  • A first step is to make sure the Universal Boot Loader (U-Boot) is up-to-date. If the device is using an older version, we may port U-Boot support of a more current release. Then we enable signature-based authentication of the device using the U-Boot verified boot feature.
  • To provide authentication of the device filesystem and encryption of application data storage, we often use the Linux kernel Device-Mapper infrastructure to create virtual layers of block devices: dm-verity for root filesystem authentication, dm-crypt for data encryption, and dm-integrity for read/write data volume integrity.
  • Finally, we can integrate Mender I/O support for OTA together with dm-verity and Yocto Project so that device updates can be performed while maintaining the system’s secure chain of trust.

This step-by-step methodology ensures straight-forward and predictable development. Please contact us to discuss how we can help you build a secure platform for OTA updating on your device.

CEO Pete Popov looks back on 2020

As we approach the end of December, it’s time to review a year that we will certainly remember for the rest of our lives. It hasn’t been easy, but all of us at Konsulko Group are still working hard, supporting the open source community and helping our customers build forward-looking products.

Even at the start of 2020, we knew this year would be different. The coronavirus was the talk of CES in January with some companies pulling out at the last minute, and everyone wondering what the global business climate would be in the months ahead.

By the time FOSDEM rolled around a few weeks later, it was clear the virus would disrupt commerce worldwide, and by the end of February, we had to cut short our presence at Embedded World because of new travel restrictions.

Then the world locked down completely. Since at Konsulko Group we all work remotely by design, we didn’t have to adjust our way of developing software, but as it did for everyone, we had to significantly change our face-to-face participation in embedded Linux, Yocto Project and other community events.

We taught ourselves to use video editing tools, and gave “virtual” presentations from our desks at the Embedded Linux Conference North America and Yocto Project Dev Day at the end of June, the virtual Automotive Grade Linux All Member Meeting in mid July, Linaro Connect in September, Virtual ELCE and Yocto Project Virtual Summit Europe at the end of October, and participated in the virtual Automotive Linux Summit the first of December.

In December, we also presented an AGL Webinar, Getting Started with AGL using Raspberry Pi.

Early in the year, we announced that we had become a Mender Authorized Referral Partner, and that important alliance has provided dividends to both Konsulko Group and our customers as the year progressed.

Konsulko engineers continued our series of technical blogs…

Helping Yocto Project work with Python 3

Getting Started with RAUC on Raspberry Pi

How Mender works

Using Rust with Yocto Project

Building a DIY SOHO router, 18 months later

…and we posted six new videos of our presentations:

Building Containers with OpenEmbedded

Highly Scalable Yocto Project Build Automation

Security Hardening with OpenEmbedded / Yocto Project

Open Source License Compliance with Yocto Project

Demo: Using Rust with Yocto Project

Software Update Solutions for Yocto and OpenEmbedded

Still, we have all been touched by the physical and emotional toll of COVID-19. Two of our engineers have endured a bout with the virus (and thankfully recovered). Some of us have family, friends or acquaintances who have become seriously ill or even passed away. We can only hope the post-pandemic world is now in sight.

In the long run, the challenges that 2020 have brought us closer together in many ways, and hopefully taught us valuable lessons that will make us stronger in a better new year.

Building a DIY SOHO router, 18 months later

Building a DIY SOHO router using the Yocto Project build system OpenEmbedded, 18 months later

It’s been around a year since my last post on this project, and 18 months since I posted the article series itself. In the world of home networking equipment that’s practically a lifetime. So it’s worth doing a check-in on this project, I think.

My little router is still going just fine. In terms of things I had talked about earlier in the series, I’m still using the ability to easily roll back a test image to try out backports. Most recently, I tried to add IPv6 Prefix Delegation support to the DHCPv6 client in an older version of systemd. It didn’t work, but with just a reboot I was back to my normal image. As times change, devices at home change, and I’m using the dnsmasq configuration file to document what devices are in the house. Performance? Still doing just great. The next time I do one of these series, my household might have crossed the threshold where newer WiFi standards are in enough devices we own that I want something that handles them, but we aren’t there yet. By then I might also just have a new PCIe card to drop in.

In terms of the article series itself, it’s a testament to the stability of the Yocto Project and everyone who works on it. Since the original posts, Mender has internally upgraded a significant amount, and in turn some of the examples there aren’t quite correct for a modern build. Mender has excellent documentation, however, and it’s been easy to update my build to work all along the way and upgrade from the older version to the new. Everything else? Yes, that’s all still correct. What prompted this particular post is that the Yocto Project has announced another milestone release, and that’s always a good time to make sure my device is up to date. My latest changes were quite literally just renaming the Linux kernel bbappend file and saying the layer is compatible with the new release. That was less work than updating the firewall rules to take in to account both Daylight Savings Time changes and that my kids are a bit older and realistically want to be online a little later.

Using Rust with Yocto Project

by Paul Barker, Konsulko Group

Introduction

Rust is a modern programming language which emerged from Mozilla Research around 2010 and has been stable since 2015 (see the history section of the Wikipedia article). Rust is an excellent fit for embedded software development due to its focus on performance and safety without the overhead of garbage collection or a large language runtime. The zero-cost abstractions provided by Rust support developer productivity, allowing the use of traits, generics, functional programming styles and other high-level approaches in the knowledge that the resulting assembly code will perform just as well as more verbose, hand written lower level code.

Now is a great time to pick up Rust if you work in the Embedded space. The Rust Embedded Working Group has produced an Embedded Rust Book for an audience with existing embedded development knowledge and the Discovery Book for an audience with no embedded experience but a desire to learn. The Linux kernel community has began discussing the use of Rust within the kernel itself and the OpenEmbedded/Yocto Project community is planning to move Rust support into the openembedded-core layer during the next release cycle.

The benefits of Rust largely stem from the language’s memory model, the borrow checker and other features which will be new to most developers learning Rust. The above resources from the Rust Embedded WG along with several published books and online tutorials cover this material well and so it will not be repeated in detail here. However, if you wish to develop software in Rust for production deployment you should expect to invest at least a few weeks in learning the language, assuming existing familiarity with other programming languages like C, Python or Java.

This article will introduce a couple of simple example applications written in Rust, discuss how to compile and run these applications natively on a Linux system using the Cargo build system and show how to create Yocto Project recipes for these applications using the cargo-bitbake tool. Some basic knowledge of the Yocto Project is assumed but no previous experience of Rust should be required.

Getting Started with Rust

In this section we will install Rust on our Linux system and create two simple applications.

Note that it is not necessary to have Rust installed natively in order to build applications and libraries written in Rust under bitbake. However, installing Rust natively does allow us to develop, test and debug applications on the host before we try to cross-compile them and it is an important step to take when learning Rust.

Installing Rust

The recommended way of installing Rust on a Linux system is to download and run the official installation script. When prompted with the installation options it is usually sufficient to select option 1 to use the defaults. This will install Rust in the current user’s home directory and modify the profile files to set necessary environment variables at login.

$ curl https://sh.rustup.rs -sSf | sh

    <output snipped>

Current installation options:


   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1

    <output snipped>

Rust is installed now. Great!

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done
automatically.

To configure your current shell run source $HOME/.cargo/env

After installing Rust you should log out and log back in to ensure that environment variables are set correctly.

Hello, World

As is traditional, we will begin by looking at a “Hello, World” application.

Each Rust application or library should have its own project directory. Within this directory, the source code is usually placed in a src directory and the top level directory contains the Cargo config file for the project
and any other collateral files such as a README file, LICENSE file, etc.

To create our project directory and populate it with initial files we can use the cargo init command:

$ cargo init hello-rs
     Created binary (application) package

Within our new hello-rs directory, this command creates an initial source file in src/main.rs with the following contents:

fn main() {
    println!("Hello, world!");
}

This makes our job of writing a Hello World application very simple – no code modifications are needed!

The cargo init command also creates a Cargo.toml file in our project directory to store project configuration and metadata:

[package]
name = "hello-rs"
version = "0.1.0"
authors = ["Paul Barker <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

We should test our new Hello World application natively before we try to cross-compile it under bitbake. To do this we can use the cargo build and cargo run commands:

$ cargo build
   Compiling hello v0.1.0 (/home/pbarker/Projects/Rust/rust/hello-rs)
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/hello-rs`
Hello, world!

The last stage for our hello world application is to publish it as a git repository so that it can be fetched and built in our Yocto Project environment. We should create a LICENSE file and a README file in the top level of the project for the benefit of anyone who wants to reuse our code. My preference is for the Apache license version 2.0 but feel free to use any appropriate open source license here.

We should also add some extra metadata to the Cargo.toml file to specify the license, briefly describe the project and link to the location where we will be publishing the repository. This metadata will be used by cargo-bitbake when we generate a recipe for our application. In my case the repository will be published to my GitLab account.

--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,9 @@ name = "hello-rs"
 version = "0.1.0"
 authors = ["Paul Barker <[email protected]>"]
 edition = "2018"
+license = "Apache-2.0"
+description = "Hello World application"
+repository = "https://gitlab.com/pbarker.dev/rust/hello-rs.git"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

To finish up, commit the project files to a git repository and push to a location which can be reached when building using Yocto Project. Alternatively, you can make use of the hello-rs repository I published under my GitLab account.

The Hello World application above will demonstrate only part of the capabilities of the cargo-bitbake tool and the Rust support in Yocto Project. To see how Rust dependencies are handled in Yocto Project we’ll need an application which actually depends on a Rust library (known as a crate). The print-rand application will fill this role as it uses the rand crate to generate random numbers.

As before we will start by creating the project using cargo init:

$ cargo init print-rand
     Created binary (application) package

We will now modify the src/main.rs file to generate and print a random number:

use rand::prelude::*;

fn main() {
    let x: u32 = random();
    println!("x = {}", x);
}

We will also modify the Cargo.toml file to list the rand crate as a dependency:

[package]
name = "print-rand"
version = "0.1.0"
authors = ["Paul Barker <[email protected]>"]
edition = "2018"

[dependencies]
rand = "0.7"

We can build and test this application in a similar way to the previous Hello World app. Note that each dependency is downloaded and built along the way:

$ cargo build
   Compiling libc v0.2.77
   Compiling getrandom v0.1.15
   Compiling cfg-if v0.1.10
   Compiling ppv-lite86 v0.2.9
   Compiling rand_core v0.5.1
   Compiling rand_chacha v0.2.2
   Compiling rand v0.7.3
   Compiling print-rand v0.1.0 (/home/pbarker/Projects/Rust/rust/print-rand)
    Finished dev [unoptimized + debuginfo] target(s) in 3.60s
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/print-rand`
x = 643356417

As before, we should add LICENSE and README files at this stage and extend the metadata in the Cargo.toml file:

--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,9 @@ name = "print-rand"
 version = "0.1.0"
 authors = ["Paul Barker <[email protected]>"]
 edition = "2018"
+license = "Apache-2.0"
+description = "Print a random number"
+repository = "https://gitlab.com/pbarker.dev/rust/print-rand.git"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Lastly, commit the project files to a git repository and push to a public location. As before you may alternatively make use of the print-rand repository I published under my GitLab account.

Using cargo-bitbake

Now that we have created a couple of simple Rust applications and published them we can look at creating bitbake recipes using the cargo-bitbake tool. The first step of this process is to install the tool itself:

$ cargo install cargo-bitbake

    <output snipped>

   Compiling cargo-bitbake v0.3.14
    Finished release [optimized] target(s) in 12m 30s
  Installing /home/debian/.cargo/bin/cargo-bitbake
   Installed package `cargo-bitbake v0.3.14` (executable `cargo-bitbake`)

Before we run cargo bitbake for each our projects we should ensure that all changes are committed and pushed to the remote repository. We should also check the remote URL for each repository as this will be used to set SRC_URI. If the remote URL uses SSH access then you should ensure that this can be reached using an SSH key from the Yocto build environment or switch to HTTPS access.

Once we’re happy with the state of our repository we can run cargo bitbake in the top directory of our hello-rs project (note that we use a space not a dash in the command here):

$ cargo bitbake
No package.homepage set in your Cargo.toml, trying package.repository
Wrote: hello_0.1.0.bb

The message printed by cargo bitbake indicates that the repository entry in our Cargo.toml file was used as the homepage URL since we did not specify a separate homepage.

We can now look at the generated recipe file hello-rs_0.1.0.bb:

# Auto-Generated by cargo-bitbake 0.3.14
#
inherit cargo

# If this is git based prefer versioned ones if they exist
# DEFAULT_PREFERENCE = "-1"

# how to get hello-rs could be as easy as but default to a git checkout:
# SRC_URI += "crate://crates.io/hello-rs/0.1.0"
SRC_URI += "git://gitlab.com/pbarker.dev/rust/hello-rs.git;protocol=https;nobranch=1;branch=dev"
SRCREV = "cec42fb0d147e4a4b271256c475620ff627c8856"
S = "${WORKDIR}/git"
CARGO_SRC_DIR = ""


# please note if you have entries that do not begin with crate://
# you must change them to how that package can be fetched
SRC_URI += " \
"



# FIXME: update generateme with the real MD5 of the license file
LIC_FILES_CHKSUM = " \
    file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327 \
"

SUMMARY = "Hello World application"
HOMEPAGE = "https://gitlab.com/pbarker.dev/rust/hello-rs.git"
LICENSE = "Apache-2.0"

# includes this file if it exists but does not fail
# this is useful for anything you may want to override from
# what cargo-bitbake generates.
include hello-rs-${PV}.inc
include hello-rs.inc

As we noted above, the SRC_URI and SRCREV entries are based on the remote URI and the currently checked out commit of our local git repository. The SUMMARYHOMEPAGE and LICENSE entries are based on the metadata in our Cargo.toml file. The LIC_FILES_CHKSUM entry is set based on the LICENSE file in our project.

We can also generate a recipe for the print-rand project by running cargo bitbake in the top directory of this project:

$ cargo bitbake
No package.homepage set in your Cargo.toml, trying package.repository
Wrote: print-rand_0.1.0.bb

The print-rand_0.1.0.bb recipe is very similar to the previous recipe for our hello world application. The SRC_URISRCREVSUMMARY and HOMEPAGE are changed to the appropriate values for this project. The SRC_URI variable is extended with a list of the dependency crates required by this project, this includes not just the rand crate that we explicitly listed as a dependency in our Cargo.toml file but also all the recursive dependencies of this crate.

# Auto-Generated by cargo-bitbake 0.3.14
#
inherit cargo

# If this is git based prefer versioned ones if they exist
# DEFAULT_PREFERENCE = "-1"

# how to get print-rand could be as easy as but default to a git checkout:
# SRC_URI += "crate://crates.io/print-rand/0.1.0"
SRC_URI += "git://gitlab.com/pbarker.dev/rust/print-rand.git;protocol=https;nobranch=1;branch=dev"
SRCREV = "3397247f929f28d70adbb65d3990dc72699553bb"
S = "${WORKDIR}/git"
CARGO_SRC_DIR = ""


# please note if you have entries that do not begin with crate://
# you must change them to how that package can be fetched
SRC_URI += " \
    crate://crates.io/cfg-if/0.1.10 \
    crate://crates.io/getrandom/0.1.15 \
    crate://crates.io/libc/0.2.79 \
    crate://crates.io/ppv-lite86/0.2.9 \
    crate://crates.io/rand/0.7.3 \
    crate://crates.io/rand_chacha/0.2.2 \
    crate://crates.io/rand_core/0.5.1 \
    crate://crates.io/rand_hc/0.2.0 \
    crate://crates.io/wasi/0.9.0+wasi-snapshot-preview1 \
"



# FIXME: update generateme with the real MD5 of the license file
LIC_FILES_CHKSUM = " \
    file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327 \
"

SUMMARY = "Print a random number"
HOMEPAGE = "https://gitlab.com/pbarker.dev/rust/print-rand.git"
LICENSE = "Apache-2.0"

# includes this file if it exists but does not fail
# this is useful for anything you may want to override from
# what cargo-bitbake generates.
include print-rand-${PV}.inc
include print-rand.inc

We can now add these recipes to a Yocto Project layer and build them using bitbake. Support for the Rust toolchain in Yocto Project is provided by the meta-rust layer so this layer must be included before these recipes can be built. As there are many ways to put together a Yocto Project build we won’t cover this in this blog post. However, you can see a walkthrough of this process in the Using Rust with Yocto Project demo presented at theYocto Project Summit Europe 2020.

How Mender works

by Tom Rini, VP Engineering

Software Update solutions are a key part of our services offering. For open source over-the-air updates, we often we recommend and work with mender.io. In fact, Konsulko Group is a Mender Authorized Referral Partner. Recently, a prospective customer expressed an interest in knowing more about how Mender works. Here’s the brief, informal introduction to member.io that I prepared, and now I’m sharing with you.

As a high level starting point, https://mender.io/how-it-works provides a good overview of what’s supported and what it covers. In short, Mender starts off by providing support for a traditional “A/B” approach to system updates, where if the update isn’t marked as valid (and there’s hooks for the application(s) to verify the system before this is done), it’s assumed invalid and the system will roll-back automatically. While “OTA” implies over the network, it can just as easily be done by providing (and validating) a USB key that contains an update.

One of the reasons we recommend Mender is that it has very good in-depth documentation. The starting point for all of that is https://docs.mender.io/2.4/ which covers all of the topic starting from how to implement Mender support in a device and including how to create your own server infrastructure if you don’t want to use their paid service. While there are a number of important pages there, one that I like to highlight is https://docs.mender.io/2.4/artifacts/state-scripts as it shows the state machine for an update and talks about some of the common use cases that come up for user interaction or dealing with failures.

Another place I want to call out is https://docs.mender.io/2.4/devices/update-modules which is also mentioned in the first link. This is how Mender is extended to provide updates for other parts of the system that are not the rootfs itself.  Since updating a Docker container is something that has been mentioned before I want to also note https://hub.mender.io/t/docker/324 as it is a well supported module for this specific case.

I hope you find this information useful. Please contact us if you have specific questions. We’re looking forward to talking to you about your own specific OTA needs.