Architecture¶
How the Flux V1 HAL is put together. The short version: your code talks to one object, Flux; Flux holds one
manager per board function; managers own hf-core handlers; handlers wrap chip drivers; drivers reach the hardware
only through the interface classes of the internal interface wrap. The objects behind those interfaces are created
by a platform binding, one per MCU family, which is the only code that includes ESP-IDF.
Figure description and sources
From top to bottom, each layer only calls the one under it. Your application asks the facade singleton for the managers. The managers (one per board function) own the hf-core handlers, which wrap one chip driver each. The managers are MCU-free: the platform binding of the MCU family (bsp_bind/esp32s3 on this board) creates the objects behind the interface classes, the ESP32 implementations that sit on ESP-IDF, and is the only HAL code that includes ESP-IDF. Drivers talk to hardware only through the interface classes. Every name in a band is read from the code: the managers from the facade's member references, the handlers, drivers and interface classes from the managers', handlers' and binding's #include lines.
Drawn from: lib/api/Flux.h Flux (manager references); lib/managers #includes; lib/core/handlers #includes; lib/managers/bsp_bind #includes; figure module docs/diagrams/figures/hal-layers.py.
The layers¶
| Layer | Where | What it does | You use it when |
|---|---|---|---|
| Application | your project, examples/esp32 |
Tasks, control loops, protocols | Always |
| Facade | lib/api/Flux.h |
One singleton; brings the managers up in order; system diagnostics | Always: Flux::GetInstance() |
| Managers | lib/managers |
One per board function (valves, ADC, temperature, ...); know the board's wiring from the pin map; MCU-free | Almost always: flux.valves, flux.adc, ... |
| Platform binding | lib/managers/bsp_bind |
Turns the managers' plain-data specs into Base* objects; esp32s3/ is the only ESP-IDF code in the HAL |
When porting to another MCU (Platform bindings) |
| hf-core handlers | lib/core/handlers |
Wrap one chip driver each and adapt it to the interface classes | Rarely; for chip features a manager does not expose |
| Chip drivers | lib/core/hf-core-drivers/external |
Register-level drivers, one repository per chip | Almost never from application code |
| Interface wrap | lib/core/hf-core-drivers/internal/hf-internal-interface-wrap |
BaseSpi, BaseGpio, BaseAdc, ... and their ESP32 implementations (EspSpi, EspGpio, ...), which only the binding names |
When porting to another MCU |
The rule that holds the design together: a layer only calls the layer below it. The managers are the only code that knows Flux V1 exists; handlers and drivers are shared with other HardFOC boards. Why the line is drawn there is recorded in ADR 0001; why the MCU objects are created in a binding and not in the managers is ADR 0004, and a lint in CI keeps it that way.
Read on¶
- Platform bindings: what the binding creates, the families, and the boundary lint.
- Initialisation: the order the managers come up and what happens when one fails.
- Ownership: which manager creates which handler, and how memory is allocated.
- Threading: which calls are safe from several tasks.
- Errors and diagnostics: error enums,
GetLastError(), health snapshots.