- 实现 node×channel 双键槽位管理,支持同一节点号在不同CAN通道独立缓存 - 扩展电机状态表容量从9个槽位到27个槽位(9节点×3通道) - 添加SPI命令子命令0xFE用于动态设置0xC5推送周期(50-5000ms) - 增加运行时可调推送周期功能,默认250ms,支持50ms-5s范围调节 - 更新CAN通道配置,启用CH1和CH2通道支持 - 版本号更新至1.5.4
86 lines
3.3 KiB
C++
86 lines
3.3 KiB
C++
/**
|
||
* @file motor_ota_relay.h
|
||
* @brief 电机 OTA relay 状态机 — GD32 本地完成与电机 Bootloader 的全部交互。
|
||
*
|
||
* 职责:
|
||
* - AES-128 密钥协商(K_master 存本地 flash)
|
||
* - 固件数据 AES-ECB 加密 + keyed-CRC32
|
||
* - CAN 上逐包 stop-and-wait(发 0x101 → 等 0x102 ACK → 按包号继续)
|
||
* - 进度/完成/错误通过 SPI ring push 报 ESP32
|
||
*
|
||
* ESP32 通过 SPI 0xD0(start) / 0xD1(data) / 0xD3(cancel) 喂数据,
|
||
* GD32 通过 0xD2 ring push 报进度。
|
||
*/
|
||
#ifndef SYS_MOTOR_OTA_RELAY_H
|
||
#define SYS_MOTOR_OTA_RELAY_H
|
||
|
||
#include <cstdint>
|
||
|
||
namespace MotorOtaRelay {
|
||
|
||
/* 电机 Bootloader CAN ID(固定,非节点相关) */
|
||
static constexpr uint32_t kOtaReqId = 0x00000100U; /* Host→Motor 握手 */
|
||
static constexpr uint32_t kOtaDataId = 0x00000101U; /* Host→Motor 数据 */
|
||
static constexpr uint32_t kOtaAckId = 0x00000102U; /* Motor→Host ACK */
|
||
static constexpr uint32_t kOtaWaitId = 0x00000103U; /* Motor→Host IDLE心跳 */
|
||
static constexpr uint32_t kOtaCancelId = 0x00000000U; /* Host→Motor 取消 */
|
||
|
||
static constexpr uint32_t kPacketPayload = 48U; /* 每包有效载荷 */
|
||
static constexpr uint32_t kFrameDlc = 64U; /* CAN FD DLC */
|
||
static constexpr uint32_t kMaxFwSize = 0xC000U; /* 48 KB */
|
||
static constexpr uint32_t kAckTimeoutMs = 5000U; /* 单包 ACK 超时 */
|
||
static constexpr uint32_t kHandshakeTimeoutMs = 3000U;
|
||
|
||
enum class State : uint8_t {
|
||
kIdle = 0,
|
||
kHandshakeReq, /* 已发 [00 AC],等 ACK */
|
||
kHandshakeNonce, /* 已发 nonce,等 36B ACK */
|
||
kHandshakeConfirm, /* 已发 confirm,等 [BA C0] */
|
||
kErase, /* 已发 size,等擦除完成 ACK */
|
||
kTransfer, /* 逐包传输中 */
|
||
kFinishOta, /* 收到 0xF0F0F0F0,已发 [0A AC],等 FINISH ACK */
|
||
kFinished, /* 完成 */
|
||
kError, /* 错误 */
|
||
kPreCancel = 9, /* 等待电机 BOOT 心跳(0x103)确认已进入 Bootloader,然后进 kHandshakeReq */
|
||
kWaitAppRun = 10 /* 尾包 ACK 后电机已跳转,等新 APP 上电自主发的 [0A AC] 运行确认,收到才进 kFinished */
|
||
};
|
||
|
||
struct Status {
|
||
State state;
|
||
uint8_t error_code;
|
||
uint16_t packets_acked;
|
||
uint16_t total_packets;
|
||
uint32_t fw_size;
|
||
};
|
||
|
||
/* 初始化(注册 CAN RX 回调等) */
|
||
void init();
|
||
|
||
/* 主循环推进(从 task_runner 周期调用,建议 1~5ms 一次) */
|
||
void process();
|
||
|
||
/* 数据发送推进:由主循环 TaskRunner 每圈调用,按 SysTick 钟表控制每包间隔
|
||
* (不再走 ISR 计时 + TASK 标志,消除跨上下文计数器竞争)。 */
|
||
void onTxTick();
|
||
|
||
/* CAN RX 分发入口:匹配 0x102 ACK 帧时消费,返回 true 表示已处理 */
|
||
bool onCanFrame(uint8_t channel, uint32_t id, const uint8_t *data, uint8_t len);
|
||
|
||
/* SPI 命令接口 */
|
||
bool start(uint8_t can_channel, uint32_t fw_size);
|
||
/**
|
||
* @brief 喂入固件明文。payload 布局:[offset:u32 LE][data...]
|
||
* offset 为固件绝对字节偏移;重复/重叠区间幂等 ACK,缺口拒绝(→SPI WAIT)。
|
||
* 无 offset 的旧纯流会在 SPI 超时重传时把同一 chunk 追加进环缓(BLF 见前 236B 循环)。
|
||
*/
|
||
bool feedData(const uint8_t *data, uint16_t len);
|
||
void cancel();
|
||
|
||
/* 状态查询 */
|
||
Status getStatus();
|
||
bool isActive();
|
||
|
||
} /* namespace MotorOtaRelay */
|
||
|
||
#endif /* SYS_MOTOR_OTA_RELAY_H */
|