#ifndef __THER_COM_HPP__ #define __THER_COM_HPP__ #include "led.hpp" #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_APP_DFU #include #endif namespace ther { class Com { public: enum HostStatus : uint8_t { STANDBY, RUNNING, PAUSE, ERROR }; using RunningStateSignal = etl::signal; static auto Init() -> zpp::error { s_proto->SetRxCallbackTable(kRxCallbackTable); // 优先使用生产写入的自定义 UID,否则回退芯片 UID Uid::Init(); s_id_buff = Uid::Get(); return zpp::ok(); } static auto SendTemp(sensor_value val) -> void { const uint8_t temp_data[] = {(uint8_t)val.val1, (uint8_t)val.val2}; s_proto->Send(R_TEMP, temp_data); } static auto AddRunningState(RunningStateSignal::slot_type slot) -> bool { return s_running_state_sig.connect(slot); } #ifdef CONFIG_APP_DEBUG_LED_STRIP /// 调试灯带控制(0x08):仅调试固件(CONFIG_APP_DEBUG_LED_STRIP=y)支持, /// 生产固件不编译此命令。订阅后收到命令回调 (r, g, b)。 using LedColorSignal = etl::signal; static auto AddLedColor(LedColorSignal::slot_type slot) -> bool { return s_led_color_sig.connect(slot); } #endif private: enum Addr : uint8_t { R_TEMP = 0, R_GET_ID, W_RUNNING_STATE, W_UID = 0x07, R_VERSION = 0x06, W_LED = 0x08, }; inline static RunningStateSignal s_running_state_sig{}; #ifdef CONFIG_APP_DEBUG_LED_STRIP inline static LedColorSignal s_led_color_sig{}; #endif static auto RunningState(uart_com::DataType data) -> void { if (data.size() != 1) { return; } s_running_state_sig(HostStatus(data[0])); } static auto GetId(uart_com::DataType data) -> void { printk("handle get id"); s_proto->Send(R_GET_ID, uart_com::DataType(s_id_buff)); }; static auto GetVersion(uart_com::DataType data) -> void { // Send version string: major.minor.patchlevel static char ver_buf[16]; snprintf(ver_buf, sizeof(ver_buf), "%d.%d.%d", APP_VERSION_MAJOR, APP_VERSION_MINOR, APP_PATCHLEVEL); printk("[com] GetVersion: %s\n", ver_buf); s_proto->Send(R_VERSION, uart_com::DataType((const uint8_t *)ver_buf, strlen(ver_buf))); }; /// 写 UID(0x07):data 为 10 字节生产 UID → 写入 flash;data 为空 → /// 清除记录(恢复芯片 UID)。 回 ACK:0x00=成功 0x01=写入失败 0x02=长度错误 static auto WriteUid(uart_com::DataType data) -> void { uint8_t status = 0x02; if (data.size() == Uid::kUidLen) { status = (Uid::Write(data) == 0) ? 0x00 : 0x01; } else if (data.empty()) { status = (Uid::Write({}) == 0) ? 0x00 : 0x01; } if (status == 0x00) { // 立即生效:后续 GET_ID(0x01)返回新 UID,无需等重启 s_id_buff = Uid::Get(); } printk("[com] WriteUid len=%zu status=0x%02x\n", data.size(), status); s_proto->Send(W_UID, uart_com::DataType(&status, 1)); }; #ifdef CONFIG_APP_DEBUG_LED_STRIP /// 调试灯带(0x08):data = [R][G][B] → 灯带整体改色,用于开发/产线检查 /// 灯光颜色是否满足需求。(0,0,0) 即熄灭。生产固件不含此命令。 static auto SetLed(uart_com::DataType data) -> void { if (data.size() != 3) { printk("[com] SetLed: expect 3 bytes (R G B), got %zu\n", data.size()); return; } printk("[com] SetLed R=%u G=%u B=%u\n", data[0], data[1], data[2]); s_led_color_sig(data[0], data[1], data[2]); } #endif #ifdef CONFIG_APP_DFU /// 升级命令(0xFF):data[0]=0x01 进入升级模式,data[0]=0x02 查询状态 static auto DfuCommand(uart_com::DataType data) -> void { if (data.size() < 1) return; switch (data[0]) { case 0x01: printk("[com] entering DFU mode, rebooting...\n"); k_msleep(100); sys_reboot(SYS_REBOOT_COLD); break; case 0x02: { uint8_t status = 0x00; s_proto->Send(0xFF, uart_com::DataType(&status, 1)); break; } } } #endif constexpr static std::pair kRxCallbackTable[] = { {R_GET_ID, GetId}, {W_RUNNING_STATE, RunningState}, {R_VERSION, GetVersion}, {W_UID, WriteUid}, #ifdef CONFIG_APP_DEBUG_LED_STRIP {W_LED, SetLed}, #endif #ifdef CONFIG_APP_DFU {0xFF, DfuCommand}, #endif }; inline static auto s_proto = (uart_com::SimpleProtocal *)DEVICE_DT_GET( DT_COMPAT_GET_ANY_STATUS_OKAY(uart_com_simple_protocal)); inline static etl::span s_id_buff; inline static auto s_heating_state = false; }; } // namespace ther #endif