Auto and Structured Binding

This article is just a short follow-up article for “Write Less Code using the ‘auto’ Keyword”. Structured binding is something handy, introduced in C++17. Therefore, only the latest compiler will support it.

If you are mainly write embedded code, you may skip this article, because it will take some years until C++17 support is available for your platform. If you also write desktop code, read on, you may like this feature.

Find a detailed reference about structural binding here. The following sections will explain the feature using several use cases.

Multiple Return Values using Tuples

Let us write a function to convert a string into an integer. For error handling, we like to use parameters or return values, but no exceptions. You may consider these variants:

uint32_t getInt(const std::string &text, bool *ok);
uint32_t getInt(const std::string &text, bool &ok);
bool getInt(const std::string &text, uint32_t &result);

The problem is, if you like to use the full range of the uint32_t, you need a second value to report of the conversion was successful or not. It may be a bool, or even better an enum to report this result.

#include <iostream>
#include <cstdint>
#include <string>
#include <limits>

uint32_t safeMultiplication(uint32_t a, uint32_t b, bool *ok = nullptr) {
    uint32_t result;
    if (__builtin_mul_overflow(a, b, &result)) {
        if (ok != nullptr) {
            *ok = false;
        }
        return 0;
    }
    if (ok != nullptr) {
        *ok = true;
    }
    return result;
}

uint32_t safeAdd(uint32_t a, uint32_t b, bool *ok = nullptr) {
    uint32_t result;
    if (__builtin_add_overflow(a, b, &result)) {
        if (ok != nullptr) {
            *ok = false;
        }
        return 0;
    }
    if (ok != nullptr) {
        *ok = true;
    }
    return result;
}

uint32_t getInt(const std::string &text, bool *ok = nullptr) {
    uint32_t result = 0;
    uint32_t factor = 1;
    bool factorValid = true;
    for (auto it = text.rbegin(); it != text.rend(); ++it) {
        if (*it < '0' || *it > '9') {
            if (ok != nullptr) {
                *ok = false;
            }
            return 0;
        }
        auto value = static_cast<uint32_t>(*it - '0');
        if (value > 0) {
            if (!factorValid) {
                if (ok != nullptr) {
                    *ok = false;
                }
                return 0;
            }
            bool multiplicationOk;
            value = safeMultiplication(factor, value, &multiplicationOk);
            if (!multiplicationOk) {
                if (ok != nullptr) {
                    *ok = false;
                }
                return 0;
            }
            bool additionOk;
            result = safeAdd(result, value, &additionOk);
            if (!additionOk) {
                if (ok != nullptr) {
                    *ok = false;
                }
                return 0;
            }
        }
        if (factorValid) {
            bool multiplicationOk;
            factor = safeMultiplication(factor, 10u, &multiplicationOk);
            if (!multiplicationOk) {
                factorValid = false;
            }
        }
    }
    if (ok != nullptr) {
        *ok = true;
    }
    return result;
}

void testText(const std::string &text) {
    bool ok;
    const auto number = getInt(text, &ok);
    std::cout << text << " -> " << number << " ok: " << (ok ? "yes" : "no") << std::endl;
}

int main(int argc, const char * argv[]) {
    testText("text");
    testText("4294967295");
    testText("4294967296");
    testText("00004294967295");
    testText("x123");
    return 0;
}

The example code works well. For simplicity, it uses two built-in functions __builtin_add_overflow and __builtin_mul_overflow from the GCC and clang compiler.

Using two return values would simplify the interface. It can be done using std::tuple and structured binding.

#include <iostream>
#include <cstdint>
#include <string>
#include <limits>
#include <tuple>

using Result = std::tuple<uint32_t, bool>;

Result safeMultiplication(uint32_t a, uint32_t b) {
    uint32_t result;
    if (__builtin_mul_overflow(a, b, &result)) {
        return std::make_tuple(0, false);
    }
    return std::make_tuple(result, true);
}

Result safeAdd(uint32_t a, uint32_t b) {
    uint32_t result;
    if (__builtin_add_overflow(a, b, &result)) {
        return std::make_tuple(0, false);
    }
    return std::make_tuple(result, true);
}

