BLE配网协议 - 分包、组包和重传功能指南
概述
本文档详细介绍了BLE配网协议中新增的MTU分包、组包和重传功能。这些功能确保在BLE连接的MTU限制下,能够可靠地传输大数据包。
功能特性
1. MTU适配
- 动态MTU设置: 支持20-512字节的MTU范围
- 自动分片判断: 根据MTU大小自动判断是否需要分片
- 最优分片计算: 智能计算最少分片数量
2. 数据分包
- 分片类型: 支持单包、首片、中间片、尾片四种类型
- 分片标识: 每个分片包含唯一ID和总分片数信息
- 数据完整性: 包含原始数据长度和偏移信息
- 最大分片数: 支持最多32个分片
3. 数据组包
- 分片接收: 支持乱序接收分片
- 重复检测: 自动检测和忽略重复分片
- 完整性验证: 确保所有分片接收完成后才进行重组
- 内存管理: 自动管理重组缓冲区
4. 可靠重传
- 自动重传: 支持最多3次重传
- 超时机制: 可配置的重传超时时间
- ACK确认: 支持确认机制停止重传
- 资源清理: 自动清理超时的重传信息
协议格式
分片头格式
typedef struct __attribute__((packed)) {uint8_t frag_type:2; // 分片类型 (0:单包, 1:首片, 2:中间片, 3:尾片)uint8_t frag_id:6; // 分片ID (0-63)uint8_t total_frags; // 总分片数uint16_t total_len; // 原始数据总长度uint16_t frag_offset; // 当前分片在原始数据中的偏移
} ble_prov_frag_header_t;
分片帧格式
+--------+--------+--------+--------+--------+--------+
| Header | Version| CMD | SEQ | Length |
+--------+--------+--------+--------+--------+--------+
| 分片头 (6字节) |
+--------+--------+--------+--------+--------+--------+
| 分片数据 |
+--------+--------+--------+--------+--------+--------+
| CRC16 | Tail |
+--------+--------+--------+
API接口
1. MTU设置
/*** 设置MTU大小* @param parser 解析器实例* @param mtu_size MTU大小 (20-512字节)* @return 0成功,其他失败*/
int ble_prov_set_mtu(ble_prov_parser_t *parser, uint16_t mtu_size);
2. 数据分片
/*** 数据分片* @param parser 解析器实例* @param cmd 命令类型* @param data 原始数据* @param data_len 数据长度* @param fragments 输出分片数组* @param frag_lens 分片长度数组* @param frag_count 分片数量* @return 0成功,其他失败*/
int ble_prov_fragment_data(ble_prov_parser_t *parser, uint8_t cmd, const uint8_t *data, uint16_t data_len, uint8_t ***fragments, uint16_t **frag_lens, uint8_t *frag_count);
3. 发送分片
/*** 发送分片数据* @param parser 解析器实例* @param fragments 分片数组* @param frag_lens 分片长度数组* @param frag_count 分片数量* @param send_func 发送函数* @return 0成功,其他失败*/
int ble_prov_send_fragments(ble_prov_parser_t *parser, uint8_t **fragments, uint16_t *frag_lens, uint8_t frag_count, int (*send_func)(const uint8_t *data, uint16_t len));
4. 处理分片
/*** 处理接收到的分片* @param parser 解析器实例* @param frame 协议帧* @return 0成功,1所有分片接收完成,其他失败*/
int ble_prov_process_fragment(ble_prov_parser_t *parser, const ble_prov_frame_t *frame);
5. 重组数据
/*** 重组分片数据* @param parser 解析器实例* @param seq 序列号* @param data 输出重组数据* @param data_len 数据长度* @return 0成功,其他失败*/
int ble_prov_reassemble_data(ble_prov_parser_t *parser, uint8_t seq, uint8_t **data, uint16_t *data_len);
6. 重传管理
/*** 添加重传信息*/
int ble_prov_add_retry(ble_prov_parser_t *parser, const uint8_t *frame_data, uint16_t frame_len, uint8_t seq, uint32_t timeout_ms);/*** 处理ACK确认*/
int ble_prov_process_ack(ble_prov_parser_t *parser, uint8_t seq);/*** 检查并处理重传*/
void ble_prov_check_retries(ble_prov_parser_t *parser, uint32_t current_time, int (*send_func)(const uint8_t *data, uint16_t len));
使用示例
发送端示例
#include "ble_provisioning_protocol.h"// 发送函数
int my_ble_send(const uint8_t *data, uint16_t len) {// 实际的BLE发送实现return ble_gatt_write(data, len);
}void send_large_data(const uint8_t *data, uint16_t data_len) {ble_prov_parser_t parser;uint8_t buffer[1024];ble_prov_config_t config = {0};// 初始化解析器ble_prov_parser_init(&parser, &config, buffer, sizeof(buffer));// 设置MTUble_prov_set_mtu(&parser, 20); // 20字节MTU// 检查是否需要分片if (ble_prov_need_fragmentation(data_len, parser.mtu_size)) {uint8_t **fragments = NULL;uint16_t *frag_lens = NULL;uint8_t frag_count = 0;// 分片数据int ret = ble_prov_fragment_data(&parser, BLE_PROV_CMD_HANDSHAKE, data, data_len,&fragments, &frag_lens, &frag_count);if (ret == 0) {// 发送分片ble_prov_send_fragments(&parser, fragments, frag_lens, frag_count, my_ble_send);// 清理内存for (int i = 0; i < frag_count; i++) {free(fragments[i]);}free(fragments);free(frag_lens);}} else {// 直接发送uint8_t frame_buf[256];int frame_len = ble_prov_build_frame(frame_buf, sizeof(frame_buf),BLE_PROV_CMD_HANDSHAKE, 1,data, data_len);if (frame_len > 0) {my_ble_send(frame_buf, frame_len);}}
}
接收端示例
void handle_received_frame(const ble_prov_frame_t *frame) {static ble_prov_parser_t parser;static bool parser_initialized = false;if (!parser_initialized) {uint8_t buffer[1024];ble_prov_config_t config = {0};ble_prov_parser_init(&parser, &config, buffer, sizeof(buffer));parser_initialized = true;}// 检查是否为分片数据if (frame->length >= sizeof(ble_prov_frag_header_t)) {ble_prov_frag_header_t *frag_header = (ble_prov_frag_header_t*)frame->payload;if (frag_header->frag_type != BLE_PROV_FRAG_SINGLE) {// 处理分片int ret = ble_prov_process_fragment(&parser, frame);if (ret == 1) {// 所有分片接收完成,重组数据uint8_t *reassembled_data = NULL;uint16_t reassembled_len = 0;ret = ble_prov_reassemble_data(&parser, frame->seq, &reassembled_data, &reassembled_len);if (ret == 0) {// 处理重组后的完整数据process_complete_data(frame->cmd, reassembled_data, reassembled_len);free(reassembled_data);}}return;}}// 处理非分片数据process_complete_data(frame->cmd, frame->payload, frame->length);
}
重传处理示例
void periodic_retry_check(void) {static ble_prov_parser_t parser;uint32_t current_time = get_current_time_ms();// 检查并处理重传ble_prov_check_retries(&parser, current_time, my_ble_send);// 清理超时的分片ble_prov_cleanup_fragments(&parser, current_time);
}void handle_ack_received(uint8_t seq) {static ble_prov_parser_t parser;// 处理ACK,停止对应序列号的重传ble_prov_process_ack(&parser, seq);
}
配置参数
默认配置
#define BLE_PROV_DEFAULT_MTU 20 // 默认BLE MTU大小
#define BLE_PROV_MAX_MTU 512 // 最大MTU大小
#define BLE_PROV_MIN_MTU 20 // 最小MTU大小
#define BLE_PROV_MAX_FRAGMENTS 32 // 最大分片数量
#define BLE_PROV_FRAGMENT_TIMEOUT 3000 // 分片超时时间(ms)
#define BLE_PROV_MAX_RETRIES 3 // 最大重传次数
#define BLE_PROV_RETRY_TIMEOUT 1000 // 重传超时时间(ms)
性能优化建议
- MTU设置: 根据实际BLE连接协商的MTU值设置,避免不必要的分片
- 缓冲区大小: 根据最大数据包大小合理设置缓冲区
- 超时时间: 根据网络环境调整重传和分片超时时间
- 内存管理: 及时清理不再使用的分片和重传信息
错误处理
常见错误码
-1
: 参数错误或内存分配失败-2
: 分片不完整0
: 操作成功1
: 所有分片接收完成
故障排除
- 分片失败: 检查MTU设置和数据长度
- 重组失败: 确保所有分片都已接收
- 重传过多: 检查网络连接和超时设置
- 内存泄漏: 确保正确释放分片和重传缓冲区
测试验证
运行分包功能测试程序:
make -f ble_prov_Makefile run-frag
测试包括:
- 分包功能测试
- 组包功能测试
- 重传功能测试
- 超时清理测试
版本历史
- v1.1.0: 新增MTU分包、组包和重传功能
- v1.0.0: 基础BLE配网协议实现
许可证
本项目采用MIT许可证,详见LICENSE文件。