Firmware architecture, "compile time requests", RTOS

Hi everyone. I’ve heard a lot about klipper and I was interested in how the klipper FW worked, so I looked through it.

I am roughly interested in doing some refactoring changes in a fork, as a
skill-builder project.

Up front, I was curious about something:
Is there a specific reason that you put it together with the “compile time
requests” architecture, using the named sections?

It seems like the same could be done with judicious use of kconfig flags and
macros, then a common “chassis” that launches/terminates any of the given
components, and the whole CTR mechanism could be removed.

Beyond that:
I’m also interested in doing an RTOS port, to refactor away from the
super-loop design. Again - is there already a known “dealbreaker” for that
design that made the devs not build it that way?

Most likely pitfalls here are going to be with the “Linux Process” and “Host Simulator” targets, and maybe keeping clean cross-platform support, but those aside, it seems like a project worth doing.

The goal of the CTR system was to facilitate encapsulation between the different components in the micro-controller software. If there was one central code location that knew of every module (and every module parameter) then that central code location would likely become very complex and need to be modified frequently. The goal was to keep the various code modules separate - for example, all the stepper logic in stepper.c and all the pwm logic in gpiocmds.c .

It was also desirable to store a compressed “data dictionary” in the flash of the micro-controller. The data dictionary stores pin names (eg, PA1) and supported commands. Many of the micro-controllers have limited flash space, so it was a goal to conserve it. The CTR system facilitates generating that data dictionary at compile time.

I’m not sure what you mean by “super-loop design”. If you are referring to the DECL_TASK system, where a module’s tasks are periodically invoked from a loop, then the goal was also to facilitate encapsulation between modules. If a central code location had to know about every module and when to invoke it, then that central location would likely become very complex and require frequent changes.



For the CTR:
I can see the implicit advantage of having all the “tasks” and such detected just by declaration and auto-launched.
And the issue of “commands” is common - you’d either need a central table of them all, with exported defs and strings, or you need a runtime “install” system to add them to a list.
Same for a single repository of strings.
I just have not seen many projects do it this way - not clear that it’s any less complex.

For concurrency:
Yes, that is what I mean by “super loop” - polling a set of tasks functions and irq_poll in a loop. RTOS design totally frees you from that and solves this issue from the README:

These functions should avoid long pauses, delays, or do work that lasts a
significant time. (Long delays in these “task” functions result in
scheduling jitter for other “tasks” - delays over 100us may become
noticeable, delays over 500us may result in command retransmissions,
delays over 100ms may result in watchdog reboots.)

RTOS would let you define and launch separate tasks, set priorities between them, and avoid this potential timing clash, by construction.
Also frees you from having to implement e.g. sched.c and your own allocator, although that is already done.
It seems like this a worthwhile refactor - I’ll work on it.

I don’t think the CTR is incompatible with such a refactor, necessarily.
Although the generated portion would change substantially.