Result getInt(const std::string &text) {
    uint32_t result = 0;
    uint32_t factor = 1;
    bool factorValid = true;
    for (auto it = text.rbegin(); it != text.rend(); ++it) {
        if (*it < '0' || *it > '9') {
            return std::make_tuple(0, false);
        }
        const auto digitValue = static_cast<uint32_t>(*it - '0');
        if (digitValue > 0) {
            if (!factorValid) {
                return std::make_tuple(0, false);
            }
            const auto[value, multiplicationOk] = safeMultiplication(factor, digitValue);
            if (!multiplicationOk) {
                return std::make_tuple(0, false);
            }
            bool additionOk;
            std::tie(result, additionOk) = safeAdd(result, value);
            if (!additionOk) {
                return std::make_tuple(0, false);
            }
        }
        if (factorValid) {
            bool multiplicationOk;
            std::tie(factor, multiplicationOk) = safeMultiplication(factor, 10u);
            if (!multiplicationOk) {
                factorValid = false;
            }
        }
    }
    return std::make_tuple(result, true);
}

void testText(const std::string &text) {
    const auto[number, ok] = getInt(text);
    std::cout << text << " -> " << number << " ok: " << (ok ? "yes" : "no") << std::endl;
}

int main(int argc, const char * argv[]) {
    testText("text");
    testText("4294967295");
    testText("4294967296");
    testText("00004294967295");
    testText("x123");
    return 0;
}

It simplified the code with just a single downside. While the initial implementation made the ok optional, the new version will get it for each result.

Bind Elements of a Struct

You can bind to members of any struct using the same syntax:

struct Result {
    uint32_t value;
    bool ok;
}

Result result = {10, true}

int main() {
    auto[value, ok] = result;
}

If we use a struct in our example, it simplifies several lines, but requires some additions elsewhere.

#include <iostream>
#include <cstdint>
#include <string>
#include <limits>
#include <tuple>

struct Result {
    uint32_t value;
    bool ok;
    constexpr static Result error() { return {0, false}; }
    constexpr static Result success(uint32_t value) { return {value, true}; }
};

Result safeMultiplication(uint32_t a, uint32_t b) {
    uint32_t result;
    if (__builtin_mul_overflow(a, b, &result)) {
        return Result::error();
    }
    return Result::success(result);
}

Result safeAdd(uint32_t a, uint32_t b) {
    uint32_t result;
    if (__builtin_add_overflow(a, b, &result)) {
        return Result::error();
    }
    return Result::success(result);
}

Result getInt(const std::string &text) {
    uint32_t result = 0;
    uint32_t factor = 1;
    bool factorValid = true;
    for (auto it = text.rbegin(); it != text.rend(); ++it) {
        if (*it < '0' || *it > '9') {
            return Result::error();
        }
        const auto digitValue = static_cast<uint32_t>(*it - '0');
        if (digitValue > 0) {
            if (!factorValid) {
                return Result::error();
            }
            const auto[value, multiplicationOk] = safeMultiplication(factor, digitValue);
            if (!multiplicationOk) {
                return Result::error();
            }
            const auto[immediateResult, additionOk] = safeAdd(result, value);
            if (!additionOk) {
                return Result::error();
            }
            result = immediateResult;
        }
        if (factorValid) {
            const auto[newFactor, multiplicationOk] = safeMultiplication(factor, 10u);
            if (!multiplicationOk) {
                factorValid = false;
            }
            factor = newFactor;
        }
    }
    return Result::success(result);
}

void testText(const std::string &text) {
    const auto[number, ok] = getInt(text);
    std::cout << text << " -> " << number << " ok: " << (ok ? "yes" : "no") << std::endl;
}

int main(int argc, const char * argv[]) {
    testText("text");
    testText("4294967295");
    testText("4294967296");
    testText("00004294967295");
    testText("x123");
    return 0;
}

The struct made the status optional, because we can write a line like this:

const auto value = getInt(text).value;

Or only check if the value is valid:

if (getInt(text).ok) {
    // ...
}

Binding to an Array

Binding values from an array is another interesting use:

#include <iostream>

int table[4][4] = {
    { 1,  2,  3,  4},
    { 5,  6,  7,  8},
    { 9, 10, 11, 12},
    {13, 14, 15, 16},
};

