Files
balance-board/inc/comm_protocol.h
T

236 lines
7.5 KiB
C

#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/crc.h>
/* ═══════════════════════════════════════════════════════════════════
* 帧常量
* ═══════════════════════════════════════════════════════════════════ */
/* 双帧头比单字节魔数更容易在连续字节流里完成包起始判定 */
#define PROTO_SYNC0 0xAAU
#define PROTO_SYNC1 0x55U
#define PROTO_TYPE_COP 0x01U /* 上行: 压力中心 (CoP) 帧 */
#define PROTO_TYPE_ENCODER 0x02U /* 上行: 电机编码器帧(预留) */
#define PROTO_TYPE_RESISTANCE 0x10U /* 下行: 阻力参数 (K, B, Tau) */
#define PROTO_TYPE_SPOTTER 0x11U /* 下行: Spotter Mode 保护阈值 */
#define PROTO_TYPE_HEARTBEAT 0x20U /* 下行: 心跳包 */
#define PROTO_TYPE_CAL_CMD 0x30U /* 下行: 标定命令 */
#define PROTO_TYPE_CAL_RESP 0x31U /* 上行: 标定响应 */
/* CoP flags 位定义 */
#define COP_FLAG_FORCE_VALID 0x01U /* 总力 > 阈值,CoP 坐标有意义 */
/* ═══════════════════════════════════════════════════════════════════
* 帧结构定义
* ═══════════════════════════════════════════════════════════════════ */
/* ─── 上行: CoP 帧 (11 bytes, 50 Hz) ───
* [AA 55 01 flags cop_x(2) cop_y(2) force(2) crc]
*/
struct cop_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
uint8_t flags;
int16_t cop_x;
int16_t cop_y;
int16_t force;
uint8_t crc;
} __attribute__((packed));
union cop_pkt_t {
struct cop_frame_t frame;
uint8_t bytes[sizeof(struct cop_frame_t)];
};
/* ─── 上行: 电机编码器帧 (13 bytes, 预留) ───
* [AA 55 02 flags cable_length(4) velocity(4) crc]
*/
struct encoder_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
uint8_t flags;
float cable_length;
float velocity;
uint8_t crc;
} __attribute__((packed));
union encoder_pkt_t {
struct encoder_frame_t frame;
uint8_t bytes[sizeof(struct encoder_frame_t)];
};
/* ─── 下行: 阻力参数帧 (16 bytes) ───
* [AA 55 10 K(4) B(4) Tau(4) crc]
*/
struct resistance_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
float K;
float B;
float Tau;
uint8_t crc;
} __attribute__((packed));
union resistance_pkt_t {
struct resistance_frame_t frame;
uint8_t bytes[sizeof(struct resistance_frame_t)];
};
/* ─── 下行: Spotter Mode 帧 (9 bytes) ───
* [AA 55 11 threshold(4) enable crc]
*/
struct spotter_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
float threshold;
uint8_t enable;
uint8_t crc;
} __attribute__((packed));
union spotter_pkt_t {
struct spotter_frame_t frame;
uint8_t bytes[sizeof(struct spotter_frame_t)];
};
/* ─── 下行: 心跳帧 (5 bytes, ~1 Hz) ───
* [AA 55 20 counter crc]
*/
struct heartbeat_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
uint8_t counter;
uint8_t crc;
} __attribute__((packed));
union heartbeat_pkt_t {
struct heartbeat_frame_t frame;
uint8_t bytes[sizeof(struct heartbeat_frame_t)];
};
/* ═══════════════════════════════════════════════════════════════════
* 标定子命令码 & 状态码
* ═══════════════════════════════════════════════════════════════════ */
#define CAL_SUBCMD_START_L1 0x01U
#define CAL_SUBCMD_TARE_CH 0x02U
#define CAL_SUBCMD_GAIN_CH 0x03U
#define CAL_SUBCMD_COMMIT_L1 0x04U
#define CAL_SUBCMD_ABORT 0x05U
#define CAL_SUBCMD_START_L2 0x10U
#define CAL_SUBCMD_RECORD_GRID 0x11U
#define CAL_SUBCMD_COMMIT_L2 0x12U
#define CAL_SUBCMD_ERASE 0x20U
#define CAL_SUBCMD_QUERY 0x21U
#define CAL_STATUS_OK 0x00U
#define CAL_STATUS_ERR_STATE 0x01U
#define CAL_STATUS_ERR_NVS 0x02U
#define CAL_STATUS_ERR_PARAM 0x03U
/* ─── 下行: 标定命令帧 (10 bytes) ───
* [AA 55 30 subcmd target param(4) crc]
*/
struct cal_cmd_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
uint8_t subcmd;
uint8_t target;
float param;
uint8_t crc;
} __attribute__((packed));
union cal_cmd_pkt_t {
struct cal_cmd_frame_t frame;
uint8_t bytes[sizeof(struct cal_cmd_frame_t)];
};
/* ─── 上行: 标定响应帧 (14 bytes) ───
* [AA 55 31 status subcmd data(8) crc]
*/
struct cal_resp_frame_t {
uint8_t sync0;
uint8_t sync1;
uint8_t type;
uint8_t status;
uint8_t subcmd;
uint8_t data[8];
uint8_t crc;
} __attribute__((packed));
union cal_resp_pkt_t {
struct cal_resp_frame_t frame;
uint8_t bytes[sizeof(struct cal_resp_frame_t)];
};
/* ═══════════════════════════════════════════════════════════════════
* 下行消息队列 payload
* ═══════════════════════════════════════════════════════════════════ */
struct comm_msg_resistance {
float K, B, Tau;
};
struct comm_msg_spotter {
float threshold;
bool enable;
};
struct comm_msg_heartbeat {
uint8_t counter;
};
enum comm_msg_type {
COMM_MSG_RESISTANCE,
COMM_MSG_SPOTTER,
COMM_MSG_HEARTBEAT,
};
struct comm_msg {
enum comm_msg_type type;
union {
struct comm_msg_resistance resistance;
struct comm_msg_spotter spotter;
struct comm_msg_heartbeat heartbeat;
};
};
/* ═══════════════════════════════════════════════════════════════════
* 协议层 API
* ═══════════════════════════════════════════════════════════════════ */
/**
* @brief 初始化协议层,注册 BLE 传输层收数据回调。
*
* 必须在 ble_transport_init() 之后调用。
*
* @retval 0 成功。
*/
int comm_protocol_init(void);
/**
* @brief 组包并发送 CoP 上行帧。
*
* @param flags COP_FLAG_* 位组合。
* @param cop_x 压力中心 X (cm)。
* @param cop_y 压力中心 Y (cm)。
* @param force 总力 (kg)。
*/
void comm_protocol_send_cop(uint8_t flags, int16_t cop_x, int16_t cop_y, int16_t force);
/**
* @brief 组包并发送标定响应上行帧。
*
* @param status 结果状态码 (CAL_STATUS_*)。
* @param subcmd 对应的子命令回显。
* @param data 8 字节响应数据。
*/
void comm_protocol_send_cal_resp(uint8_t status, uint8_t subcmd, const uint8_t data[8]);