Skip to content

Commit d08c713

Browse files
authored
Merge pull request #747 from elbeno/interrupt-config
✨ Allow interrupt manager to dump config
2 parents 712136e + 51a585d commit d08c713

File tree

11 files changed

+187
-8
lines changed

11 files changed

+187
-8
lines changed

include/interrupt/concepts.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <interrupt/fwd.hpp>
44
#include <interrupt/policies.hpp>
55

6+
#include <stdx/ct_conversions.hpp>
7+
#include <stdx/ct_string.hpp>
68
#include <stdx/tuple.hpp>
79
#include <stdx/type_traits.hpp>
810

@@ -61,4 +63,27 @@ concept nexus_for = requires {
6163
T::template service<Flow>();
6264
{ T::template service<Flow>.active } -> std::same_as<bool const &>;
6365
};
66+
67+
namespace detail {
68+
template <typename T> constexpr auto config_string1() {
69+
if constexpr (requires {
70+
[]<auto N>(stdx::ct_string<N>) {}(T::config());
71+
}) {
72+
return stdx::ct<T::config()>();
73+
} else if constexpr (requires {
74+
[]<auto N>(stdx::ct_string<N>) {}(T::name);
75+
}) {
76+
return stdx::ct<T::name>();
77+
} else {
78+
constexpr auto s = stdx::type_as_string<T>();
79+
return stdx::ct<stdx::ct_string<s.size() + 1>{s}>();
80+
}
81+
}
82+
83+
template <typename... Ts> constexpr auto config_string_for() {
84+
using namespace stdx::literals;
85+
return stdx::tuple{config_string1<Ts>()...}.join(
86+
""_ctst, [](auto lhs, auto rhs) { return lhs + ", "_ctst + rhs; });
87+
}
88+
} // namespace detail
6489
} // namespace interrupt

include/interrupt/config.hpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
#include <interrupt/impl.hpp>
88
#include <interrupt/policies.hpp>
99

10+
#include <stdx/ct_format.hpp>
1011
#include <stdx/tuple.hpp>
1112
#include <stdx/tuple_algorithms.hpp>
13+
#include <stdx/utility.hpp>
1214

1315
namespace interrupt {
1416
namespace detail {
@@ -96,6 +98,13 @@ struct irq : detail::policy_config<Policies>,
9698
detail::super_config<Number, Priority>,
9799
detail::flow_config<Flows...> {
98100
template <typename... Nexi> using built_t = irq_impl<irq, Nexi...>;
101+
102+
constexpr static auto config() {
103+
using namespace stdx::literals;
104+
return +stdx::ct_format<"interrupt::irq<{}_irq, {}, {}>">(
105+
stdx::ct<stdx::to_underlying(Number)>(), stdx::ct<Priority>(),
106+
detail::config_string_for<Policies, Flows...>());
107+
}
99108
};
100109

101110
template <typename EnableField, typename StatusField, typename Policies,
@@ -105,6 +114,13 @@ struct sub_irq : detail::policy_config<Policies>,
105114
detail::sub_config<EnableField, StatusField>,
106115
detail::flow_config<Flows...> {
107116
template <typename... Nexi> using built_t = sub_irq_impl<sub_irq, Nexi...>;
117+
118+
constexpr static auto config() {
119+
using namespace stdx::literals;
120+
return +stdx::ct_format<"interrupt::sub_irq<{}>">(
121+
detail::config_string_for<EnableField, StatusField, Policies,
122+
Flows...>());
123+
}
108124
};
109125

110126
template <typename EnableField, typename Policies>
@@ -113,6 +129,12 @@ struct id_irq : detail::policy_config<Policies>,
113129
detail::sub_config<EnableField, status_t<>> {
114130
template <typename...> using built_t = id_irq_impl<id_irq>;
115131
template <typename> constexpr static bool triggers_flow = false;
132+
133+
constexpr static auto config() {
134+
using namespace stdx::literals;
135+
return +stdx::ct_format<"interrupt::id_irq<{}>">(
136+
detail::config_string_for<EnableField, Policies>());
137+
}
116138
};
117139

118140
template <irq_num_t Number, priority_t Priority, typename Policies,
@@ -131,6 +153,13 @@ struct shared_irq : detail::policy_config<Policies>,
131153
template <typename Flow>
132154
constexpr static bool triggers_flow =
133155
(... or Cfgs::template triggers_flow<Flow>);
156+
157+
constexpr static auto config() {
158+
using namespace stdx::literals;
159+
return +stdx::ct_format<"interrupt::shared_irq<{}_irq, {}, {}>">(
160+
stdx::ct<stdx::to_underlying(Number)>(), stdx::ct<Priority>(),
161+
detail::config_string_for<Policies, Cfgs...>());
162+
}
134163
};
135164

136165
template <typename EnableField, typename StatusField, typename Policies,
@@ -149,5 +178,12 @@ struct shared_sub_irq : detail::policy_config<Policies>,
149178
template <typename Flow>
150179
constexpr static bool triggers_flow =
151180
(... or Cfgs::template triggers_flow<Flow>);
181+
182+
constexpr static auto config() {
183+
using namespace stdx::literals;
184+
return +stdx::ct_format<"interrupt::shared_sub_irq<{}>">(
185+
detail::config_string_for<EnableField, StatusField, Policies,
186+
Cfgs...>());
187+
}
152188
};
153189
} // namespace interrupt