int main(int argc, const char * argv[]) {
    for (const auto &row : table) {
        const auto [a, b, c, d] = row;
        std::cout << a << ", " << b << ", " << c << ", " << d << std::endl;
    }
    return 0;
}

References

I found structural binding also useful creating references to values for actual modification, or const references to avoid copy operations.

#include <iostream>

int table[4][4] = {
    { 1,  2,  3,  4},
    { 5,  6,  7,  8},
    { 9, 10, 11, 12},
    {13, 14, 15, 16},
};

int main(int argc, const char * argv[]) {
    for (auto &row : table) {
        auto& [a, b, c, d] = row;
        std::swap(a, d);
        std::swap(b, c);
    }
    for (const auto &row : table) {
        const auto& [a, b, c, d] = row;
        std::cout << a << ", " << b << ", " << c << ", " << d << std::endl;
    }
    return 0;
}

Learn More

Conclusion

If you already use a C++17 capable compiler, like the GCC, clang or Visual Studio, try to use structural binding in your project. You can find a table with the current compiler support in this document.

  • It can create cleaner interfaces, where all values are returned with the return statement.
  • Returned objects can be directly split into variables.
  • Working with std::tuple values is straightforward.
  • Array tables can be accessed in a column like way.

If you have questions, miss some information or have any feedback, feel free to add a comment below.

Guide to Modular Firmware

This article is for embedded software developers with good knowledge of C or C++, but struggle with large and complex projects.

If you learn developing embedded code, e.g. using the Arduino IDE, you find plenty of small example programs. It is helpful for a quick start, but as soon your project grows, help about software design is rare.

In contrast, if you learn software development for desktop applications, project structures and software design is an integral part of the learning process.

With this short article, I will give you a simple guideline, how you can build a modular structure for your firmware, which will keep your code clean and maintainable for large and complex projects.

Refactor your Code

If you start a new project, you can already prepare the structures as described. I assume in this article you already have a working firmware but need to improve the code quality.

Improving the code in an iterative process is called refactoring. Testing is an integral part of this process. After each small change, you test if the software is still working as expected.

In desktop application development, there are unit tests to ensure the integrity of smaller modules. I found it difficult to apply unit tests to embedded code, if not for small independent functions or modules. Therefore you have to use a simple run-time test of your software, to make sure it is still working as expected.

Refactoring only changes the code, but not the functionality. Even if you change names, move code around and change implementations, the function of your code stays exactly the same. It is important you either change or extend functionality or do refactoring, but never do both at the same time (or in the same commit).

Use a Version Control System

Changing your code without version history is a bad idea. If you do not already manage your code in a version control system, now it is the time to start using one.

If you never used a version control system before, use GIT and read one of the many tutorials on how to use it. There are graphical user interfaces for any operating system, so you do not have to work on the console. It does not matter how you manage your code – it is important that you use a version control system.

After each small successful change, you should commit a new version. If you run into troubles at a later stage, you can easily analyse every change you did on the code and go back to the last working version.

The Demo Setup

If you like to follow along using the real demo setup, you will need an Arduino Uno, three LEDs with matching resistors and two pushbuttons. The example code expects a circuit shown in the next illustration.

A Shockingly Bad Example to Start With

The example code to start with is something I sadly see often. Please open a second browser window with the code at the following URL:

https://github.com/LuckyResistor/guide-modular-firmware/blob/master/fade_demo_01/fade_demo_01.ino

I can not use a really complex firmware for this article, and your source code may be in a different state. Nevertheless, this example code contains most of the elements I like to discuss.

Because of the length of the code, I will just link to the full examples. The code snippets in the article should have the correct line numbers, so you can easily find the locations.

Continue reading Guide to Modular Firmware

It’s Time to Use #pragma once

In my opinion, preprocessor macros and the outdated #include mechanism are one of the worst parts of the C++ language. It is not just these things are causing a lot of problems, even more, it is very time consuming to find them.

This article will focus on #pragma once. In the past, I already wrote articles about how to avoid macros and why you should use namespaces.

While I usually focus on embedded development on this blog, this topic especially aplies to desktop software. It is valid not only for C++, but also C programs.

