Burkhard on Qt Embedded Systems: No. 2
Welcome to my newsletter on Qt Embedded Systems. In my monthly newsletters, I cover a large spectrum of topics needed to build Qt applications on embedded systems. Topics include UI design, QML, Qt, C++, Yocto, system-on-chips, system architecture, agile practices and more. I'd love to discuss the topics of my newsletters with you. Feel free to contact me by email, LinkedIn or Twitter. Now enjoy reading this issue.
My Blog Posts
QML Engine Deletes C++ Objects Still In Use – Revisited with Address Sanitizers. In the past month, I had to find some strange crashes in a code base only partially known to me. I knew from past experience that Valgrind's memory checker would flood me with false negatives and that the instrumented code would execute far too slow to be usable. As I had heard a lot of good things about sanitizers, I decided to take them for a spin. I was rewarded with uncovering about two dozen slumbering crashes.
When I set out to write a post, I remembered a tricky crash I had roughly two years ago (see this old post). The reason for that crash was that the QML engine deleted C++ objects that were still in use. The example application from the old post was the ideal test case for address sanitizers. And, the address sanitizers didn't disappoint. The stack traces pointed directly to the problem. Address sanitizers would have saved me most of the three days I spent on debugging the original problem.
My new post explains how to compile and link an application with sanitizers and how to interpret the stack traces. Sanitizers are most effective, if you can run them over a test suite with high coverage. I'd suggest to integrate a sanitized run of your test suite into your CI process.
Introduction to the SAE J1939 Standard. The CAN standard doesn't define the meaning of CAN frames. One CAN device could interpret a frame as the engine speed, whereas another device interprets the same frame as the distance covered on the field. The SAE J1939 standard puts an end to this Babylonian chaos and standardises the meaning of over 1500 CAN frames and over 100 ECU addresses for agricultural, construction and other commercial vehicles.
When I developed the driver terminals of maize and sugar beet harvesters, I had to decode and encode J1939 frames. The terminal displays the information from the J1939 frames and reads and writes parameters of other ECUs. I noticed that information about J1939 is hard to come by, as the standard documents are all behind a paywall. In this post, I describe the structure of J1939 broadcast and peer-to-peer messages. If you want to learn how driver terminals handle over 1000 J1939 frames per second, you'll find more details in my talk A Deep Dive into Controller Area Networks with Qt (with links to slides and video).
News
Qt offering changes 2020 by Petteri Holländer. The Qt Company announced three changes to their FOSS offering. All three changes will make using Qt under LGPL or GPL more inconvenient.
As a FOSS user, you will be required to have a Qt account to download any Qt binary packages. A Qt account has been mandatory for the online installer for some years now. The offline installer will only be available for commercial users from now on. If you don't want to give away your contact details, you will have to download the Qt source packages and build from source. This will be a considerable obstacle for less experienced Qt users.
Long-term support (LTS) versions of Qt will not be available to FOSS users any more. Once the next minor version after an LTS version is released, FOSS users won't get the bugfix releases of the LTS version any more. These bugfixes will go into the next minor version. This will force you to upgrade to the next minor version or to patch the LTS version yourself. On embedded Linux systems, you'll have to adapt Yocto recipes and layers to the new Qt version. Moving to the newer Yocto version including the new Qt version is often not an option, because a new Yocto version means changes to the whole system. Making LTS Qt versions commercial-only implies more efforts for FOSS users.
If your business has a revenue of less than 100,000 USD, you can buy the start-up and small-business edition of Qt for 499 USD per year. You'll get Qt for Device Creation (Boot2Qt), but you won't be allowed to distribute your product. You'll get installation support but not the full technical support coming with Qt Commercial. I am wondering who would be entitled for this offering. With a 100K USD revenue, you wouldn't have a sustainable business as a freelancer, let alone as a small business with some employees. I think that The Qt Company should be more generous: You pay nothing for revenue up to 100K USD, 300 USD for up to 300K USD and 500 USD for up to 500K. The Qt company should not forget that the freelancer or small business may initiate the next 100K or 1M USD Qt Commercial deal for them.
C++ Move Semantics - The Complete Guide by Nicolai M. Josuttis. This book (available on Leanpub for 8.90 USD) will be the golden reference on C++ move semantics - like Nicolai's books The C++ Standard Library, C++17 and C++ Templates are the golden references on their respective topics. As usual, Nicolai takes his readers by the hand and walks them through the topic with many examples and diagrams - all lovingly explained.
Although I have read many treatises about move semantics, I have never understood when to use move semantics in my C++ code. So, I haven't used it yet. Chapter 4, How to Benefit from Move Semantics, provides the missing application guidelines:
Avoid temporary objects with names, because they cannot be moved.
Avoid unnecessary
std::move()
, because it may prevent compiler optimisations (e.g., return value optimisation).Use move semantics for initialising members in constructor calls. But don't use it for setters.
QtDay 2020 in Florence, Italy, 13-14 March 2020. I am pleased to give my talk A Deep Dive into Controller Area Networks with Qt there. It's the third year in a row I speak in Florence and the fourth time overall (2019: Using Qt under LGPLv3, 2018: Qt vs. Web - Total Cost of Ownership, 2012: Keynote for Nokia Qt). I love speaking at QtDay. QtDay just has the right size with 100-150 participants and creates a familial atmosphere. And, Florence and Tuscany are a very nice bonus.
Reading
What TDD is - and isn't - like by Ron Jeffries. Test-Driven Development (TDD) is about reducing the complexity of software development. Ron notes that
[...] it's at least ten times harder to find a defect in 100 lines than in 10. [The number of defects] increaseswith chunk size: writing correct code involves a lot of juggling of ideas, names, and other details, and larger chunks might quite likely be disproportionately more likely to include defects.
Ron Jeffries
TDD guides you to break down a big problem into many small problems. You solve these small problems one by one. The benefit is huge.
[...] TDD [...] causes us [...] to do our testing in very small batches, so small that finding defects is nearly trivial. And we seem to make fewer mistakes, or at least leave fewer in the code. Fewer defects, faster finding, simpler debugging: these are the things that make TDD faster.
Ron Jeffries
TDD Guided by ZOMBIES by James Grenning. The ZOMBIES approach helps you to find the small and simple steps that Ron Jeffries advocated above. The acronym ZOMBIES stands for Zero, One, Many, Boundaries, Interfaces, Exceptions and Simple. You start with the zero case (e.g., sorting no strings), check the boundary and exceptional cases and get the interface right. Then, you move to the one case (e.g., sorting one string) and check for BIE. Finally, you move to the many case (e.g., sorting of multiple strings) and check for BIE. You must check the transitions between Z, O and M as well. All these steps are governed by S: stick to Simple Scenarios and Simple Solutions.
Hexagonal Architecture (Ports and Adapters) by Alistair Cockburn. This pattern is a golden oldie that is as relevant now as it was on publication in 2005. Its main goal is to prevent the business logic from leaking into other parts of the application - not just the HMI. All the business logic is concentrated in the application core shown as a hexagon. The hexagon offers ports with well-defined interfaces. The hexagon of a harvester terminal, for example, offers ports for HMI, database, machine bus (e.g. CAN bus) and cloud.
Each port can be used by different clients, which adapt to the port's interface. A graphical user interface (GUI), a command-line interface (CLI) or a test harness can attach to the HMI port. An SQL database or a mock in-memory database can use the database port. By combining different pluggable components, you can
test the business logic by plugging the test harness into the HMI port and the mock database into the database port,
run the same tests against the production database, and
release the application with a CLI for automating process steps.
The Ports and Adapters pattern forces you to keep the business logic out of the pluggable components. If the HMI contained business logic, the test harness or CLI wouldn't work without duplicating this business logic.
Prototyping for Portability: Lightweight Architectural Strategies by Phillip Johnston. I'd like to widen the scope from prototypes to software in general. Writing portable code gives you clear benefits.
We merely want to separate portable code from the underlying system, making it easier to test without hardware and to migrate to a new platform.
Phillip Johnston
Portable code helps you to avoid vendor lock-in. Even the car OEMs start to understand that. They require different suppliers to implement the same standardised interfaces abstracting away the platform specifics. The OEMs can run the same infotainment HMI on the platforms of different suppliers. Suppliers hate this easy replaceability. OEMs love it and save a lot of money.
Portable code is the essence of Qt: Write once, run everywhere. The best way to make your code portable or cross-platform is to write and test it on your PC. When you build the code for the embedded system, the compiler will point out the platform-specific parts like mutexes, threads, sockets and time. You'll replace the problematic parts with lightweight abstractions. On a typical project, you won't have the time to find good abstractions for every platform-specific piece of code. You'll settle with moving these pieces to a single location. Your overall goal is to keep all other code platform-independent.
If you are lucky enough to have Qt on your embedded system, Qt will do the heavy lifting and hide the platform specifics. Otherwise, the Qt source code and Phillip's article are great starting points to build your own lightweight abstractions.
Color Theory for Designers: How to Create Your Own Color Schemes by Cameron Chapman. The article is not only for HMI designers but also for HMI developers. Many projects don't have dedicated designers or have bad designers. As a Qt developer, you will have to decide at some point which colour to use for the background, title, body text, highlighted graphics and normal graphics.
Cameron explains how to derive seven different classes of colour schemes from the 12-spoke colour wheel. An analogous scheme, for example, is created from three different adjacent colours on the wheel. Triadic schemes are made up of three colours spaced equally around the wheel. She gives many examples of good and bad colour schemes. Fortunately, there are free colour scheme generators like Coolors and Paletton.
Color Contrast for Interface Design by Matt D. Smith. Colour schemes are best readable if the colours have enough contrast. This article explains what enough contrast means. Black and white have the maximum contrast of 21 (see this link for the formulas to calculate the contrast of two RGB values).
A contrast score of less than 3.0 (fail) is hard to read and shouldn't be used. For font sizes greater than 18 points, a contrast of 3.0 or more (AA Large) will do. For smaller font sizes, you need a contrast of at least 4.5 to make your users happy (AA). When you read long texts, say, on an e-reader or need to spot differences in images or graphics, you need a contrast of at least 7.0 (AAA).
You find a web-based tool for calculating the contrast of two RGB values here. If you combine the colour scheme generators with the contrast checker, you should be able to come up with some decent colour schemes. As usual, exercise helps.