This commit is contained in:
2026-03-31 23:30:33 +08:00
commit 760043c8e7
1615 changed files with 1406836 additions and 0 deletions

183
App/Can/snc_can_app.h Normal file
View File

@@ -0,0 +1,183 @@
#ifndef __SNC_CAN_APP_H
#define __SNC_CAN_APP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "fdcan.h"
#define SNC_ODOM_TIMEOUT_MS 300U
/* ========================= 协议 CAN ID ========================= */
#define SNC_CAN_ID_HEARTBEAT 0x080U
#define SNC_CAN_ID_CMD_VEL 0x100U
#define SNC_CAN_ID_STATUS 0x181U
#define SNC_CAN_ID_ACTUAL_RPM 0x182U
#define SNC_CAN_ID_TARGET_RPM 0x183U
#define SNC_CAN_ID_COMM_DIAG 0x184U
#define SNC_CAN_ID_ODOM 0x200U
/* ========================= 系统状态定义 ========================= */
typedef enum
{
SNC_SYSTEM_BOOTING = 0,
SNC_SYSTEM_OPERATIONAL = 1,
SNC_SYSTEM_SAFE_FAULT = 2
} SNC_SystemState_t;
typedef enum
{
SNC_SYSTEM_HEALTH_OK = 0,
SNC_SYSTEM_HEALTH_WARNING = 1,
SNC_SYSTEM_HEALTH_FAULT = 2
} SNC_SystemHealth_t;
/* ========================= 诊断位定义 ========================= */
typedef enum
{
SNC_DIAG_COMM_TIMEOUT = (1UL << 0),
SNC_DIAG_CAN_BUS_OFF = (1UL << 1),
SNC_DIAG_CMD_CRC_STORM = (1UL << 2),
SNC_DIAG_CMD_CNT_STORM = (1UL << 3),
SNC_DIAG_MOTOR_FL_STALL = (1UL << 4),
SNC_DIAG_MOTOR_RL_STALL = (1UL << 5),
SNC_DIAG_MOTOR_FR_STALL = (1UL << 6),
SNC_DIAG_MOTOR_RR_STALL = (1UL << 7),
SNC_DIAG_CONTROL_SATURATION = (1UL << 8)
} SNC_DiagBits_t;
/* ========================= 下位机状态快照 ========================= */
typedef struct
{
uint8_t state;
uint8_t health;
uint32_t diag_bits;
uint8_t cmd_age_10ms;
uint8_t status_counter;
uint32_t last_update_ms;
bool online;
} SNC_ChassisStatus_t;
/* ========================= 轮速数据 ========================= */
typedef struct
{
int16_t fl;
int16_t rl;
int16_t fr;
int16_t rr;
uint32_t last_update_ms;
} SNC_WheelRpmFrame_t;
/* ========================= 里程增量 ========================= */
typedef struct
{
int16_t fl_delta;
int16_t rl_delta;
int16_t fr_delta;
int16_t rr_delta;
uint32_t last_update_ms;
} SNC_OdomDeltaFrame_t;
/**
* @brief 里程增量累加器
*
* 解决 0x200 增量帧的"漏积分/重复积分"问题:
* - ISR 收到每帧 0x200 时,将增量**累加**到此结构体(不覆盖)
* - 消费者调用 SNC_CAN_ConsumeOdomDelta() 原子取走累计值并清零
*
* 这样即使消费者频率 (100ms) 低于帧到达频率 (~60ms)
* 也不会丢失任何增量;也不会重复消费同一份增量。
*/
typedef struct
{
int32_t fl_accum; /**< 左前轮累计增量 ticks (int32 防溢出) */
int32_t rl_accum; /**< 左后轮累计增量 ticks */
int32_t fr_accum; /**< 右前轮累计增量 ticks */
int32_t rr_accum; /**< 右后轮累计增量 ticks */
uint32_t first_frame_ms; /**< 本次累加窗口内第一帧的时间戳 [ms] */
uint32_t last_frame_ms; /**< 本次累加窗口内最后一帧的时间戳 [ms] */
uint32_t span_ms; /**< 本次累计增量实际覆盖的时间窗 [ms] */
uint8_t frame_count; /**< 本次累加窗口内收到的帧数 */
} SNC_OdomDeltaAccum_t;
/* ========================= 通信诊断 ========================= */
typedef struct
{
uint8_t valid_cmd_total_lsb;
uint8_t crc_error_total_lsb;
uint8_t counter_reject_total_lsb;
uint8_t can_tx_drop_total_lsb;
uint8_t busoff_total_lsb;
uint8_t rx_overrun_total_lsb;
uint8_t last_accepted_counter;
uint8_t consecutive_counter_errors;
uint8_t consecutive_crc_errors;
uint32_t last_update_ms;
} SNC_CommDiagFrame_t;
/* ========================= 上位机应用层总状态 ========================= */
typedef struct
{
SNC_ChassisStatus_t status;
SNC_WheelRpmFrame_t actual_rpm;
SNC_WheelRpmFrame_t target_rpm;
SNC_OdomDeltaFrame_t odom_delta; /**< 最近一帧快照 (保留兼容性, 勿用于积分) */
SNC_OdomDeltaAccum_t odom_accum; /**< 里程增量累加器 (正确消费入口) */
SNC_CommDiagFrame_t comm_diag;
uint8_t tx_counter;
uint8_t tx_ctrl_flags;
uint32_t tx_total;
uint32_t tx_fail_total;
uint32_t rx_total;
} SNC_CAN_AppContext_t;
/* ========================= 全局上下文 ========================= */
extern SNC_CAN_AppContext_t g_snc_can_app;
/* ========================= 初始化与任务 ========================= */
void SNC_CAN_AppInit(void);
void SNC_CAN_20msTask(void);
void SNC_CAN_100msTask(void);
void SNC_CAN_PollOnlineState(uint32_t now_ms);
/* ========================= 发送接口 ========================= */
HAL_StatusTypeDef SNC_CAN_SendHeartbeat(void);
HAL_StatusTypeDef SNC_CAN_SendCmdVel(float vx_mps, float wz_radps, uint8_t ctrl_flags);
/* ========================= 接收回调 ========================= */
void SNC_CAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t rxFifo0ITs);
/* ========================= 数据读取接口 ========================= */
const SNC_CAN_AppContext_t *SNC_CAN_GetContext(void);
/**
* @brief 原子取走并清零里程增量累加器
*
* 消费者monitorTask每周期调用一次取走自上次消费以来
* ISR 累积的全部增量帧总和。返回后累加器归零,等待下一批帧。
*
* @param[out] fl 左前轮累计增量 ticks (截断为 int16)
* @param[out] rl 左后轮累计增量 ticks
* @param[out] fr 右前轮累计增量 ticks
* @param[out] rr 右后轮累计增量 ticks
* @param[out] dt_ms 累加增量实际覆盖的时间窗 [ms]
* 若无法可靠计算(如系统首帧)则为 0可用默认帧间隔替代
* @return 本次取走的帧数0 表示期间没有新帧到达
*/
uint8_t SNC_CAN_ConsumeOdomDelta(int16_t *fl, int16_t *rl,
int16_t *fr, int16_t *rr,
uint32_t *dt_ms);
/* ========================= 工具接口 ========================= */
uint8_t SNC_CAN_Crc8J1850(const uint8_t *data, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif /* __SNC_CAN_APP_H */