diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index c19131e37..b2bc00023 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -183,15 +183,16 @@ struct GPIODomain { } } - template consteval void inscribe(Ctx &ctx) const { - ctx.template add(e); + template consteval auto inscribe(Ctx &ctx) const { + return ctx.template add(e, this); } }; static constexpr std::size_t max_instances{110}; struct Config { - std::tuple init_data{}; + Port port; + GPIO_InitTypeDef init_data; }; template @@ -216,7 +217,9 @@ struct GPIODomain { GPIO_InitStruct.Alternate = static_cast(e.af); } - cfgs[i].init_data = std::make_tuple(e.port, GPIO_InitStruct); + // Assign directly to struct members + cfgs[i].port = e.port; + cfgs[i].init_data = GPIO_InitStruct; } return cfgs; @@ -242,14 +245,16 @@ struct GPIODomain { GPIO_PinState read() { return HAL_GPIO_ReadPin(port, pin); } }; - template struct Init { + template cfgs> struct Init { static inline std::array instances{}; - static void init(std::span cfgs) { + static void init() { static_assert(N > 0); for (std::size_t i = 0; i < N; ++i) { const auto &e = cfgs[i]; - auto [port, gpio_init] = e.init_data; + + auto port = e.port; + auto gpio_init = e.init_data; enable_gpio_clock(port); HAL_GPIO_Init(port_to_reg(port), &gpio_init); diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 32fb54814..ed86031aa 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -32,6 +32,7 @@ template struct BuildCtx { static constexpr std::size_t max_count_v = D::max_instances; std::tuple, max_count_v>...> storage{}; + std::tuple>...> owners{}; std::array sizes{}; template @@ -47,12 +48,17 @@ template struct BuildCtx { } } - template consteval std::size_t add(typename D::Entry e) { + template + consteval std::size_t add(typename D::Entry e, const Owner *owner) { constexpr std::size_t I = domain_index(); auto &arr = std::get(storage); + auto &own = std::get(owners); auto &size = sizes[I]; + const auto idx = size; - arr[size++] = e; + arr[size] = e; + own[size] = owner; + ++size; return idx; } @@ -64,18 +70,34 @@ template struct BuildCtx { return std::span{arr.data(), size}; } + template consteval auto owners_span() const { + constexpr std::size_t I = domain_index(); + auto const &arr = std::get(owners); + auto const size = sizes[I]; + return std::span{arr.data(), size}; + } + template consteval std::size_t size() const { constexpr std::size_t I = domain_index(); return sizes[I]; } }; -using DomainsCtx = BuildCtx; +template struct UnpackToCtx; +template struct UnpackToCtx> { + using type = BuildCtx; +}; template struct Board { + using Domains = std::tuple< + /* Level 0: Base Domains */ + GPIODomain, + /* Level 1: Domains depending on Level 0 */ + DigitalOutputDomain, DigitalInputDomain /*, ADCDomain, PWMDomain, ...*/>; + using CtxType = typename UnpackToCtx::type; + static consteval auto build_ctx() { - DomainsCtx ctx{}; + CtxType ctx{}; (devs.inscribe(ctx), ...); return ctx; } @@ -86,91 +108,79 @@ template struct Board { return ctx.template span().size(); } + template + static consteval auto build_configs(std::index_sequence) { + return std::make_tuple( + std::tuple_element_t::template build< + domain_size>()>( + ctx.template span>())...); + } + static consteval auto build() { - constexpr std::size_t gpioN = domain_size(); - constexpr std::size_t doutN = domain_size(); - constexpr std::size_t dinN = domain_size(); - // ... - - struct ConfigBundle { - std::array gpio_cfgs; - std::array dout_cfgs; - std::array din_cfgs; - // ... - }; - - return ConfigBundle{ - .gpio_cfgs = - GPIODomain::template build(ctx.template span()), - .dout_cfgs = DigitalOutputDomain::template build( - ctx.template span()), - .din_cfgs = DigitalInputDomain::template build( - ctx.template span()), - // ... - }; + return build_configs( + std::make_index_sequence>{}); } static constexpr auto cfg = build(); - static void init() { - constexpr std::size_t gpioN = domain_size(); - constexpr std::size_t doutN = domain_size(); - constexpr std::size_t dinN = domain_size(); - // ... + template static consteval auto get_config() { + constexpr std::size_t I = CtxType::template domain_index(); + return std::get(cfg); + } - GPIODomain::Init::init(cfg.gpio_cfgs); - DigitalOutputDomain::Init::init(cfg.dout_cfgs, - GPIODomain::Init::instances); - DigitalInputDomain::Init::init(cfg.din_cfgs, - GPIODomain::Init::instances); - // ... + template static auto &get_instances() { + constexpr std::size_t N = domain_size(); + return Domain::template Init()>::instances; } - template - static consteval std::size_t domain_size_for_instance() { - return domain_size(); + template + static void init_with_deps(std::tuple *) { // Pointer to deduce types easily, not used + InitT::init(get_instances()...); } - template - static consteval std::size_t domain_index_of_impl() { - std::size_t idx = 0; - bool found = false; - - ( - [&] { - using DevT = std::remove_cvref_t; - if constexpr (std::is_same_v) { - if (!found) { - if (&devs == &Target) { - found = true; - } else { - ++idx; - } - } - } - }(), - ...); - - if (!found) { - compile_error("Device not found for domain"); + template static void init_domain() { + constexpr std::size_t N = domain_size(); + constexpr auto cfgs = get_config(); + using InitT = typename Domain::template Init; + + if constexpr (requires { typename Domain::dependencies; }) { + // Resolve dependencies + init_with_deps(static_cast(nullptr)); + } else { + InitT::init(); } + } - return idx; + template + static void init_domains(std::index_sequence) { + (init_domain>(), ...); + } + + static void init() { + init_domains(std::make_index_sequence>{}); } - template - static consteval std::size_t domain_index_of() { - return domain_index_of_impl(); + template + static consteval std::size_t owner_index_of() { + constexpr auto owners = ctx.template owners_span(); + + if constexpr (I >= owners.size()) { + compile_error("Device not registered in domain"); + return 0; + } else { + return owners[I] == &Target ? I : owner_index_of(); + } } template static auto &instance_of() { using DevT = std::remove_cvref_t; using Domain = typename DevT::domain; - constexpr std::size_t idx = domain_index_of(); - constexpr std::size_t N = domain_size_for_instance(); + constexpr std::size_t idx = owner_index_of(); + + constexpr std::size_t N = domain_size(); - return Domain::template Init::instances[idx]; + return Domain::template Init()>::instances[idx]; } }; diff --git a/Inc/ST-LIB_LOW/DigitalInput2.hpp b/Inc/ST-LIB_LOW/DigitalInput2.hpp index e161e39a5..cef57b799 100644 --- a/Inc/ST-LIB_LOW/DigitalInput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalInput2.hpp @@ -6,6 +6,8 @@ using ST_LIB::GPIODomain; namespace ST_LIB { struct DigitalInputDomain { + using dependencies = std::tuple; + struct Entry { size_t gpio_idx; }; @@ -18,10 +20,10 @@ struct DigitalInputDomain { GPIODomain::Speed speed = GPIODomain::Speed::Low) : gpio{pin, GPIODomain::OperationMode::INPUT, pull, speed} {} - template consteval void inscribe(Ctx &ctx) const { - const auto gpio_idx = ctx.template add(gpio.e); + template consteval auto inscribe(Ctx &ctx) const { + const auto gpio_idx = gpio.inscribe(ctx); Entry e{.gpio_idx = gpio_idx}; - ctx.template add(e); + return ctx.template add(e, this); } }; @@ -47,11 +49,10 @@ struct DigitalInputDomain { GPIO_PinState read() { return gpio_instance->read(); } }; - template struct Init { + template cfgs> struct Init { static inline std::array instances{}; - static void init(std::span cfgs, - std::span gpio_instances) { + static void init(std::span gpio_instances) { for (std::size_t i = 0; i < N; ++i) { const auto &e = cfgs[i]; diff --git a/Inc/ST-LIB_LOW/DigitalOutput2.hpp b/Inc/ST-LIB_LOW/DigitalOutput2.hpp index 7dcad5b65..8ce11f4d8 100644 --- a/Inc/ST-LIB_LOW/DigitalOutput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalOutput2.hpp @@ -6,6 +6,8 @@ using ST_LIB::GPIODomain; namespace ST_LIB { struct DigitalOutputDomain { + using dependencies = std::tuple; + enum class OutputMode : uint8_t { PUSH_PULL = static_cast(GPIODomain::OperationMode::OUTPUT_PUSHPULL), @@ -26,10 +28,10 @@ struct DigitalOutputDomain { : gpio{pin, static_cast(mode), pull, speed} { } - template consteval void inscribe(Ctx &ctx) const { - const auto gpio_idx = ctx.template add(gpio.e); + template consteval auto inscribe(Ctx &ctx) const { + const auto gpio_idx = gpio.inscribe(ctx); Entry e{.gpio_idx = gpio_idx}; - ctx.template add(e); + return ctx.template add(e, this); } }; @@ -59,11 +61,10 @@ struct DigitalOutputDomain { void toggle() { gpio_instance->toggle(); } }; - template struct Init { + template cfgs> struct Init { static inline std::array instances{}; - static void init(std::span cfgs, - std::span gpio_instances) { + static void init(std::span gpio_instances) { for (std::size_t i = 0; i < N; ++i) { const auto &e = cfgs[i];