Files
ESP32_COMM/main/monitor/motor_state.h
T
小龙虾 ebb3dcdf38 feat(debug_log): 新增UART0 RX泵任务支持串口日志转发
新增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通道参数验证更严格
2026-09-01 02:49:34 +08:00

84 lines
3.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 */