Fracanto Dependency Injection #1 — The Core Principle
No driver in fracanto creates its hardware dependencies itself. Instead, each driver defines a _hw_t struct that describes the required hardware operations as function pointers — along with an opaque void *hw_ctx that carries platform-specific data. During initialization, the caller passes this struct, and the driver copies it into its internal context. From that point on, the driver exclusively calls the injected functions, without knowing whether a real SPI peripheral or a test double lies behind them.
This pattern follows the same philosophy as void *ctx in the vtable pattern: type erasure through opaque pointers. The difference lies in granularity — the vtable pattern abstracts framework interfaces, DI abstracts hardware access within individual drivers.
