forked from EmbeddedTeam/app_photomagnetic
Refactor thermistor components and update board dependencies
- Remove heating and NTC functionality from communication module - Convert Infrared from template to runtime array-based implementation - Refactor Led to support multiple LEDs with compile-time name validation - Simplify main to remove direct hardware initialization - Update west manifest for dr2501a board and add ch9438 module
This commit is contained in:
parent
e0908bc8f0
commit
a9e8885ec8
@ -1,9 +1,7 @@
|
|||||||
#ifndef __THER_COM_HPP__
|
#ifndef __THER_COM_HPP__
|
||||||
#define __THER_COM_HPP__
|
#define __THER_COM_HPP__
|
||||||
|
|
||||||
#include "heating.hpp"
|
|
||||||
#include "led.hpp"
|
#include "led.hpp"
|
||||||
#include "ntc.hpp"
|
|
||||||
#include <led_strip_indicator/led_strip_indicator.hpp>
|
#include <led_strip_indicator/led_strip_indicator.hpp>
|
||||||
#include <uart_com/simple_protocal.hpp>
|
#include <uart_com/simple_protocal.hpp>
|
||||||
#include <zephyr/drivers/hwinfo.h>
|
#include <zephyr/drivers/hwinfo.h>
|
||||||
@ -50,9 +48,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data[0] == RUNNING) {
|
if (data[0] == RUNNING) {
|
||||||
InfLed::On();
|
|
||||||
} else {
|
} else {
|
||||||
InfLed::Off();
|
|
||||||
}
|
}
|
||||||
printk("set ledsrtip to %d", data[0]);
|
printk("set ledsrtip to %d", data[0]);
|
||||||
const uint8_t id = data[0];
|
const uint8_t id = data[0];
|
||||||
@ -61,40 +57,33 @@ private:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
static auto WHeatingState(uart_com::DataType data) -> void {
|
static auto WHeatingState(uart_com::DataType data) -> void {
|
||||||
if (data.size() != 1) {
|
// if (data.size() != 1) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
const bool state = (data[0] > 0);
|
// const bool state = (data[0] > 0);
|
||||||
if (state) {
|
// if (state) {
|
||||||
HeatingPad::Start(sensor_value{data[0], 0});
|
// HeatingPad::Start(sensor_value{data[0], 0});
|
||||||
} else {
|
// } else {
|
||||||
HeatingPad::Stop();
|
// HeatingPad::Stop();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
static auto RHeatingState(uart_com::DataType data) -> void {
|
static auto RHeatingState(uart_com::DataType data) -> void {
|
||||||
if (data.size() != 0) {
|
// if (data.size() != 0) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
const sensor_value temp = HeatingPad::CurrentTemp();
|
// const sensor_value temp = HeatingPad::CurrentTemp();
|
||||||
const uint8_t state[] = {s_heating_state, (uint8_t)temp.val1,
|
// const uint8_t state[] = {s_heating_state, (uint8_t)temp.val1,
|
||||||
(uint8_t)temp.val2};
|
// (uint8_t)temp.val2};
|
||||||
s_proto->Send(R_HEATING_STATE, state);
|
// s_proto->Send(R_HEATING_STATE, state);
|
||||||
}
|
}
|
||||||
/// Read one pole NTC by index (0~7).
|
/// Read one pole NTC by index (0~7).
|
||||||
static auto ReadPoleNtcTemperature(uart_com::DataType data) -> void {
|
static auto ReadPoleNtcTemperature(uart_com::DataType data) -> void {
|
||||||
if (data.size() != 1) {
|
if (data.size() != 1) {
|
||||||
return;
|
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).
|
/// Read heating pad NTC (onboard ADC).
|
||||||
static auto ReadHeatingPadNtcTemperature(uart_com::DataType data) -> void {
|
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
constexpr static std::pair<const uint8_t,
|
constexpr static std::pair<const uint8_t,
|
||||||
uart_com::SimpleProtocal::CallbackType>
|
uart_com::SimpleProtocal::CallbackType>
|
||||||
@ -113,7 +102,6 @@ private:
|
|||||||
inline static auto s_proto =
|
inline static auto s_proto =
|
||||||
(uart_com::SimpleProtocal *)(DEVICE_DT_GET(DT_NODELABEL(pm_protocal)));
|
(uart_com::SimpleProtocal *)(DEVICE_DT_GET(DT_NODELABEL(pm_protocal)));
|
||||||
inline static auto s_heating_state = false;
|
inline static auto s_heating_state = false;
|
||||||
using InfLed = ther::Led<LED_DT_SPEC_GET(DT_NODELABEL(inf_led))>;
|
|
||||||
};
|
};
|
||||||
} // namespace ther
|
} // namespace ther
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#ifndef __THER_INFRARED_HPP__
|
#ifndef __THER_INFRARED_HPP__
|
||||||
#define __THER_INFRARED_HPP__
|
#define __THER_INFRARED_HPP__
|
||||||
|
#include <etl/algorithm.h>
|
||||||
|
#include <etl/bitset.h>
|
||||||
|
#include <etl/tuple.h>
|
||||||
#include <zephyr/device.h>
|
#include <zephyr/device.h>
|
||||||
#include <zephyr/drivers/sensor.h>
|
#include <zephyr/drivers/sensor.h>
|
||||||
#include <zpp/result.hpp>
|
#include <zpp/result.hpp>
|
||||||
@ -7,41 +10,64 @@
|
|||||||
#include <zpp/work_queue.hpp>
|
#include <zpp/work_queue.hpp>
|
||||||
namespace ther {
|
namespace ther {
|
||||||
|
|
||||||
template <device *kDev> class Infrared {
|
class Infrared {
|
||||||
public:
|
public:
|
||||||
static auto Init() -> zpp::error {
|
static auto Init() -> zpp::error {
|
||||||
static sensor_trigger tri{.type = SENSOR_TRIG_DATA_READY,
|
static sensor_trigger tri{.type = SENSOR_TRIG_DATA_READY,
|
||||||
.chan = SENSOR_CHAN_AMBIENT_TEMP};
|
.chan = SENSOR_CHAN_AMBIENT_TEMP};
|
||||||
if (auto r = sensor_trigger_set(
|
for (auto dev : s_dev) {
|
||||||
kDev, &tri,
|
if (auto r = sensor_trigger_set(
|
||||||
[](const device *dev, const sensor_trigger *trig) {
|
dev, &tri,
|
||||||
s_is_data_ready = true;
|
[](const device *dev, const sensor_trigger *trig) {
|
||||||
});
|
const size_t id = etl::distance(
|
||||||
r != 0) {
|
s_dev.begin(), etl::find(s_dev.begin(), s_dev.end(), dev));
|
||||||
return -ENODEV;
|
s_dev_ready[id] = 1;
|
||||||
};
|
});
|
||||||
|
r != 0) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return zpp::ok();
|
||||||
}
|
}
|
||||||
static auto GetSensorValue()
|
/* One-shot fetch of ALL sensors, return the hottest one. */
|
||||||
-> zpp::result<zpp::value<zpp::value_type::AMBIENT_TEMP>> {
|
static auto GetMaxSensorValue() -> zpp::result<std::pair<int, sensor_value>> {
|
||||||
if (!s_is_data_ready) {
|
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<int>(id);
|
||||||
|
max_val = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
return zpp::error_code::k_nodata;
|
return zpp::error_code::k_nodata;
|
||||||
}
|
}
|
||||||
|
return std::make_pair(max_id, max_val);
|
||||||
if (0 != sensor_sample_fetch(kDev)) {
|
|
||||||
return zpp::error_code::k_io;
|
|
||||||
}
|
|
||||||
|
|
||||||
zpp::value<zpp::value_type::AMBIENT_TEMP> 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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.size()> s_dev_ready;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ther
|
} // namespace ther
|
||||||
|
|||||||
@ -1,28 +1,95 @@
|
|||||||
#ifndef __THER_LED_HPP__
|
#ifndef __THER_LED_HPP__
|
||||||
#define __THER_LED_HPP__
|
#define __THER_LED_HPP__
|
||||||
|
#include <etl/algorithm.h>
|
||||||
|
#include <etl/array.h>
|
||||||
#include <zephyr/drivers/led.h>
|
#include <zephyr/drivers/led.h>
|
||||||
|
#include <zpp/ct_string.hpp>
|
||||||
#include <zpp/work_queue.hpp>
|
#include <zpp/work_queue.hpp>
|
||||||
namespace ther {
|
namespace ther {
|
||||||
|
|
||||||
template <led_dt_spec kSpec> class Led {
|
/* Compile-time check: every LED name must be distinct so that
|
||||||
|
* Led::On/Off/Flash<kName> name lookup stays unambiguous. */
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
consteval auto AreUniqueNames(const etl::array<T, N> &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 <led_dt_spec> 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<led_dt_spec *> work{Flash};
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static auto On() { led_on_dt(&kSpec); }
|
template <zpp::ct_string kName> static auto On() -> zpp::error {
|
||||||
static auto Off() { led_off_dt(&kSpec); }
|
static_assert(IsDeviceName<kName>());
|
||||||
template <typename TRep, typename TPeriod>
|
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 <zpp::ct_string kName> static auto Off() -> zpp::error {
|
||||||
|
static_assert(IsDeviceName<kName>());
|
||||||
|
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 <zpp::ct_string kName, typename TRep, typename TPeriod>
|
||||||
static auto Flash(std::chrono::duration<TRep, TPeriod> period) {
|
static auto Flash(std::chrono::duration<TRep, TPeriod> period) {
|
||||||
s_work.submit(period);
|
static_assert(IsDeviceName<kName>());
|
||||||
|
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<s_led_dev[id]>::work.submit(period);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static zpp::periodic_work<> s_work{[]() {
|
template <zpp::ct_string kName> static consteval auto IsDeviceName() {
|
||||||
static bool is_on = false;
|
for (size_t i = 0; i < s_led_node_name.size(); ++i) {
|
||||||
if (is_on) {
|
if (s_led_node_name[i] == std::string_view(kName)) {
|
||||||
Off();
|
return true;
|
||||||
} else {
|
}
|
||||||
On();
|
|
||||||
}
|
}
|
||||||
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<std::string_view>(
|
||||||
|
DT_FOREACH_STATUS_OKAY(gpio_leds, LED_NODE_NAME));
|
||||||
|
static_assert(AreUniqueNames(s_led_node_name),
|
||||||
|
"LED node names must be unique");
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ther
|
} // namespace ther
|
||||||
|
|||||||
59
src/main.cpp
59
src/main.cpp
@ -1,65 +1,8 @@
|
|||||||
#include <com.hpp>
|
|
||||||
#include <heating.hpp>
|
|
||||||
#include <infrared.hpp>
|
|
||||||
#include <led.hpp>
|
|
||||||
#include <ntc.hpp>
|
|
||||||
#include <optional>
|
|
||||||
#include <watchdog.hpp>
|
|
||||||
namespace {
|
|
||||||
using StatusLed = ther::Led<LED_DT_SPEC_GET(DT_NODELABEL(status_led))>;
|
|
||||||
bool is_infrared_ready = false;
|
|
||||||
auto infrared = DEVICE_DT_GET(DT_NODELABEL(godtek));
|
|
||||||
auto GetmaxTemp() -> std::optional<sensor_value> {
|
|
||||||
if (is_infrared_ready) {
|
|
||||||
sensor_value max_val{};
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
// NTC 8 路最大值
|
#include <zephyr/kernel.h>
|
||||||
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;
|
|
||||||
|
|
||||||
// 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 {
|
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) {
|
while (1) {
|
||||||
if (auto v = GetmaxTemp(); v.has_value()) {
|
|
||||||
ther::Com::Send(v.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
k_sleep(K_MSEC(20));
|
k_sleep(K_MSEC(20));
|
||||||
}
|
}
|
||||||
|
|||||||
8
west.yml
8
west.yml
@ -22,8 +22,8 @@ manifest:
|
|||||||
path: modules/zpp
|
path: modules/zpp
|
||||||
remote: robotstorm
|
remote: robotstorm
|
||||||
revision: dev
|
revision: dev
|
||||||
- name: dr2501a_g070rb
|
- name: dr2501a
|
||||||
path: boards/dr2501a_g070rb
|
path: boards/dr2501a
|
||||||
remote: robotstorm
|
remote: robotstorm
|
||||||
revision: main
|
revision: main
|
||||||
- name: led_strip_indicator
|
- name: led_strip_indicator
|
||||||
@ -34,6 +34,10 @@ manifest:
|
|||||||
path: modules/godtek_temp
|
path: modules/godtek_temp
|
||||||
remote: robotstorm
|
remote: robotstorm
|
||||||
revision: main
|
revision: main
|
||||||
|
- name: ch9438
|
||||||
|
path: modules/ch9438
|
||||||
|
remote: robotstorm
|
||||||
|
revision: main
|
||||||
# - name: heading_pad
|
# - name: heading_pad
|
||||||
# path: modules/heading_pad
|
# path: modules/heading_pad
|
||||||
# revision: main
|
# revision: main
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user