新增UART0 RX泵任务功能,将GPIO20接收到的串口数据按切行、剥离后以tag=UART推入ring buffer,通过HTTP /logs接口显示在网页日志面板。 接线方式:任意串口源TX连接至H1/H2的ESP_RX引脚,波特率3M 8N1。 feat(motor_ota): GD32 OTA增加包级防呆机制防止错误固件刷入 中继触发前校验gd32_ota镜像向量表身份(Gd32FlashStore::validateStoredImageIdentity), 对Bootloader包或非APP包在WiFi /ota/relay与BLE 0xF7均拒绝中继, 避免GD32 APP区被错误包擦除。新增0x87完成码用于固件身份验证失败场景。 feat(motor_state): 扩展CAN状态数据结构支持CONFIG负载 扩展motor_slot_t结构体,新增config_rx_count、config_seq和config_data字段 用于存储CONFIG帧的相关信息。CAN状态数据包大小从44B扩展到76B, 页面总数从6调整为9,支持目标值回报的配置数据传输。 fix(motor_ota): 修复OTA取消流程中的信用度管理和任务清理问题 ★ 先复位credit再发送CANCEL命令,防止传输卡住时背压导致CANCEL被拒绝。 延长取消等待时间至10s覆盖最坏情况,确保feedTask正常退出而非强制删除。 取消完成后复位credit防止锁存死锁,确保后续通信正常进行。 fix(http_server): 修复HTTP请求处理中的边界检查和安全验证 拒绝chunked请求(content_len<=0)防止无限循环,添加通道参数范围验证(ch 0~2), 在OTA中继触发前验证固件身份防止错误包刷入,使用http_json_append避免缓冲区越界。 refactor(gd32_flash): 实现GD32固件身份验证算法确保刷写安全 基于Cortex-M向量表内容实现包级身份校验,通过MSP和复位向量位置 区分APP包、Bootloader包和无效固件,为OTA安全提供基础保障。 BREAKING CHANGE: 电机状态API数据格式变更,CAN通道参数验证更严格
84 lines
3.2 KiB
C
84 lines
3.2 KiB
C
/*
|
||
* motor_state.h - 被动接收 GD32 多电机状态推送(SPI TYPE 0xC5)
|
||
*
|
||
* 与 CAN 0xC1 / ADC 0xC4 同模型:GD32 250ms 主动按铃推送(独立任务位),ESP32 takeEvent 侧解析入库。
|
||
* 是否推送由 GD32 CONFIG_MOTOR_STATE_ENABLE 决定;ESP32 无本地开关,有帧即解析。
|
||
*
|
||
* payload 格式(每页):
|
||
* [0] page, [1] total_pages, [2] entry_count, [3] active_count
|
||
* [4..] 每个 entry 76B:
|
||
* [0] node_id, [1] channel, [2] online, [3] dlc,
|
||
* [4..7] rx_count (LE), [8..11] seq (LE),
|
||
* [12..43] data[32] (原始 STATUS payload)
|
||
* [44..47] config_rx_count (LE), [48..51] config_seq (LE),
|
||
* [52..75] config_data[24] (原始 CONFIG payload, 目标值回报)
|
||
*
|
||
* 同一节点号可能同时挂在多个 CAN 通道(两台电机同号异线),
|
||
* 缓存表与 GD32 端一致按 node×channel 双键存储(27 槽)。
|
||
*/
|
||
#ifndef MOTOR_STATE_H
|
||
#define MOTOR_STATE_H
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
#include <stddef.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#define MOTOR_MAX_NODES 9
|
||
#define MOTOR_CHANNELS 3
|
||
#define MOTOR_MAX_SLOTS (MOTOR_MAX_NODES * MOTOR_CHANNELS)
|
||
#define MOTOR_STATUS_DLC 32
|
||
#define MOTOR_CONFIG_DLC 24
|
||
#define MOTOR_ENTRY_SIZE 76
|
||
#define MOTOR_PAGE_HEADER 4
|
||
#define MOTOR_TOTAL_PAGES 9
|
||
|
||
/** @brief 单电机状态快照。 */
|
||
typedef struct {
|
||
uint8_t node_id; ///< 1-9, 0=空槽
|
||
uint8_t channel; ///< CAN 通道 (0/1/2)
|
||
uint8_t online; ///< 1=在线, 0=离线
|
||
uint8_t dlc; ///< STATUS 帧 DLC (正常=32)
|
||
uint32_t rx_count; ///< 累计收到帧数
|
||
uint32_t seq; ///< GD32 侧更新序号
|
||
uint8_t data[MOTOR_STATUS_DLC]; ///< 原始 STATUS payload
|
||
uint32_t config_rx_count; ///< 累计收到 CONFIG 帧数
|
||
uint32_t config_seq; ///< CONFIG 更新序号
|
||
uint8_t config_data[MOTOR_CONFIG_DLC]; ///< 原始 CONFIG payload (目标值回报)
|
||
} motor_slot_t;
|
||
|
||
/** @brief 全局电机状态表。 */
|
||
typedef struct {
|
||
motor_slot_t slots[MOTOR_MAX_SLOTS]; ///< 按 (node_id-1)*MOTOR_CHANNELS+channel 索引
|
||
uint8_t active_count; ///< 在线电机数
|
||
uint8_t boot_active; ///< 1=总线上有电机在 BOOT(0x103 心跳,来自 0xC5 头 bit7)
|
||
uint8_t valid_slots; ///< 有效槽位数(node_id!=0)
|
||
int64_t recv_ms; ///< ESP32 最近收到时 esp_timer ms
|
||
bool have_data; ///< 至少收到过一帧
|
||
} motor_state_table_t;
|
||
|
||
/**
|
||
* @brief 处理一帧 0xC5 EVENT payload(由 can_fb 任务 takeEvent 分发)。
|
||
* @return true 表示已接受并更新。
|
||
*/
|
||
bool onMotorStateEvent(const uint8_t *payload, size_t len);
|
||
|
||
/**
|
||
* @brief 拷贝最新电机状态表(线程安全)。
|
||
* @param[out] out 输出缓冲
|
||
* @return true 表示至少收到过一帧
|
||
*/
|
||
bool getLatestMotorState(motor_state_table_t *out);
|
||
|
||
/** @brief 距离上次收到的毫秒数;无数据返回 UINT32_MAX。 */
|
||
uint32_t motorStateAgeMs(void);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* MOTOR_STATE_H */
|