85 lines
3.2 KiB
C++
85 lines
3.2 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 */
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
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 */
|