forked from EmbeddedTeam/app_photomagnetic
- Add UID encoding/decoding with flash storage and CRC16 validation - Add write UID (0x07) and LED strip color (0x08) protocol commands - Add debug LED strip configuration option - Switch MCUboot signing from RSA-2048 to ECDSA-P256 - Add SMP serial client for firmware upload over UART - Add firmware version output on boot - Update upgrade documentation with ECDSA key generation steps
152 lines
4.9 KiB
C++
152 lines
4.9 KiB
C++
#ifndef __THER_COM_HPP__
|
|
#define __THER_COM_HPP__
|
|
|
|
#include "led.hpp"
|
|
#include <etl/delegate.h>
|
|
#include <etl/signal.h>
|
|
#include <led_strip_indicator/led_strip_indicator.hpp>
|
|
#include <stdio.h>
|
|
#include <uart_com/simple_protocal.hpp>
|
|
#include <uid.hpp>
|
|
#include <zephyr/app_version.h>
|
|
#include <zephyr/drivers/hwinfo.h>
|
|
#include <zephyr/drivers/sensor.h>
|
|
#include <zpp/driver.hpp>
|
|
#include <zpp/error.hpp>
|
|
#ifdef CONFIG_APP_DFU
|
|
#include <zephyr/sys/reboot.h>
|
|
#endif
|
|
namespace ther {
|
|
|
|
class Com {
|
|
public:
|
|
enum HostStatus : uint8_t { STANDBY, RUNNING, PAUSE, ERROR };
|
|
using RunningStateSignal = etl::signal<void(HostStatus), 10>;
|
|
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<void(uint8_t, uint8_t, uint8_t), 4>;
|
|
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<const uint8_t,
|
|
uart_com::SimpleProtocal::CallbackType>
|
|
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<const uint8_t> s_id_buff;
|
|
inline static auto s_heating_state = false;
|
|
};
|
|
} // namespace ther
|
|
|
|
#endif
|