What can modern C++ can do for us, embedded developers ?
I am not a C++ expert, but I want to submit for educational and criticism purpose a module small enough to be readable in minutes, and big enough to be useful.
The module is a job dispatcher, with an API close to the C language ChibiOS one.
Modern C++ stuff that are used are
• variant (remember discriminated records in Ada ?)
• template parameter pack
• concept
• lambda
Variant permits to safely choose the type of the argument to the callback, without cast, neither in the module nor in the calling side. Type errors will be trapped during compilation.
Parameters pack permits to list all the types that can be used
Concepts permit, in case of incorrect use of the API, to limit compiler output to dozens of lines instead of hundreds of pages, still not as readable as I hoped, but usable.
Lambda permit to have the code that is executed in the job dispatcher thread, at the same level than the submitXXX function, that can ease code reading.
The module is one header file : https://github.com/alex31/chibios_enac_ ... bQueue.hpp
the API is simple : 3 methods to declare the jobqueue, then submit job from thread or ISR
overhead is low, does not use heap, only overhead is a copy of the argument passed to the queue : argument has to be constructed on the heap, then the module copies it to the queue.
Example of use :
Code: Select all
#include <ch.h>
#include <hal.h>
#include "jobQueue.hpp"
struct BaroData {
float p;
float t;
};
auto& jq = JobQueue<4, BaroData, int>::instance();
static const GPTConfig gptcfg = {
.frequency = 10'000,
.callback = [](GPTDriver *gptd) {
chSysLockFromISR();
static int i = 0;
if (gptd == &GPTD4) {
jq.submitI([](int &_i) {
chprintf(chp, "FROM GPTD4 i = %d\r\n", _i);
}, i++);
} else {
jq.submitI([](BaroData &bd) {
chprintf(chp, "FROM GPTD5 p,t = %.2f, %.2f\r\n", bd.p, bd.t);
}, (BaroData){.p = 1013.5, .t = 13.5});
}
chSysUnlockFromISR();
},
.cr2 = 0,
.dier = 0
};
void _init_chibios() __attribute__ ((constructor(101)));
void _init_chibios() {
halInit();
chSysInit();
}
int main(void)
{
consoleInit();
consoleLaunch();
gptStart(&GPTD5, &gptcfg);
gptStart(&GPTD4, &gptcfg);
gptStartContinuous(&GPTD5, 500);
gptStartContinuous(&GPTD4, 500);
chThdSleep(TIME_INFINITE);
}
happy C++ coding.
Alexandre