#ifndef __THER_LED_HPP__ #define __THER_LED_HPP__ #include #include #include #include #include namespace ther { /* Compile-time check: every LED name must be distinct so that * Led::On/Off/Flash name lookup stays unambiguous. */ template consteval auto AreUniqueNames(const etl::array &names) -> bool { for (std::size_t i = 0; i < N; ++i) { for (std::size_t j = i + 1; j < N; ++j) { if (names[i] == names[j]) { return false; } } } return true; } #define LED_SPEC(node) led_dt_spec LED_DT_SPEC_GET(node) #define LED_DEV_CHILD_SPEC(node) DT_FOREACH_CHILD_SEP(node, LED_SPEC, (, )), #define LED_NODE_NAME(node) DT_FOREACH_CHILD_SEP(node, DEVICE_DT_NAME, (, )) class Led { private: template struct Periodic { static auto Flash(led_dt_spec *spec) -> void { bool flag = false; if (flag) { led_on_dt(spec); } else { led_off_dt(spec); } flag = !flag; } static inline zpp::periodic_work work{Flash}; }; public: template static auto On() -> zpp::error { static_assert(IsDeviceName()); const auto id = etl::find(s_led_node_name.begin(), s_led_node_name.end(), std::string_view(kName)) - s_led_node_name.begin(); return led_on_dt(&s_led_dev[id]); } template static auto Off() -> zpp::error { static_assert(IsDeviceName()); const auto id = etl::find(s_led_node_name.begin(), s_led_node_name.end(), std::string_view(kName)) - s_led_node_name.begin(); return led_off_dt(&s_led_dev[id]); } template static auto Flash(std::chrono::duration period) { static_assert(IsDeviceName()); const auto id = etl::find(s_led_node_name.begin(), s_led_node_name.end(), std::string_view(kName)) - s_led_node_name.begin(); Periodic::work.submit(period); } private: template static consteval auto IsDeviceName() { for (size_t i = 0; i < s_led_node_name.size(); ++i) { if (s_led_node_name[i] == std::string_view(kName)) { return true; } } return false; } static auto Flash(led_dt_spec *spec) -> void { static bool flag = false; if (flag) { led_off_dt(spec); } else { led_on_dt(spec); } flag = !flag; } inline static constexpr etl::array s_led_dev{ DT_FOREACH_STATUS_OKAY(gpio_leds, LED_DEV_CHILD_SPEC)}; inline static constexpr auto s_led_node_name = etl::make_array( DT_FOREACH_STATUS_OKAY(gpio_leds, LED_NODE_NAME)); static_assert(AreUniqueNames(s_led_node_name), "LED node names must be unique"); }; } // namespace ther #endif