zhangyisong de68631faf Add DFU support with MCUboot serial recovery
Implement device firmware upgrade using MCUboot Serial Recovery over
usart1 (reusing the existing protocol UART). The application layer
handles upgrade commands (0xFF) to trigger bootloader entry, while
MCUboot manages the actual firmware swap with RSA signature
verification.

Key additions:
- sysbuild.conf to enable MCUboot bootloader with signing key
- mcuboot.conf with serial recovery and watchdog feed settings
- Kconfig option APP_DFU (default y) with conditional compilation
- dfu.cpp module for DFU initialization
- Upgrade command callback in com.hpp (bootmode_set + sys_reboot)
- Documentation for upgrade procedures and change notes
2026-08-18 21:39:59 +08:00

93 lines
2.6 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 <uart_com/simple_protocal.hpp>
#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);
auto size = hwinfo_get_device_id(buff, sizeof(buff));
s_id_buff = etl::span<uint8_t>(buff, size);
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);
}
private:
enum Addr : uint8_t {
R_TEMP = 0,
R_GET_ID,
W_RUNNING_STATE,
};
inline static RunningStateSignal s_running_state_sig{};
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));
};
#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},
#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 uint8_t buff[20];
inline static auto s_heating_state = false;
inline static etl::span<uint8_t> s_id_buff;
};
} // namespace ther
#endif