As usual, I try to cover the topic in detail to bridge any knowledge gaps you may have.

What is the Problem with Macro Header Guards?

Macro based header guards can lead to unexpected problems. In the following sections, I will explain the core concepts and demonstrate the problem using a simple example.

Compiling Units

In C and C++ a compile unit usually consists of a header (.h or .hpp) and implementation file (.c or .cpp). It is the lowest level of encapsulation. The header file contains the interface of the unit, while the cpp or c file contains the implementation.

Continue reading It’s Time to Use #pragma once

Write Less Code using the “auto” Keyword

The auto keyword was introduced with C++11. It reduces the amount of code you have to write, reduces repetitive code and the number of required changes. Sadly, many C++ developers are not aware of how useful this keyword is. Especially embedded code can gain a lot by its usage.

In this article, I try to explain a number of useful cases of the auto keyword, using Arduino example code. The same principles are valid for any embedded environment which is using a modern C++ compiler. The C++11 standard is eight years old, and meanwhile, every C++ compiler should support it.

The examples are written for Arduino or Adafruit SAMD boards using the Arduino IDE. The toolchain for these boards use a compiler which supports more features explained in this article. Using auto with AVR code is possible too, just give it a try.

The “auto” Keyword

The auto keyword was introduced to instruct the compiler to automatically deduce a type from the given context. In programming language terms, they call this a placeholder type specifier.

C++11 mainly introduced the auto keyword for variable declarations. These are the main focus of this article.

Simple Variable Declarations

At any point in your code, where you declare a variable which is initialized, you can use auto instead of a type.

auto variable = <some expression>
Continue reading Write Less Code using the “auto” Keyword

How to use Unit Types for Safe and Readable Code

In your program code, you often have to deal with values which have a given unit. The problem is, this unit is often completely lost. If you do not add the unit as a comment or as part of the variable name, there is the risk you accidentally make wrong conversions.

This article describes how you declare new types to handle the units for common time values. It also explains how to use user defined literals so you can write values like 100_ms in your code.

The shown example code will only work with 32-bit processors, like the SAM D21 used in the Arduino Zero or Adafruit Feather M0 platform. It is possible to adapt the code to compile on the AVR toolchain for Arduino Uno and similar, but this is not part of this article.

Another requirement is your C++ compiler has to support the language standard C++11. This standard is eight years old and should meanwhile be supported by all compilers.

What is the Issue not Using Units?

Imagine an interface where you set the delay of some action:

void setActionDelay(uint32_t delay);

The problem with this interface is the lack of unit information. Do you pass seconds, milliseconds, nanoseconds or any other unit to this function? If you do not document the function, the user has to guess or study the implementation of the function.

/// Set the Delay for the action.
///
/// @param delay The delay in milliseconds.
///
void setActionDelay(uint32_t delay);

Much better. Now the interface user can read the API documentation and is aware you expect milliseconds. They will start using the code like this:

void setup() {
  // ...
  setActionDelay(1000);
  // ...
}

Again, the unit is lost. If someone else is reading this code, they have to look up the API documentation to find out about the millisecond unit and to know, 1000 means 1000 milliseconds.

Decorate Names is Ugly

A standard solution is to decorate function and variable names. The resulting interface looks like this:

Continue reading How to use Unit Types for Safe and Readable Code

Real Time Counter and Integer Overflow

After writing the article about event-based firmware, I realised there are some misunderstandings how real-time counter are working and should be used. Especially there is a misconception about an imagined problem if such counter overflows. In this article, I try to explain this topic in more detail, using example code for the Arduino IDE.

What is a Real-Time Counter?

A real-time counter is a variable or register which increases at a given time interval. The term real-time may be confusing. It just states the fact this counter ideally does count independently of any other parts of the firmware. Therefore, even if the main code stops at one point and waiting for a specific condition, the real-time counter will get increased in the “background” at the given interval.

How is the Real-Time Counter Implemented?

These counters are usually implemented using a hardware timer and an interrupt. For the Arduino platform, a hardware timer is set to create an interrupt each millisecond. If you can find most of this code in the file wired.c (AVR) or delay.c (SAMD). The following code is a summary of the relevant parts of the simpler implementation for the SAMD platform:

