Skip to content

数据包格式

本文档定义蓝牙通信协议中的数据包格式、接口分类、加密方式等核心规范。

接口分类

蓝牙通信协议定义了三类接口,分别用于不同的通信场景:

接口类型功能说明使用场景
A接口开锁记录及报警信息向云平台汇报设备→云平台
B接口固件升级、开锁账号下发指令云平台→设备
C接口手机APP与智能门锁的交互信令APP/网关↔设备

主要使用接口

大部分开发场景使用C接口进行APP与设备的交互。

数据包结构

字段定义

通信数据包由以下字段组成:

字段名称长度说明
包头4字节固定标识,用于识别数据包起始位置
包类型1字节区分请求包和应答包
包序号2字节数据包序列号,用于匹配请求和应答
包标识1字节包版本和加密类型
数据长度4字节数据块长度信息
数据块变长实际业务数据内容
校验位2字节数据完整性校验

数据包示意图

┌──────────────────────────────────────────────────────────────┐
│  包头   │包类型│ 包序号 │包标识│  数据长度  │  数据块  │校验位│
│ 4 Bytes │1 Byte│2 Bytes │1 Byte│  4 Bytes  │ 变长    │2 Bytes│
└──────────────────────────────────────────────────────────────┘

字段详细说明

1. 包头 (Header)

  • 长度: 4字节
  • 固定值: 0xEF01EE02
  • 字节序: 大端序(Big-Endian)
  • 用途: 标识数据包起始位置,用于数据流同步
c
// C语言示例
#define PACKET_HEADER 0xEF01EE02

uint8_t header[4] = {0xEF, 0x01, 0xEE, 0x02};

2. 包类型 (Packet Type)

  • 长度: 1字节
  • 取值:
    • 0x01 - 请求包(Request)
    • 0x11 - 应答包(Response)
请求流程:
APP/网关 ──[0x01]──> 设备 (请求)
设备     ──[0x11]──> APP/网关 (应答)

3. 包序号 (Sequence Number)

  • 长度: 2字节
  • 字节序: 大端序(Big-Endian)
  • 取值范围: 0x0001 ~ 0xFFFF
  • 规则:
    • 1开始计数
    • 每次请求递增1
    • 应答包序号与请求包序号相同
c
// 包序号示例
uint16_t seq = 1;  // 第一个请求包

// 请求包序号: 0x0001
send_request(seq);

// 应答包序号: 0x0001 (与请求相同)
receive_response(seq);

seq++;  // 下一个请求包序号: 0x0002

序号回绕

当包序号达到0xFFFF后,下一个包序号回到0x0001(不使用0x0000)。

4. 包标识 (Packet Flags)

  • 长度: 1字节
  • 结构: [版本(高4位)][加密类型(低4位)]
包标识字节结构:
┌─────────────┬─────────────┐
│  版本(4bit) │ 加密类型(4bit)│
│   Bit 7~4   │   Bit 3~0   │
└─────────────┴─────────────┘

加密类型定义

加密类型值加密方式密钥来源说明
0x0明文数据不加密,用于公开信息
0x1AES128预设密钥使用AES-128加密
0x2SM4事先约定密钥使用SM4加密,密钥预先配置
0x3SM4设备指定密钥使用SM4加密,密钥由设备动态分配

示例

c
// 版本1, SM4加密(事先约定密钥)
uint8_t flags = 0x12;  // 0001 0010
                       //  ↑    ↑
                       //  版本1 SM4(约定密钥)

// 版本1, 明文传输
uint8_t flags = 0x10;  // 0001 0000
                       //  ↑    ↑
                       //  版本1 明文

5. 数据长度 (Data Length)

  • 长度: 4字节
  • 字节序: 大端序(Big-Endian)
  • 结构: [加密后长度(高16位)][原始长度(低16位)]
数据长度字段结构(4字节):
┌────────────────┬────────────────┐
│ 加密后长度(2B) │  原始长度(2B)  │
│   Byte 0~1     │   Byte 2~3     │
└────────────────┴────────────────┘

字段说明

字段长度说明
加密后长度2字节实际传输的数据块长度(加密+填充后)
原始长度2字节加密前的原始数据长度

计算规则

c
// 示例: 原始数据100字节, SM4加密(16字节对齐)
uint16_t original_len = 100;           // 原始长度
uint16_t encrypted_len = 112;          // 加密后长度(向上对齐到16倍数)

