Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions Inc/HALAL/Models/GPIO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,16 @@ struct GPIODomain {
}
}

template <class Ctx> consteval void inscribe(Ctx &ctx) const {
ctx.template add<GPIODomain>(e);
template <class Ctx> consteval auto inscribe(Ctx &ctx) const {
return ctx.template add<GPIODomain>(e, this);
}
};

static constexpr std::size_t max_instances{110};

struct Config {
std::tuple<Port, GPIO_InitTypeDef> init_data{};
Port port;
GPIO_InitTypeDef init_data;
};

template <size_t N>
Expand All @@ -216,7 +217,9 @@ struct GPIODomain {
GPIO_InitStruct.Alternate = static_cast<uint32_t>(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;
Expand All @@ -242,14 +245,16 @@ struct GPIODomain {
GPIO_PinState read() { return HAL_GPIO_ReadPin(port, pin); }
};

template <std::size_t N> struct Init {
template <std::size_t N, std::array<Config, N> cfgs> struct Init {
static inline std::array<Instance, N> instances{};

static void init(std::span<const Config, N> 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);
Expand Down
148 changes: 79 additions & 69 deletions Inc/ST-LIB.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ template <typename... Domains> struct BuildCtx {
static constexpr std::size_t max_count_v = D::max_instances;

std::tuple<std::array<Decl<Domains>, max_count_v<Domains>>...> storage{};
std::tuple<std::array<const void *, max_count_v<Domains>>...> owners{};
std::array<std::size_t, sizeof...(Domains)> sizes{};

template <typename D, std::size_t I = 0>
Expand All @@ -47,12 +48,17 @@ template <typename... Domains> struct BuildCtx {
}
}

template <typename D> consteval std::size_t add(typename D::Entry e) {
template <typename D, typename Owner>
consteval std::size_t add(typename D::Entry e, const Owner *owner) {
constexpr std::size_t I = domain_index<D>();
auto &arr = std::get<I>(storage);
auto &own = std::get<I>(owners);
auto &size = sizes[I];

const auto idx = size;
arr[size++] = e;
arr[size] = e;
own[size] = owner;
++size;
return idx;
}

Expand All @@ -64,18 +70,34 @@ template <typename... Domains> struct BuildCtx {
return std::span<const E>{arr.data(), size};
}

template <typename D> consteval auto owners_span() const {
constexpr std::size_t I = domain_index<D>();
auto const &arr = std::get<I>(owners);
auto const size = sizes[I];
return std::span<const void *const>{arr.data(), size};
}

template <typename D> consteval std::size_t size() const {
constexpr std::size_t I = domain_index<D>();
return sizes[I];
}
};

using DomainsCtx = BuildCtx<GPIODomain, DigitalOutputDomain,
DigitalInputDomain /*, ADCDomain, PWMDomain, ...*/>;
template <typename Tuple> struct UnpackToCtx;
template <typename... Ds> struct UnpackToCtx<std::tuple<Ds...>> {
using type = BuildCtx<Ds...>;
};

template <auto &...devs> 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<Domains>::type;

static consteval auto build_ctx() {
DomainsCtx ctx{};
CtxType ctx{};
(devs.inscribe(ctx), ...);
return ctx;
}
Expand All @@ -86,91 +108,79 @@ template <auto &...devs> struct Board {
return ctx.template span<D>().size();
}

template <size_t... Is>
static consteval auto build_configs(std::index_sequence<Is...>) {
return std::make_tuple(
std::tuple_element_t<Is, Domains>::template build<
domain_size<std::tuple_element_t<Is, Domains>>()>(
ctx.template span<std::tuple_element_t<Is, Domains>>())...);
}

static consteval auto build() {
constexpr std::size_t gpioN = domain_size<GPIODomain>();
constexpr std::size_t doutN = domain_size<DigitalOutputDomain>();
constexpr std::size_t dinN = domain_size<DigitalInputDomain>();
// ...

struct ConfigBundle {
std::array<GPIODomain::Config, gpioN> gpio_cfgs;
std::array<DigitalOutputDomain::Config, doutN> dout_cfgs;
std::array<DigitalInputDomain::Config, dinN> din_cfgs;
// ...
};

return ConfigBundle{
.gpio_cfgs =
GPIODomain::template build<gpioN>(ctx.template span<GPIODomain>()),
.dout_cfgs = DigitalOutputDomain::template build<doutN>(
ctx.template span<DigitalOutputDomain>()),
.din_cfgs = DigitalInputDomain::template build<dinN>(
ctx.template span<DigitalInputDomain>()),
// ...
};
return build_configs(
std::make_index_sequence<std::tuple_size_v<Domains>>{});
}

static constexpr auto cfg = build();

static void init() {
constexpr std::size_t gpioN = domain_size<GPIODomain>();
constexpr std::size_t doutN = domain_size<DigitalOutputDomain>();
constexpr std::size_t dinN = domain_size<DigitalInputDomain>();
// ...
template <typename Domain> static consteval auto get_config() {
constexpr std::size_t I = CtxType::template domain_index<Domain>();
return std::get<I>(cfg);
}

GPIODomain::Init<gpioN>::init(cfg.gpio_cfgs);
DigitalOutputDomain::Init<doutN>::init(cfg.dout_cfgs,
GPIODomain::Init<gpioN>::instances);
DigitalInputDomain::Init<dinN>::init(cfg.din_cfgs,
GPIODomain::Init<gpioN>::instances);
// ...
template <typename Domain> static auto &get_instances() {
constexpr std::size_t N = domain_size<Domain>();
return Domain::template Init<N, get_config<Domain>()>::instances;
}

template <typename Domain>
static consteval std::size_t domain_size_for_instance() {
return domain_size<Domain>();
template <typename InitT, typename... Deps>
static void init_with_deps(std::tuple<Deps...> *) { // Pointer to deduce types easily, not used
InitT::init(get_instances<Deps>()...);
}

template <typename Domain, auto &Target, std::size_t I = 0>
static consteval std::size_t domain_index_of_impl() {
std::size_t idx = 0;
bool found = false;

(
[&] {
using DevT = std::remove_cvref_t<decltype(devs)>;
if constexpr (std::is_same_v<typename DevT::domain, Domain>) {
if (!found) {
if (&devs == &Target) {
found = true;
} else {
++idx;
}
}
}
}(),
...);

if (!found) {
compile_error("Device not found for domain");
template <typename Domain> static void init_domain() {
constexpr std::size_t N = domain_size<Domain>();
constexpr auto cfgs = get_config<Domain>();
using InitT = typename Domain::template Init<N, cfgs>;

if constexpr (requires { typename Domain::dependencies; }) {
// Resolve dependencies
init_with_deps<InitT>(static_cast<typename Domain::dependencies *>(nullptr));
} else {
InitT::init();
}
}

return idx;
template <std::size_t... Is>
static void init_domains(std::index_sequence<Is...>) {
(init_domain<std::tuple_element_t<Is, Domains>>(), ...);
}

static void init() {
init_domains(std::make_index_sequence<std::tuple_size_v<Domains>>{});
}

template <typename Domain, auto &Target>
static consteval std::size_t domain_index_of() {
return domain_index_of_impl<Domain, Target>();
template <typename Domain, auto &Target, std::size_t I = 0>
static consteval std::size_t owner_index_of() {
constexpr auto owners = ctx.template owners_span<Domain>();

if constexpr (I >= owners.size()) {
compile_error("Device not registered in domain");
return 0;
} else {
return owners[I] == &Target ? I : owner_index_of<Domain, Target, I + 1>();
}
}

template <auto &Target> static auto &instance_of() {
using DevT = std::remove_cvref_t<decltype(Target)>;
using Domain = typename DevT::domain;

constexpr std::size_t idx = domain_index_of<Domain, Target>();
constexpr std::size_t N = domain_size_for_instance<Domain>();
constexpr std::size_t idx = owner_index_of<Domain, Target>();

constexpr std::size_t N = domain_size<Domain>();

return Domain::template Init<N>::instances[idx];
return Domain::template Init<N, get_config<Domain>()>::instances[idx];
}
};

Expand Down
13 changes: 7 additions & 6 deletions Inc/ST-LIB_LOW/DigitalInput2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ using ST_LIB::GPIODomain;

namespace ST_LIB {
struct DigitalInputDomain {
using dependencies = std::tuple<GPIODomain>;

struct Entry {
size_t gpio_idx;
};
Expand All @@ -18,10 +20,10 @@ struct DigitalInputDomain {
GPIODomain::Speed speed = GPIODomain::Speed::Low)
: gpio{pin, GPIODomain::OperationMode::INPUT, pull, speed} {}

template <class Ctx> consteval void inscribe(Ctx &ctx) const {
const auto gpio_idx = ctx.template add<GPIODomain>(gpio.e);
template <class Ctx> consteval auto inscribe(Ctx &ctx) const {
const auto gpio_idx = gpio.inscribe(ctx);
Entry e{.gpio_idx = gpio_idx};
ctx.template add<DigitalInputDomain>(e);
return ctx.template add<DigitalInputDomain>(e, this);
}
};

Expand All @@ -47,11 +49,10 @@ struct DigitalInputDomain {
GPIO_PinState read() { return gpio_instance->read(); }
};

template <std::size_t N> struct Init {
template <std::size_t N, std::array<Config, N> cfgs> struct Init {
static inline std::array<Instance, N> instances{};

static void init(std::span<const Config, N> cfgs,
std::span<GPIODomain::Instance> gpio_instances) {
static void init(std::span<GPIODomain::Instance> gpio_instances) {
for (std::size_t i = 0; i < N; ++i) {
const auto &e = cfgs[i];

Expand Down
13 changes: 7 additions & 6 deletions Inc/ST-LIB_LOW/DigitalOutput2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ using ST_LIB::GPIODomain;

namespace ST_LIB {
struct DigitalOutputDomain {
using dependencies = std::tuple<GPIODomain>;

enum class OutputMode : uint8_t {
PUSH_PULL =
static_cast<uint8_t>(GPIODomain::OperationMode::OUTPUT_PUSHPULL),
Expand All @@ -26,10 +28,10 @@ struct DigitalOutputDomain {
: gpio{pin, static_cast<GPIODomain::OperationMode>(mode), pull, speed} {
}

template <class Ctx> consteval void inscribe(Ctx &ctx) const {
const auto gpio_idx = ctx.template add<GPIODomain>(gpio.e);
template <class Ctx> consteval auto inscribe(Ctx &ctx) const {
const auto gpio_idx = gpio.inscribe(ctx);
Entry e{.gpio_idx = gpio_idx};
ctx.template add<DigitalOutputDomain>(e);
return ctx.template add<DigitalOutputDomain>(e, this);
}
};

Expand Down Expand Up @@ -59,11 +61,10 @@ struct DigitalOutputDomain {
void toggle() { gpio_instance->toggle(); }
};

template <std::size_t N> struct Init {
template <std::size_t N, std::array<Config, N> cfgs> struct Init {
static inline std::array<Instance, N> instances{};

static void init(std::span<const Config, N> cfgs,
std::span<GPIODomain::Instance> gpio_instances) {
static void init(std::span<GPIODomain::Instance> gpio_instances) {
for (std::size_t i = 0; i < N; ++i) {
const auto &e = cfgs[i];

Expand Down