static volatile uint32_t _ulTickCount=0;

unsigned long millis(void)
{
  return _ulTickCount;
}

void SysTick_DefaultHandler(void)
{
  _ulTickCount++;
}

You see the variable _ulTickCount which is an unsigned 32bit integer. It is marked as volatile to tell the compiler, this variable can be modified from an interrupt and reads can not be optimised away.

You can access the current value using the millis() function. Interrupts do not need to be blocked while reading this value, because reading a single 32bit value is an atomic operation for the SAMD platform. It means, it is not possible to process an interrupt in the middle of reading the integer. The interrupt will occur before or after reading the value, but never e.g. after reading the first byte of the integer value. For some platforms, this can be a problem.

The last function is SysTick_DefaultHandler which just increases the variable by one every millisecond.

What is Integer Overflow?

An integer overflow happens, if you add to an integer value and the result exceeds the maximum number it can store. You can easily verify this using the following code:

Continue reading Real Time Counter and Integer Overflow

Class or Module for Singletons?

Should you use a class or a module with a namespace for a singleton interface in your firmware? I found there are many misunderstandings which lead beginners to make a wrong decision in this matter. With this article, I try to visualize these misunderstandings with simple example code for the Arduino platform.

Before we start, as with all of these topics, there is no simple rule, and there are a lot of exceptions. In the end, it heavily depends on the compiler and architecture you use.

The Example Use Case

I like to write simple driver code for my firmware, which flashes two LEDs for a given duration. The used PINs for the LEDs shall be configurable. In my main loop, I will flash the two LEDs at different durations.

The use case is no real-world example, but it contains all elements of configuration, initialization and usage.

Using a Simple Class

For the first test case, I write a simple class, without constructor and all required methods for the use case.

Continue reading Class or Module for Singletons?

Event-based Firmware (Part 2/2)

In the first part of this article, we explored the general concept of event-based firmware. For the first part, please click this link.

The introduced concepts were directly tailored to one specific firmware. Now let us develop the concepts further to build an event system which can be integrated in many different applications.

Let us analyze the last exampe:

blink8.ino

#include "BlinkLed.hpp"
#include "Event.hpp"

Event gBlinkLedEvent;

void setup() {
  BlinkLed::initialize();
  gBlinkLedEvent.start(10);
}

void loop() {
  const auto currentTime = millis();
  if (gBlinkLedEvent.isReady(currentTime)) {
    const auto scheduledDelay = BlinkLed::event();
    gBlinkLedEvent.scheduleNext(scheduledDelay);
  }
  while (millis() == currentTime) {}
}

What makes this code static?

First, the variable gBlinkLedEvent is directly tied to this single event. It can not be reused by other events.

Second, the if (gBlinkLedEvent.isReady(currentTime)) { ... } code is repetitive for all events. If you have repetitive code, it is usually a sign of bad design. While there are very few cases where repetitive code is acceptable, usually it should be removed using structures, loops and tables.

Backtrack for a New Direction

Let us address the issue with the fixed function call first. To solve this, we have to backtrack and enter a new direction. The next example consists of the files blink9.ino, Event.hpp and Event.cpp:

Continue reading Event-based Firmware (Part 2/2)

Event-based Firmware (Part 1/2)

In this article, I explain the event-based approach for writing an embedded firmware. While I use the term event-based, it is similar to events systems used for desktop application but much more straightforward. It is nothing new or innovative; the shown approach is just good practice to keep your firmware modular and extensible.

I will guide you in small iterations, using practical examples, through this complex topic. You can stop at any point and start improving your code to that level of complexity you fully understand and can handle.

What are Event-Driven Applications?

For desktop applications, an event-driven approach is chosen because the software always reacts to events generated by the user. Each movement of the mouse, key and mouse button press and release will generate an event. These events are pushed into a queue and processed in an event loop.

The second important source of events is timers. Either fixed timers, which will e.g. generate an event every 100ms – or delayed timers which will create an event after a defined delay.

For embedded code, we mostly use timers as an event source. If implemented correctly, you can easily generate events from button presses, interrupts or other asynchronous sources as well.

In this article, I will focus on events generated by timers. These will solve most of the problems in firmware. Asynchronous input sources can be implemented using polling to integrate them into the event-based approach.