// 数据长度字段 (大端序)
uint8_t data_length[4] = {
    (encrypted_len >> 8) & 0xFF,   // [0] 加密后长度高字节
    encrypted_len & 0xFF,           // [1] 加密后长度低字节
    (original_len >> 8) & 0xFF,    // [2] 原始长度高字节
    original_len & 0xFF             // [3] 原始长度低字节
};
// 结果: {0x00, 0x70, 0x00, 0x64}

明文传输

当使用明文传输时(加密类型=0),加密后长度和原始长度相同

6. 数据块 (Data Block)

  • 长度: 变长
  • 内容: 具体业务数据,格式由各接口定义
  • 加密: 根据包标识中的加密类型进行加密

数据块填充规则

加密时需要进行数据填充以满足块对齐要求:

加密算法块大小填充方式
AES12816字节PKCS#7填充
SM416字节PKCS#7填充

PKCS#7填充示例:

原始数据(10字节): 01 02 03 04 05 06 07 08 09 0A
填充后(16字节):   01 02 03 04 05 06 07 08 09 0A 06 06 06 06 06 06
                                                 └─填充6个0x06

7. 校验位 (CRC)

  • 长度: 2字节
  • 算法: CRC16-KERMIT
  • 校验范围: 包头 ~ 数据块(不包括校验位本身)
  • 字节序: 大端序(Big-Endian)

CRC计算范围

┌─────────────────────────────────────────┐
│ 包头 │ 包类型 │ 包序号 │ ... │ 数据块 │ CRC │
└─────────────────────────────────────────┘
  └──────── 参与CRC计算 ──────────┘  └─校验值─┘

CRC16-KERMIT参数

c
// CRC16-KERMIT参数
Polynomial: 0x1021
Initial Value: 0x0000
Input Reflected: Yes
Output Reflected: Yes
Final XOR: 0x0000

完整数据包示例

明文请求包示例

请求: 获取设备状态 (命令0x3040)

┌────────────────────────────────────────────────────────────────┐
│ EF 01 EE 02 │ 01 │ 00 01 │ 10 │ 00 04 00 04 │ 30 40 00 00 │ CRC │
└────────────────────────────────────────────────────────────────┘
    包头      │类型│ 序号  │标识│  数据长度   │  数据块   │校验位│
   (4字节)    │请求│  1    │明文│   4/4      │ 命令+参数 │      │

字段解析:

c
包头:     0xEF01EE02  // 固定值
包类型:   0x01        // 请求包
包序号:   0x0001      // 第1个包
包标识:   0x10        // 版本1, 明文传输
数据长度: 0x00040004  // 加密后4字节, 原始4字节
数据块:   0x30400000  // 命令0x3040 + 2字节参数
校验位:   [CRC16]     // 根据前面所有字节计算

数据类型定义

数据块中使用的基本数据类型:

类型长度字节序说明
整型(uN)N字节大端序如u1=1字节, u2=2字节, u4=4字节
字符串(定长)固定GBK编码C风格字符串,以\0结尾,不足部分用\0填充
字符串(变长)变长GBK编码C风格字符串,以\0结尾
二进制变长-原始字节数据,长度由其他字段指定

整型示例

c
// u1: 1字节整数
uint8_t value_u1 = 0x42;

// u2: 2字节整数 (大端序)
uint16_t value_u2 = 0x1234;
uint8_t bytes[2] = {0x12, 0x34};  // 传输时的字节顺序

// u4: 4字节整数 (大端序)
uint32_t value_u4 = 0x12345678;
uint8_t bytes[4] = {0x12, 0x34, 0x56, 0x78};

字符串示例

c
// 定长字符串(16字节)
char username[16] = "admin";
// 实际数据: "admin\0\0\0\0\0\0\0\0\0\0\0"
//           (5字节数据 + 1字节\0 + 10字节填充\0)

// 变长字符串
char device_name[] = "智能门锁\0";  // GBK编码
// 实际数据: {0xD6, 0xC7, 0xC4, 0xDC, 0xC3, 0xC5, 0xCB, 0xF8, 0x00}

重要规则

包序号匹配

  • 应答包的包序号必须与请求包相同
  • 用于匹配请求和应答,防止数据错乱
  • 超时未收到应答时,可使用相同序号重发请求

鑫泓佳智能硬件通信协议文档