diff --git a/include/interrupt/concepts.hpp b/include/interrupt/concepts.hpp index 23159e53..ff8ee4c2 100644 --- a/include/interrupt/concepts.hpp +++ b/include/interrupt/concepts.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include @@ -61,4 +63,27 @@ concept nexus_for = requires { T::template service(); { T::template service.active } -> std::same_as; }; + +namespace detail { +template constexpr auto config_string1() { + if constexpr (requires { + [](stdx::ct_string) {}(T::config()); + }) { + return stdx::ct(); + } else if constexpr (requires { + [](stdx::ct_string) {}(T::name); + }) { + return stdx::ct(); + } else { + constexpr auto s = stdx::type_as_string(); + return stdx::ct{s}>(); + } +} + +template constexpr auto config_string_for() { + using namespace stdx::literals; + return stdx::tuple{config_string1()...}.join( + ""_ctst, [](auto lhs, auto rhs) { return lhs + ", "_ctst + rhs; }); +} +} // namespace detail } // namespace interrupt diff --git a/include/interrupt/config.hpp b/include/interrupt/config.hpp index 092992fa..c1d4b56b 100644 --- a/include/interrupt/config.hpp +++ b/include/interrupt/config.hpp @@ -7,8 +7,10 @@ #include #include +#include #include #include +#include namespace interrupt { namespace detail { @@ -96,6 +98,13 @@ struct irq : detail::policy_config, detail::super_config, detail::flow_config { template using built_t = irq_impl; + + constexpr static auto config() { + using namespace stdx::literals; + return +stdx::ct_format<"interrupt::irq<{}_irq, {}, {}>">( + stdx::ct(), stdx::ct(), + detail::config_string_for()); + } }; template , detail::sub_config, detail::flow_config { template using built_t = sub_irq_impl; + + constexpr static auto config() { + using namespace stdx::literals; + return +stdx::ct_format<"interrupt::sub_irq<{}>">( + detail::config_string_for()); + } }; template @@ -113,6 +129,12 @@ struct id_irq : detail::policy_config, detail::sub_config> { template using built_t = id_irq_impl; template constexpr static bool triggers_flow = false; + + constexpr static auto config() { + using namespace stdx::literals; + return +stdx::ct_format<"interrupt::id_irq<{}>">( + detail::config_string_for()); + } }; template , template constexpr static bool triggers_flow = (... or Cfgs::template triggers_flow); + + constexpr static auto config() { + using namespace stdx::literals; + return +stdx::ct_format<"interrupt::shared_irq<{}_irq, {}, {}>">( + stdx::ct(), stdx::ct(), + detail::config_string_for()); + } }; template , template constexpr static bool triggers_flow = (... or Cfgs::template triggers_flow); + + constexpr static auto config() { + using namespace stdx::literals; + return +stdx::ct_format<"interrupt::shared_sub_irq<{}>">( + detail::config_string_for()); + } }; } // namespace interrupt diff --git a/include/interrupt/manager.hpp b/include/interrupt/manager.hpp index 94e046ea..b4ba8552 100644 --- a/include/interrupt/manager.hpp +++ b/include/interrupt/manager.hpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include @@ -14,13 +16,16 @@ namespace interrupt { namespace detail { template struct manager { void init() const { - // TODO: log exact interrupt manager configuration - // (should be a single compile-time string with no arguments) hal::init(); init_mcu_interrupts(); init_sub_interrupts(); } + constexpr static auto config() { + return +stdx::ct_format<"interrupt::root<{}>">( + detail::config_string_for()); + } + void init_mcu_interrupts() const { (Impls::init_mcu_interrupts(), ...); } void init_sub_interrupts() const { diff --git a/test/interrupt/CMakeLists.txt b/test/interrupt/CMakeLists.txt index e7862ebd..5835eec8 100644 --- a/test/interrupt/CMakeLists.txt +++ b/test/interrupt/CMakeLists.txt @@ -1,6 +1,7 @@ add_tests( FILES dynamic_controller + id_irq_impl irq_impl manager shared_irq_impl diff --git a/test/interrupt/common.hpp b/test/interrupt/common.hpp index 1959d19f..209a04b1 100644 --- a/test/interrupt/common.hpp +++ b/test/interrupt/common.hpp @@ -34,16 +34,15 @@ struct test_hal { } // namespace template <> inline auto interrupt::injected_hal<> = test_hal{}; -namespace { template inline bool flow_run{}; -template struct flow { +template struct flow_t { auto operator()() const { flow_run = true; } constexpr static bool active{T::value}; }; struct test_nexus { - template constexpr static auto service = flow{}; + template constexpr static auto service = flow_t{}; }; template struct enable_field_t { @@ -64,4 +63,3 @@ template constexpr auto clear(Field) { template constexpr auto apply(Ops... ops) { return (ops(), ...); } -} // namespace diff --git a/test/interrupt/id_irq_impl.cpp b/test/interrupt/id_irq_impl.cpp new file mode 100644 index 00000000..be745fbc --- /dev/null +++ b/test/interrupt/id_irq_impl.cpp @@ -0,0 +1,28 @@ +#include "common.hpp" + +#include + +#include + +#include + +namespace { +using config_t = interrupt::id_irq, interrupt::policies<>>; +} // namespace + +TEST_CASE("config models concept", "[id_irq_impl]") { + STATIC_REQUIRE(interrupt::sub_irq_config); +} + +TEST_CASE("impl models concept", "[id_irq_impl]") { + using impl_t = interrupt::id_irq_impl; + STATIC_REQUIRE(interrupt::sub_irq_interface); +} + +TEST_CASE("impl can dump config", "[id_irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::id_irq_impl; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == "interrupt::id_irq, interrupt::policies<>>"_cts); +} diff --git a/test/interrupt/irq_impl.cpp b/test/interrupt/irq_impl.cpp index 41f5b40e..ee9c367b 100644 --- a/test/interrupt/irq_impl.cpp +++ b/test/interrupt/irq_impl.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -46,11 +48,29 @@ TEST_CASE("impl models concept", "[irq_impl]") { STATIC_REQUIRE(interrupt::irq_interface); } +TEST_CASE("impl can dump config (no flows)", "[irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::irq_impl; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE(s == + "interrupt::irq<42_irq, 17, interrupt::policies<>>"_cts); +} + namespace { template using flow_config_t = interrupt::irq<17_irq, 42, interrupt::policies<>, T>; } // namespace +TEST_CASE("impl can dump config (some flows)", "[irq_impl]") { + using namespace stdx::literals; + using impl_t = + interrupt::irq_impl, test_nexus>; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == + "interrupt::irq<17_irq, 42, interrupt::policies<>, std::integral_constant>"_cts); +} + TEST_CASE("impl runs a flow", "[irq_impl]") { using impl_t = interrupt::irq_impl, test_nexus>; diff --git a/test/interrupt/manager.cpp b/test/interrupt/manager.cpp index b3c07d79..97f6f97f 100644 --- a/test/interrupt/manager.cpp +++ b/test/interrupt/manager.cpp @@ -7,10 +7,10 @@ #include -namespace { struct flow_1 : std::true_type {}; struct flow_2 : std::true_type {}; +namespace { using config_a = interrupt::root, flow_1>>; using config_b = interrupt::root< @@ -30,6 +30,18 @@ TEST_CASE("init enables interrupts", "[manager]") { CHECK(priority<17_irq> == 42); } +TEST_CASE("manager can dump config", "[manager]") { + using namespace stdx::literals; + constexpr auto s1 = interrupt::manager::config(); + STATIC_REQUIRE( + s1 == + "interrupt::root, flow_1>>"_cts); + constexpr auto s2 = interrupt::manager::config(); + STATIC_REQUIRE( + s2 == + "interrupt::root, flow_1, flow_2>>"_cts); +} + TEST_CASE("run single flow", "[manager]") { auto m = interrupt::manager{}; flow_run = false; @@ -54,7 +66,7 @@ namespace { template struct alt_flow : Flow {}; struct alt_nexus { - template constexpr static auto service = flow>{}; + template constexpr static auto service = flow_t>{}; }; } // namespace diff --git a/test/interrupt/shared_irq_impl.cpp b/test/interrupt/shared_irq_impl.cpp index 278576d0..2f247373 100644 --- a/test/interrupt/shared_irq_impl.cpp +++ b/test/interrupt/shared_irq_impl.cpp @@ -46,6 +46,14 @@ TEST_CASE("impl models concept", "[shared_irq_impl]") { STATIC_REQUIRE(interrupt::irq_interface); } +TEST_CASE("impl can dump config (no subs)", "[shared_irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::shared_irq_impl; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == "interrupt::shared_irq<42_irq, 17, interrupt::policies<>>"_cts); +} + namespace { template using sub_config_t = interrupt::sub_irq, status_field_t, @@ -56,6 +64,15 @@ using flow_config_t = interrupt::shared_irq<17_irq, 42, interrupt::policies<>, sub_config_t>; } // namespace +TEST_CASE("impl can dump config (some subs)", "[shared_irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::shared_irq_impl>; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == + "interrupt::shared_irq<17_irq, 42, interrupt::policies<>, interrupt::sub_irq, status_field_t<0>, interrupt::policies<>, std::integral_constant>>"_cts); +} + TEST_CASE("impl runs a flow", "[shared_irq_impl]") { using sub_impl_t = interrupt::sub_irq_impl, test_nexus>; diff --git a/test/interrupt/shared_sub_irq_impl.cpp b/test/interrupt/shared_sub_irq_impl.cpp index 51411eac..3d48c231 100644 --- a/test/interrupt/shared_sub_irq_impl.cpp +++ b/test/interrupt/shared_sub_irq_impl.cpp @@ -35,6 +35,15 @@ TEST_CASE("impl models concept", "[shared_sub_irq_impl]") { STATIC_REQUIRE(interrupt::sub_irq_interface); } +TEST_CASE("impl can dump config (no flows)", "[shared_sub_irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::shared_sub_irq_impl; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == + "interrupt::shared_sub_irq, status_field_t<0>, interrupt::policies<>>"_cts); +} + namespace { template using sub_config_t = interrupt::sub_irq, status_field_t, @@ -46,6 +55,15 @@ using flow_config_t = interrupt::policies<>, sub_config_t>; } // namespace +TEST_CASE("impl can dump config (some flows)", "[shared_sub_irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::sub_irq_impl>; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == + "interrupt::shared_sub_irq, status_field_t<0>, interrupt::policies<>, interrupt::sub_irq, status_field_t<1>, interrupt::policies<>, std::integral_constant>>"_cts); +} + TEST_CASE("impl runs a flow", "[shared_sub_irq_impl]") { using sub_impl_t = interrupt::sub_irq_impl, test_nexus>; diff --git a/test/interrupt/sub_irq_impl.cpp b/test/interrupt/sub_irq_impl.cpp index 7332ef7f..35bd424a 100644 --- a/test/interrupt/sub_irq_impl.cpp +++ b/test/interrupt/sub_irq_impl.cpp @@ -34,12 +34,31 @@ TEST_CASE("impl models concept", "[sub_irq_impl]") { STATIC_REQUIRE(interrupt::sub_irq_interface); } +TEST_CASE("impl can dump config (no flows)", "[sub_irq_impl]") { + using namespace stdx::literals; + using impl_t = interrupt::sub_irq_impl; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == + "interrupt::sub_irq, status_field_t<0>, interrupt::policies<>>"_cts); +} + namespace { template using flow_config_t = interrupt::sub_irq, status_field_t<0>, interrupt::policies<>, T>; } +TEST_CASE("impl can dump config (some flows)", "[sub_irq_impl]") { + using namespace stdx::literals; + using impl_t = + interrupt::sub_irq_impl, test_nexus>; + constexpr auto s = impl_t::config(); + STATIC_REQUIRE( + s == + "interrupt::sub_irq, status_field_t<0>, interrupt::policies<>, std::integral_constant>"_cts); +} + TEST_CASE("impl runs a flow when enabled and status", "[sub_irq_impl]") { using impl_t = interrupt::sub_irq_impl, test_nexus>;