refactor(protocol): 新增 comm_protocol 协议收发解析层,ble_transport 退化为纯传输
- 删除 protocol.h,帧定义和标定命令码统一迁入 comm_protocol.h - 新增 comm_protocol.c:上行组包(CoP/标定响应)、下行解析+msgq 分发 - ble_transport 剥离所有协议解析和参数 getter,仅保留字节收发+rx 回调注册 - main.c 初始化顺序:ble_transport → comm_protocol → adv_start → cal_init - 更新 README 架构图和项目结构表,补充标定流程章节 - 更新 BALANCE_BOARD_PROTOCOL.md 增加标定命令/响应帧格式文档
This commit is contained in:
+31
-7
@@ -2,15 +2,39 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** @brief BLE 原始数据接收回调类型。 */
|
||||
typedef void (*ble_rx_cb_t)(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief 初始化 BLE 协议栈和 NUS 服务。
|
||||
*
|
||||
* @retval 0 成功。
|
||||
* @retval 负值 初始化错误码。
|
||||
*/
|
||||
int ble_transport_init(void);
|
||||
|
||||
/** @brief 启动 BLE 可连接广播。 */
|
||||
void ble_transport_adv_start(void);
|
||||
|
||||
/**
|
||||
* @brief 通过 NUS 发送二进制数据,内部自动重试最多 3 次。
|
||||
*
|
||||
* @param data 待发送字节缓冲区。
|
||||
* @param len 字节数。
|
||||
*/
|
||||
void ble_transport_send(const uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief 检查 BLE 连接是否就绪(已连接且通知已使能)。
|
||||
*
|
||||
* @retval true 可发送数据。
|
||||
* @retval false 未就绪。
|
||||
*/
|
||||
bool ble_transport_is_ready(void);
|
||||
|
||||
/* --- 下行参数 getter --- */
|
||||
float ble_transport_get_resistance_K(void);
|
||||
float ble_transport_get_resistance_B(void);
|
||||
float ble_transport_get_resistance_Tau(void);
|
||||
float ble_transport_get_spotter_threshold(void);
|
||||
bool ble_transport_get_spotter_enabled(void);
|
||||
int64_t ble_transport_get_last_heartbeat_ms(void);
|
||||
/**
|
||||
* @brief 注册上层原始数据接收回调,NUS 收到数据时透传调用。
|
||||
*
|
||||
* @param cb 回调函数指针。
|
||||
*/
|
||||
void ble_transport_register_rx_cb(ble_rx_cb_t cb);
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
#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]);
|
||||
|
||||
/**
|
||||
* @brief 获取下行消息队列指针,业务层通过 k_msgq_get() 消费。
|
||||
*
|
||||
* @return 指向内部 msgq 的指针。
|
||||
*/
|
||||
struct k_msgq *comm_protocol_get_msgq(void);
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.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 /* 下行: 心跳包 */
|
||||
|
||||
/* CoP flags 位定义 */
|
||||
#define COP_FLAG_FORCE_VALID 0x01U /* 总力 > 阈值,CoP 坐标有意义 */
|
||||
|
||||
/* ─── 板面几何 & 传感器标定 ─── */
|
||||
/* 传感器到板面中心的半宽、半长 (cm)。 */
|
||||
#define BOARD_HALF_WIDTH_CM 42.5f
|
||||
#define BOARD_HALF_LENGTH_CM 16.0f
|
||||
|
||||
/*
|
||||
* ADC → kg 换算推导:
|
||||
* GML670 50kg: 灵敏度 1.75 mV/V, 激励 5V → 满量程输出 8.75 mV
|
||||
* ADS1256: PGA=64, VREF=2.5V → 满量程 ±78.125 mV
|
||||
* 50kg 对应 ADC counts = 8.75 / 78.125 × 8388607 ≈ 939524
|
||||
* 1 LSB = 50.0 / 939524 ≈ 5.322e-5 kg
|
||||
* 如实际激励电压或 VREF 不同,按比例修正此系数。
|
||||
*/
|
||||
#define SENSOR_EXCITATION_V 5.0f
|
||||
#define SENSOR_SENSITIVITY_MVV 1.75f
|
||||
#define SENSOR_RATED_LOAD_KG 50.0f
|
||||
#define ADS1256_VREF_V 2.5f
|
||||
#define ADS1256_PGA 64
|
||||
|
||||
#define ADC_COUNTS_AT_RATED \
|
||||
((SENSOR_SENSITIVITY_MVV * SENSOR_EXCITATION_V) / (2.0f * ADS1256_VREF_V * 1000.0f / ADS1256_PGA) * 8388607.0f)
|
||||
#define ADC_TO_FORCE_SCALE (SENSOR_RATED_LOAD_KG / ADC_COUNTS_AT_RATED)
|
||||
|
||||
/* 总重低于此值时 CoP 无意义(除零保护),单位 kg */
|
||||
#define COP_MIN_FORCE_THRESHOLD 0.5f
|
||||
|
||||
/* ─── 上行: 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; /* = PROTO_SYNC0 */
|
||||
uint8_t sync1; /* = PROTO_SYNC1 */
|
||||
uint8_t type; /* = PROTO_TYPE_COP */
|
||||
uint8_t flags; /* bit0: force_valid */
|
||||
int16_t cop_x; /* 压力中心 X (cm),板面坐标系 */
|
||||
int16_t cop_y; /* 压力中心 Y (cm),板面坐标系 */
|
||||
int16_t force; /* 总重量 (kg) */
|
||||
uint8_t crc; /* CRC-8/MAXIM, 校验 type~force */
|
||||
} __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; /* = PROTO_SYNC0 */
|
||||
uint8_t sync1; /* = PROTO_SYNC1 */
|
||||
uint8_t type; /* = PROTO_TYPE_ENCODER */
|
||||
uint8_t flags; /* 预留,填 0 */
|
||||
float cable_length; /* 拉索长度 (mm) */
|
||||
float velocity; /* 拉索速度 (mm/s) */
|
||||
uint8_t crc; /* CRC-8/MAXIM */
|
||||
} __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; /* = PROTO_SYNC0 */
|
||||
uint8_t sync1; /* = PROTO_SYNC1 */
|
||||
uint8_t type; /* = PROTO_TYPE_RESISTANCE */
|
||||
float K; /* 刚度 (N/m) */
|
||||
float B; /* 阻尼 (Ns/m) */
|
||||
float Tau; /* 时间常数 (s) */
|
||||
uint8_t crc; /* CRC-8/MAXIM */
|
||||
} __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; /* = PROTO_SYNC0 */
|
||||
uint8_t sync1; /* = PROTO_SYNC1 */
|
||||
uint8_t type; /* = PROTO_TYPE_SPOTTER */
|
||||
float threshold; /* 保护力阈值 (N) */
|
||||
uint8_t enable; /* 0 = 关闭, 1 = 启用 */
|
||||
uint8_t crc; /* CRC-8/MAXIM */
|
||||
} __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; /* = PROTO_SYNC0 */
|
||||
uint8_t sync1; /* = PROTO_SYNC1 */
|
||||
uint8_t type; /* = PROTO_TYPE_HEARTBEAT */
|
||||
uint8_t counter; /* 滚动计数,用于活性检测 */
|
||||
uint8_t crc; /* CRC-8/MAXIM */
|
||||
} __attribute__((packed));
|
||||
|
||||
union heartbeat_pkt_t {
|
||||
struct heartbeat_frame_t frame;
|
||||
uint8_t bytes[sizeof(struct heartbeat_frame_t)];
|
||||
};
|
||||
Reference in New Issue
Block a user