I'm writing a firmware in which I would like to define functions "command" in multiple .c files, and automatically insert them in a list of function pointers. Subsequently from the serial port I want to recall one of these commands present in the array, and execute it with a list of arguments.
There is a firmware for 3d printers, on which I am relying, where such a thing is implemented.
https://github.com/KevinOConnor/klipper
The software structure used is this "remote procedure call" https://en.wikipedia.org/wiki/Remote_procedure_call
In this firmware the commands are implemented in the .c h file and there is no prototype in the .h
For example:
void command_set_digital_out(uint32_t *args)
{
gpio_out_setup(args[0], args[1]);
}
DECL_COMMAND(command_set_digital_out, "set_digital_out pin=%u value=%c");
below is a list of the definitions used
// Declare a function to run when the specified command is received
#define DECL_COMMAND_FLAGS(FUNC, FLAGS, MSG) \
DECL_CTR("DECL_COMMAND_FLAGS " __stringify(FUNC) " " \
__stringify(FLAGS) " " MSG)
#define DECL_COMMAND(FUNC, MSG) \
DECL_COMMAND_FLAGS(FUNC, 0, MSG)
// Declare a compile time request
#define DECL_CTR(REQUEST) \
static char __PASTE(_DECLS_, __LINE__)[] __attribute__((used)) \
__section(".compile_time_request") = (REQUEST)
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
Subsequently when the firmware acquires serial code it is able to recall these declared functions, as requested. How is it possible ?
I am not able to replicate this, in my firmware written for AVR in platformio, is there an easy and similar way to declare a list of functions dynamically?
I should say I do not like at all the idea of "auto declare functions in an array". Placing data in sections are neat tricks, but it's just spagetti code - different parts of code are connected via invisible links - which may lead to unmaintainable mess. Instead of resorting to compiler tricks, I suggest to just write a single big array in one place with clear and simple and readable and maintainable code.
That's relatively very very simple. You place data formatted how you want into a section. Gcc compiler picks up all sections from all files and concatenates them (let's say in random order) and generates to symbols -
__start_SECTIONAMEand__end_SECTIONAMEthat you can use to iterate over the elements in the section.The following code:
then compile and link:
and you can:
The same way instead of using
__attribute__((__section__("autofunc")))you could make a big array of structures that has all the information in one place.Many compilers have different syntax of how to place data in a section and how then get to that section. Research your compiler documentation.
Note that that is some convention that sections with leading dot are rather reserved. Prefer to use sections without leading dot for custom sections.
Compiler and linker expose a specific interface to work with user defined section that allows to do just that.