After a quick adventure with the .NET nanoFramework on microcontrollers, I sort of came back to my senses and continued with something that seemed to have a brighter future (read: more supported boards, more documentation, bigger community, …). So, after a quick look around, I tried: PlatformIO:
- Loads of supported microcontrollers, and boards
- Arduino and Espressif IDF supported
- Programming language is C or C++
- Unit Testing possible
- Remote debugging
- IDE is a VS Code extension
- Runs on Windows, Linux and Mac
Sounds just too promising. At least promising enough to reactivate my C++03 knowledge and bring it up to at least C++17 (spoiler: after all there _was_ a reason why I switched to C#).
On the way I found out, that we now support auto, bool and lambda expressions but kept the splitting-of-declaration-and-implementation-nightmare – yikes …
Installation
Installation of PlatformIO was really straightforward. After the installation of VSCode, I installed the Python, C/C++ and the C++ extension beforehand. That automatically brought me CMake as well. And after that I just had to add the PlatformIO extension.
From there I could start and create my first project. And depending on the framework chosen (Arduino in my case) the main.cpp comes with either setup() and loop() or just app_main() (EspIdf).
Note: if the main file (under the src folder) is a main.c we have to rename it to main.cpp to use C++ features – I totally forgot about that …
Unit Testing
Building and flashing the controller “just worked”. So, I started to port my C# HelloWorld morse code generator to C++. Certainly, I wanted to write some unit tests along that way. And there the “trouble” started …
There is documentation, but I totally missed the way how unit testing are to be done with PlatformIO (at least when it is one with Unity:
- First, unit tests are either “local” or “native” tests (on your dev machine) or “embedded” tests. We have to set up a separate *environment* for each.
- The microcontroller framework (Arduino, in my case) is not supported on the native environment (not even an
#include <Arduino.h>is allowed). So, we have to make sure, we use only code that is totally hardware independeent. - PlatformIO does not install a toolchain for the native environment (i.e. we have to install a C/C++ compiler ourselves). And on Windows, it is recommended to use MSYS2 with Mingw64. That effectively means, we have different compilers depending on the environment. Something, that just feels weird to me. And something that could cause problems, as I later should find out.
- Every test is compiled as a separate executable with a
main()function. Something I am not used to in a .NET environment. And here is again, it matters which framework (Arduino or EspIdf) we are using, as we have to repeatsetup()/loop()orapp_main()again and again. - The main code in the
srcfolder is compiled as well, which leaves us with duplicate main() function. Preprocessor with#if defined()to the rescue – quite clumsy … - And then the main thing: we essentially have to move all the application code to the
libfolder, as -by default- thesrccode is not included when unit testing. That is not only strange to me, but leaves the src folder being an empty stub, as all the code now lives in the the (private)libfolder. - Documentation or the Calculator example were only partially helpful. I ended up with the weirdest compilation and linker errors I never dared to imagine.
- Unity requires we need to specify all tests manually if we want to run them.
But in the end, I got it working. Here is what I did:
- Guard your
src/main.cppwith#if defined(ARDUINO) / #endif. - Move everything else to
lib(hardware / framework dependent and indepedent code). - Create
test_embeddedandtest_native foldersundertest. - Create a
env:nativeenviroment and excludetest_embedded. Exlcudetest_nativeon the environment of your real board(s). - Code that relies on the (Arduino) framework is guarded with
#if defined(ARDUINO) / #endifas well. - Create a test file with
setup()/loop(),app_main()andmain(). And have a central functionrunUnityTeststhat runs all the tests.
Summary
My first impression is … mixed. On the one hand, PlatformIO makes it relatively easy to develop for different hardware/boards. Due to VSCode the “developer experience” is much better than with the Arduino IDE.
But … setting up Unit Testing and how it is implemented is rather awkward. Needless to say, that error messages are not for the faint of the heart.
I cannot say, that I miss my C++ days. On the other hand, not something I could not get used to and around with it.