The Blink Example – Without Events

Let us start with a simple example application, you can find for any platform. For this article, I will explain everything based on examples for the Arduino Uno platform, using the Arduino IDE. I do this because anyone can easily reproduce the examples, and it will remove the additional complexity of the actual hardware access layer from the code.

Nevertheless, the shown concepts are meant to be used on any platform, especially for real-world applications. I try to explain the core concepts to you, so you will be able to apply them in any situation.

The Simple Blink Example

blink1.ino

const uint8_t cOrangeLedPin = 13;

void setup() {
  pinMode(cOrangeLedPin, OUTPUT);
}

void loop() {
  digitalWrite(cOrangeLedPin, HIGH);
  delay(1000);
  digitalWrite(cOrangeLedPin, LOW);
  delay(1000);
}

The Example Explained

If you are not familiar with the Arduino libraries: There are two predefined functions, setup() and loop(). The setup() function is called once after the start to set up things and the loop() function is called endlessly afterwards. This structure is already prepared for the event-based approach.

In the blink example above, I set the pin where a red or orange LED is attached as output, using pinMode() and in the loop, I toggle the output from low to high and back with a delay of one second.

While this example works perfectly, it is not very extensible or modular. If you like to e.g. blink a second LED on another pin, test the states of several sensors and buttons, you will get into trouble.

Introducing a Real-Time Counter to use Time Points

Instead of just blocking the CPU until an amount of time has passed (using the delay function), a better approach is to introduce a real-time counter. Often this is also called real-time clock, which can easily get confused with the special chips which hold the current date and time. This is just a counter which starts at zero at the start of the firmware and is increased every millisecond or another time unit.

If you write a firmware from scratch, you use a hardware timer and interrupts to create a timer like this:

// pseudocode:

uint32_t gTimer = 0;

setup {
    // setup the hardware timer to create an interrupt
    // every millisecond.
}

interrupt {
    ++gTimer;
}

In the Arduino environment, this is already implemented, and there is the function millis() to get the current value of the counter. The counter will flip over at the highest value and restart at zero.

Continue reading Event-based Firmware (Part 1/2)

A New Modular CMake Based Toolchain for Feather M0 HAL

In the past months, I developed firmware for a few Adafruit Feather M0 based projects. The reason why I use the Adafruit Feather platform, instead of using an MCU directly, is for modularity.

By using a board on sockets, it can be replaced at any later time with a more powerful one – or by one with additional peripherals.

The only downside of these boards is the programming toolchain. Either you use the Arduino IDE, or solder wires to the board to program the MCU directly using, e.g. Atmel Studio.

Using the Arduino IDE, I am bound to some really horrible written libraries. It is probably a good thing if you are really new to the concept of programming and just likes to get things working. In the long run, I think using these libraries will lead to bad coding habits. Yet, I like the simplicity of using this IDE – compiling and uploading the firmware using the bootloader.

The Atmel IDE is a pure Windows solution with a professional Visual Studio based IDE, introducing unnecessary complexity. The MCU is usually programmed directly, overwriting the bootloader.

So I worked on a compromise: A simple toolchain, which is reusing the tools from the Arduino IDE, also gives the comfort of the simple build and upload process, but it is based on CMake, a modular and widespread build system.

It is not meant to use for beginners. The idea is to provide a system which can be used in a prototype stage from professionals. Writing code to a fully abstract HAL which can later easily migrated to a professional firmware.

In this article, I will briefly describe this toolchain for the Feather M0 HAL. As for the HAL, it is a work in progress. It is meant as inspiration and example.

Update 2019-06-22: I concluded my tests on Linux successfully. For my tests, I used Ubuntu Linux with a compiled version of CMake. At this point, the available CMake package for this distribution was one version behind.

Requirements

I successfully tested the toolchain on macOS and it should work on Linux (Update: Successfully tested on Linux). There are a few requirements for both systems:

  • Works with any Adafruit Feather M0 based board.
  • Arduino IDE 1.8.9+
  • Python 3.7+
  • CMake 3.14+
Continue reading A New Modular CMake Based Toolchain for Feather M0 HAL

The Fusion of Software and Hardware…