diff --git a/include/com.hpp b/include/com.hpp index 2cc22d3..adc71b8 100644 --- a/include/com.hpp +++ b/include/com.hpp @@ -1,9 +1,7 @@ #ifndef __THER_COM_HPP__ #define __THER_COM_HPP__ -#include "heating.hpp" #include "led.hpp" -#include "ntc.hpp" #include #include #include @@ -50,9 +48,7 @@ private: return; } if (data[0] == RUNNING) { - InfLed::On(); } else { - InfLed::Off(); } printk("set ledsrtip to %d", data[0]); const uint8_t id = data[0]; @@ -61,40 +57,33 @@ private: }); } static auto WHeatingState(uart_com::DataType data) -> void { - if (data.size() != 1) { - return; - } - const bool state = (data[0] > 0); - if (state) { - HeatingPad::Start(sensor_value{data[0], 0}); - } else { - HeatingPad::Stop(); - } + // if (data.size() != 1) { + // return; + // } + // const bool state = (data[0] > 0); + // if (state) { + // HeatingPad::Start(sensor_value{data[0], 0}); + // } else { + // HeatingPad::Stop(); + // } } static auto RHeatingState(uart_com::DataType data) -> void { - if (data.size() != 0) { - return; - } - const sensor_value temp = HeatingPad::CurrentTemp(); - const uint8_t state[] = {s_heating_state, (uint8_t)temp.val1, - (uint8_t)temp.val2}; - s_proto->Send(R_HEATING_STATE, state); + // if (data.size() != 0) { + // return; + // } + // const sensor_value temp = HeatingPad::CurrentTemp(); + // const uint8_t state[] = {s_heating_state, (uint8_t)temp.val1, + // (uint8_t)temp.val2}; + // s_proto->Send(R_HEATING_STATE, state); } /// Read one pole NTC by index (0~7). static auto ReadPoleNtcTemperature(uart_com::DataType data) -> void { if (data.size() != 1) { return; } - const sensor_value temp = NtcGroup::GetSensorValue(data[0]); - const uint8_t payload[] = {(uint8_t)temp.val1, (uint8_t)temp.val2}; - s_proto->Send(R_TEMP_POLE_NTC, payload); } /// Read heating pad NTC (onboard ADC). - static auto ReadHeatingPadNtcTemperature(uart_com::DataType data) -> void { - const sensor_value temp = HeatingPad::CurrentTemp(); - const uint8_t payload[] = {(uint8_t)temp.val1, (uint8_t)temp.val2}; - s_proto->Send(R_TEMP_HETING_PAD_NTC, payload); - } + static auto ReadHeatingPadNtcTemperature(uart_com::DataType data) -> void {} }; constexpr static std::pair @@ -113,7 +102,6 @@ private: inline static auto s_proto = (uart_com::SimpleProtocal *)(DEVICE_DT_GET(DT_NODELABEL(pm_protocal))); inline static auto s_heating_state = false; - using InfLed = ther::Led; }; } // namespace ther diff --git a/include/infrared.hpp b/include/infrared.hpp index 419cab8..c8eeb31 100644 --- a/include/infrared.hpp +++ b/include/infrared.hpp @@ -1,5 +1,8 @@ #ifndef __THER_INFRARED_HPP__ #define __THER_INFRARED_HPP__ +#include +#include +#include #include #include #include @@ -7,41 +10,64 @@ #include namespace ther { -template class Infrared { +class Infrared { public: static auto Init() -> zpp::error { static sensor_trigger tri{.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_AMBIENT_TEMP}; - if (auto r = sensor_trigger_set( - kDev, &tri, - [](const device *dev, const sensor_trigger *trig) { - s_is_data_ready = true; - }); - r != 0) { - return -ENODEV; - }; + for (auto dev : s_dev) { + if (auto r = sensor_trigger_set( + dev, &tri, + [](const device *dev, const sensor_trigger *trig) { + const size_t id = etl::distance( + s_dev.begin(), etl::find(s_dev.begin(), s_dev.end(), dev)); + s_dev_ready[id] = 1; + }); + r != 0) { + return -ENODEV; + } + } + return zpp::ok(); } - static auto GetSensorValue() - -> zpp::result> { - if (!s_is_data_ready) { + /* One-shot fetch of ALL sensors, return the hottest one. */ + static auto GetMaxSensorValue() -> zpp::result> { + bool found = false; + int max_id = 0; + sensor_value max_val{}; + + for (size_t id = 0; id < s_dev.size(); ++id) { + /* -ENODATA just means no new sample for this channel; keep going. */ + if (0 != sensor_sample_fetch(s_dev[id])) { + continue; + } + + sensor_value val; + if (0 != sensor_channel_get(s_dev[id], SENSOR_CHAN_AMBIENT_TEMP, &val)) { + s_dev_ready[id] = 0; /* sample consumed, drop the ready flag */ + continue; + } + + s_dev_ready[id] = 0; + + if (!found || val.val1 > max_val.val1 || + (val.val1 == max_val.val1 && val.val2 > max_val.val2)) { + found = true; + max_id = static_cast(id); + max_val = val; + } + } + + if (!found) { return zpp::error_code::k_nodata; } - - if (0 != sensor_sample_fetch(kDev)) { - return zpp::error_code::k_io; - } - - zpp::value val; - if (0 != sensor_channel_get(kDev, SENSOR_CHAN_AMBIENT_TEMP, &val)) { - return zpp::error_code::k_io; - } - - s_is_data_ready = false; - return val; + return std::make_pair(max_id, max_val); } private: - inline static bool s_is_data_ready{false}; +#define INFRARED_DEV(node) DEVICE_DT_GET(node), + inline static etl::array s_dev{ + DT_FOREACH_STATUS_OKAY(godtek_temp_uart, INFRARED_DEV)}; + inline static etl::bitset s_dev_ready; }; } // namespace ther diff --git a/include/led.hpp b/include/led.hpp index 4735706..5d87554 100644 --- a/include/led.hpp +++ b/include/led.hpp @@ -1,28 +1,95 @@ #ifndef __THER_LED_HPP__ #define __THER_LED_HPP__ +#include +#include #include +#include #include namespace ther { -template class Led { +/* 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: - static auto On() { led_on_dt(&kSpec); } - static auto Off() { led_off_dt(&kSpec); } - template + 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) { - s_work.submit(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: - inline static zpp::periodic_work<> s_work{[]() { - static bool is_on = false; - if (is_on) { - Off(); - } else { - On(); + 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; + } } - is_on = !is_on; - }}; + 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 diff --git a/src/main.cpp b/src/main.cpp index 6e7d12a..c33a442 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,65 +1,8 @@ -#include -#include -#include -#include -#include -#include -#include -namespace { -using StatusLed = ther::Led; -bool is_infrared_ready = false; -auto infrared = DEVICE_DT_GET(DT_NODELABEL(godtek)); -auto GetmaxTemp() -> std::optional { - if (is_infrared_ready) { - sensor_value max_val{}; - bool found = false; - // NTC 8 路最大值 - auto ntc_result = ther::NtcGroup::GetSensorValue(); - if (ntc_result) { - max_val = *ntc_result; - found = true; - } - // 红外数据就绪时参与比较 - sensor_value ir_val{}; - if (0 == sensor_sample_fetch_chan(infrared, SENSOR_CHAN_AMBIENT_TEMP)) { - if (0 == - sensor_channel_get(infrared, SENSOR_CHAN_AMBIENT_TEMP, &ir_val)) { - double ir_t = sensor_value_to_double(&ir_val); - // printk("[ir] = %.2f°C\n", ir_t); - if (!found || ir_val.val1 > max_val.val1 || - (ir_val.val1 == max_val.val1 && ir_val.val2 > max_val.val2)) { - max_val = ir_val; - } - max_val = ir_val; +#include - // printk("[out] sent = %.2f°C\n", sensor_value_to_double(&max_val)); - is_infrared_ready = false; - } - } - return max_val; - } - return std::nullopt; -} -} // namespace auto main(void) -> int { - using namespace std::chrono_literals; - printk("app on board %s\n", CONFIG_BOARD); - // auto wdt = app::WatchDogConfig{}; - StatusLed::Flash(1s); - ther::Com::Init(); - ther::HeatingPad::Start(1.0f); - // ther::HeatingPad::Start(sensor_value{42, 0}); - sensor_trigger tri{.type = SENSOR_TRIG_DATA_READY, - .chan = SENSOR_CHAN_AMBIENT_TEMP}; - sensor_trigger_set(infrared, &tri, - [](const device *dev, const sensor_trigger *trig) { - is_infrared_ready = true; - }); while (1) { - if (auto v = GetmaxTemp(); v.has_value()) { - ther::Com::Send(v.value()); - } k_sleep(K_MSEC(20)); } diff --git a/west.yml b/west.yml index ed72fb4..a8bc7a2 100644 --- a/west.yml +++ b/west.yml @@ -22,8 +22,8 @@ manifest: path: modules/zpp remote: robotstorm revision: dev - - name: dr2501a_g070rb - path: boards/dr2501a_g070rb + - name: dr2501a + path: boards/dr2501a remote: robotstorm revision: main - name: led_strip_indicator @@ -34,6 +34,10 @@ manifest: path: modules/godtek_temp remote: robotstorm revision: main + - name: ch9438 + path: modules/ch9438 + remote: robotstorm + revision: main # - name: heading_pad # path: modules/heading_pad # revision: main