include/interrupt/manager.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <interrupt/dynamic_controller.hpp>
55
#include <interrupt/hal.hpp>
66

7+
#include <stdx/ct_format.hpp>
8+
#include <stdx/tuple.hpp>
79
#include <stdx/type_traits.hpp>
810
#include <stdx/utility.hpp>
911

@@ -14,13 +16,16 @@ namespace interrupt {
1416
namespace detail {
1517
template <typename Dynamic, irq_interface... Impls> struct manager {
1618
void init() const {
17-
// TODO: log exact interrupt manager configuration
18-
// (should be a single compile-time string with no arguments)
1919
hal::init();
2020
init_mcu_interrupts();
2121
init_sub_interrupts();
2222
}
2323

24+
constexpr static auto config() {
25+
return +stdx::ct_format<"interrupt::root<{}>">(
26+
detail::config_string_for<Impls...>());
27+
}
28+
2429
void init_mcu_interrupts() const { (Impls::init_mcu_interrupts(), ...); }
2530

2631
void init_sub_interrupts() const {

test/interrupt/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_tests(
22
FILES
33
dynamic_controller
4+
id_irq_impl
45
irq_impl
56
manager
67
shared_irq_impl

test/interrupt/common.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,15 @@ struct test_hal {
3434
} // namespace
3535
template <> inline auto interrupt::injected_hal<> = test_hal{};
3636

37-
namespace {
3837
template <typename T> inline bool flow_run{};
3938

40-
template <typename T> struct flow {
39+
template <typename T> struct flow_t {
4140
auto operator()() const { flow_run<T> = true; }
4241
constexpr static bool active{T::value};
4342
};
4443

4544
struct test_nexus {
46-
template <typename T> constexpr static auto service = flow<T>{};
45+
template <typename T> constexpr static auto service = flow_t<T>{};
4746
};
4847

4948
template <auto> struct enable_field_t {
@@ -64,4 +63,3 @@ template <typename Field> constexpr auto clear(Field) {
6463
template <typename... Ops> constexpr auto apply(Ops... ops) {
6564
return (ops(), ...);
6665
}
67-
} // namespace

test/interrupt/id_irq_impl.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "common.hpp"
2+
3+
#include <interrupt/concepts.hpp>
4+
5+
#include <catch2/catch_test_macros.hpp>
6+
7+
#include <type_traits>
8+
9+
namespace {
10+
using config_t = interrupt::id_irq<enable_field_t<0>, interrupt::policies<>>;
11+
} // namespace
12+
13+
TEST_CASE("config models concept", "[id_irq_impl]") {
14+
STATIC_REQUIRE(interrupt::sub_irq_config<config_t>);
15+
}
16+
17+
TEST_CASE("impl models concept", "[id_irq_impl]") {
18+
using impl_t = interrupt::id_irq_impl<config_t>;
19+
STATIC_REQUIRE(interrupt::sub_irq_interface<impl_t>);
20+
}
21+
22+
TEST_CASE("impl can dump config", "[id_irq_impl]") {
23+
using namespace stdx::literals;
24+
using impl_t = interrupt::id_irq_impl<config_t>;
25+
constexpr auto s = impl_t::config();
26+
STATIC_REQUIRE(
27+
s == "interrupt::id_irq<enable_field_t<0>, interrupt::policies<>>"_cts);
28+
}

test/interrupt/irq_impl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <interrupt/concepts.hpp>
44

5+
#include <stdx/ct_string.hpp>
6+
57
#include <catch2/catch_test_macros.hpp>
68

79
#include <type_traits>
@@ -46,11 +48,29 @@ TEST_CASE("impl models concept", "[irq_impl]") {
4648
STATIC_REQUIRE(interrupt::irq_interface<impl_t>);
4749
}
4850

51+
TEST_CASE("impl can dump config (no flows)", "[irq_impl]") {
52+
using namespace stdx::literals;
53+
using impl_t = interrupt::irq_impl<no_flows_config_t, test_nexus>;
54+
constexpr auto s = impl_t::config();
55+
STATIC_REQUIRE(s ==
56+
"interrupt::irq<42_irq, 17, interrupt::policies<>>"_cts);
57+
}
58+
4959
namespace {
5060
template <typename T>
5161
using flow_config_t = interrupt::irq<17_irq, 42, interrupt::policies<>, T>;
5262
} // namespace
5363

64+
TEST_CASE("impl can dump config (some flows)", "[irq_impl]") {
65+
using namespace stdx::literals;
66+
using impl_t =
67+
interrupt::irq_impl<flow_config_t<std::true_type>, test_nexus>;
68+
constexpr auto s = impl_t::config();
69+
STATIC_REQUIRE(
70+
s ==
71+
"interrupt::irq<17_irq, 42, interrupt::policies<>, std::integral_constant<bool, true>>"_cts);
72+
}
73+
5474
TEST_CASE("impl runs a flow", "[irq_impl]") {
5575
using impl_t =
5676
interrupt::irq_impl<flow_config_t<std::true_type>, test_nexus>;

test/interrupt/manager.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77

88
#include <type_traits>
99

10-
namespace {
1110
struct flow_1 : std::true_type {};
1211
struct flow_2 : std::true_type {};
1312

13+
namespace {
1414
using config_a =
1515
interrupt::root<interrupt::irq<17_irq, 42, interrupt::policies<>, flow_1>>;
1616
using config_b = interrupt::root<
@@ -30,6 +30,18 @@ TEST_CASE("init enables interrupts", "[manager]") {
3030
CHECK(priority<17_irq> == 42);
3131
}
3232

33+
TEST_CASE("manager can dump config", "[manager]") {
34+
using namespace stdx::literals;
35+
constexpr auto s1 = interrupt::manager<config_a, test_nexus>::config();
36+
STATIC_REQUIRE(
37+
s1 ==
38+
"interrupt::root<interrupt::irq<17_irq, 42, interrupt::policies<>, flow_1>>"_cts);
39+
constexpr auto s2 = interrupt::manager<config_b, test_nexus>::config();
40+
STATIC_REQUIRE(
41+
s2 ==
42+
"interrupt::root<interrupt::irq<17_irq, 42, interrupt::policies<>, flow_1, flow_2>>"_cts);
43+
}
44+
3345
TEST_CASE("run single flow", "[manager]") {
3446
auto m = interrupt::manager<config_a, test_nexus>{};
3547
flow_run<flow_1> = false;
@@ -54,7 +66,7 @@ namespace {
5466
template <typename Flow> struct alt_flow : Flow {};
5567

5668
struct alt_nexus {
57-
template <typename T> constexpr static auto service = flow<alt_flow<T>>{};
69+
template <typename T> constexpr static auto service = flow_t<alt_flow<T>>{};
5870
};
5971
} // namespace
6072

test/interrupt/shared_irq_impl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ TEST_CASE("impl models concept", "[shared_irq_impl]") {
4646
STATIC_REQUIRE(interrupt::irq_interface<impl_t>);
4747
}
4848

49+
TEST_CASE("impl can dump config (no subs)", "[shared_irq_impl]") {
50+
using namespace stdx::literals;
51+
using impl_t = interrupt::shared_irq_impl<no_flows_config_t>;
52+
constexpr auto s = impl_t::config();
53+
STATIC_REQUIRE(
54+
s == "interrupt::shared_irq<42_irq, 17, interrupt::policies<>>"_cts);
55+
}
56+
4957
namespace {
5058
template <typename T, auto N>
5159
using sub_config_t = interrupt::sub_irq<enable_field_t<N>, status_field_t<N>,
@@ -56,6 +64,15 @@ using flow_config_t = interrupt::shared_irq<17_irq, 42, interrupt::policies<>,
5664
sub_config_t<T, 0>>;
5765
} // namespace
5866

67+
TEST_CASE("impl can dump config (some subs)", "[shared_irq_impl]") {
68+
using namespace stdx::literals;
69+
using impl_t = interrupt::shared_irq_impl<flow_config_t<std::true_type>>;
70+
constexpr auto s = impl_t::config();
71+
STATIC_REQUIRE(
72+
s ==
73+
"interrupt::shared_irq<17_irq, 42, interrupt::policies<>, interrupt::sub_irq<enable_field_t<0>, status_field_t<0>, interrupt::policies<>, std::integral_constant<bool, true>>>"_cts);
74+
}
75+
5976
TEST_CASE("impl runs a flow", "[shared_irq_impl]") {
6077
using sub_impl_t =
6178
interrupt::sub_irq_impl<sub_config_t<std::true_type, 0>, test_nexus>;

test/interrupt/shared_sub_irq_impl.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ TEST_CASE("impl models concept", "[shared_sub_irq_impl]") {
3535
STATIC_REQUIRE(interrupt::sub_irq_interface<impl_t>);
3636
}
3737

38+
TEST_CASE("impl can dump config (no flows)", "[shared_sub_irq_impl]") {
39+
using namespace stdx::literals;
40+
using impl_t = interrupt::shared_sub_irq_impl<no_flows_config_t>;
41+
constexpr auto s = impl_t::config();
42+
STATIC_REQUIRE(
43+
s ==
44+
"interrupt::shared_sub_irq<enable_field_t<0>, status_field_t<0>, interrupt::policies<>>"_cts);
45+
}
46+
3847
namespace {
3948
template <typename T, auto N>
4049
using sub_config_t = interrupt::sub_irq<enable_field_t<N>, status_field_t<N>,
@@ -46,6 +55,15 @@ using flow_config_t =
4655
interrupt::policies<>, sub_config_t<T, 1>>;
4756
} // namespace
4857

58+
TEST_CASE("impl can dump config (some flows)", "[shared_sub_irq_impl]") {
59+
using namespace stdx::literals;
60+
using impl_t = interrupt::sub_irq_impl<flow_config_t<std::true_type>>;
61+
constexpr auto s = impl_t::config();
62+
STATIC_REQUIRE(
63+
s ==
64+
"interrupt::shared_sub_irq<enable_field_t<0>, status_field_t<0>, interrupt::policies<>, interrupt::sub_irq<enable_field_t<1>, status_field_t<1>, interrupt::policies<>, std::integral_constant<bool, true>>>"_cts);
65+
}
66+
4967
TEST_CASE("impl runs a flow", "[shared_sub_irq_impl]") {
5068
using sub_impl_t =
5169
interrupt::sub_irq_impl<sub_config_t<std::true_type, 1>, test_nexus>;

0 commit comments

Comments
 (0)