目录
概述
本文主要介绍Zephyr OS下GATT的服务端(Server)接口 ,GATT(通用属性配置文件)是蓝牙低功耗(BLE)协议中的核心组件,定义了服务端与客户端之间的数据交互架构。其采用层级结构组织服务(Service)、特性(Characteristic)、描述符(Descriptor)等元素,支持读取、写入、通知等多种交互模式。服务端开发涉及静态/动态服务注册、特性值操作、安全权限设置等关键功能,通过回调函数处理客户端请求。示例展示了设备信息服务和动态服务的实现方法,典型应用包括电池状态监测等场景。GATT架构为BLE设备提供了标准化的数据交换机制,支持安全通信和实时数据传输。
1 GATT 服务架构
GATT (Generic Attribute Profile) 是蓝牙低功耗(BLE)协议栈中的关键组成部分,定义了服务(Server)和客户端(Client)之间数据交换的标准架构。
1.1 GATT 核心架构组成
1)层级结构
GATT Profile
├── Services (服务)
│ ├── Characteristics (特性)
│ │ ├── Value (值)
│ │ ├── Descriptors (描述符)
│ │ │ └── Client Characteristic Configuration (CCC)
│ │ └── Properties (属性)
│ └── Includes (包含服务)
└── Attributes (属性)
2) 关键组件说明
组件 | 说明 | 示例UUID |
---|---|---|
服务(Service) | 功能逻辑集合 | 0x180A (设备信息服务) |
特性(Characteristic) | 服务中的数据项 | 0x2A29 (厂商名称) |
描述符(Descriptor) | 特性的元数据 | 0x2902 (CCC描述符) |
属性(Attribute) | 数据库基本单元 | 由协议栈管理 |
1.2 服务类型
类型 | 特点 | 使用场景 |
---|---|---|
主服务(Primary) | 设备核心功能 | 电池服务、设备信息 |
次要服务(Secondary) | 辅助功能 | 引用服务组件 |
包含服务(Include) | 服务引用 | 组合复杂功能 |
1.3 数据交互模式
Server和Client通信方式对比
方式 | 特点 | 适用场景 |
---|---|---|
读取(Read) | 客户端主动请求 | 获取静态配置 |
写入(Write) | 客户端修改值 | 发送控制命令 |
通知(Notify) | 服务端主动推送 | 实时传感器数据 |
指示(Indicate) | 需确认的推送 | 关键状态变更 |
1.4 安全架构设计
权限标志 | 说明 | 安全要求 |
---|---|---|
BT_GATT_PERM_READ | 允许读取 | 无 |
BT_GATT_PERM_READ_ENCRYPT | 需加密读取 | 加密连接 |
BT_GATT_PERM_READ_AUTHEN | 需认证读取 | 已配对设备 |
BT_GATT_PERM_WRITE | 允许写入 | 无 |
BT_GATT_PERM_WRITE_ENCRYPT | 需加密写入 | 加密连接 |
2 GATT 服务端(Server)接口
2.1 服务定义与注册
2.1.1 静态服务定义宏
/* 定义完整的GATT服务(编译时静态注册)*/
BT_GATT_SERVICE_DEFINE(
service_name, // 服务变量名
BT_GATT_PRIMARY_SERVICE(UUID), // 主服务声明
BT_GATT_CHARACTERISTIC( // 特性定义
UUID,
properties,
permissions,
read_cb, write_cb, value
),
BT_GATT_CCC(ccc_cfg_changed, permissions), // 客户端特性配置
// 可添加更多特性或描述符...
);
2.1.2 动态服务管理
/* 动态分配服务结构 */
struct bt_gatt_service *service = bt_gatt_service_alloc(num_attrs);
/* 添加特性到动态服务 */
int bt_gatt_service_add_characteristic(
struct bt_gatt_service *svc,
struct bt_gatt_attr *attr
);
/* 注册动态服务 */
int bt_gatt_service_register(struct bt_gatt_service *svc);
/* 注销动态服务 */
int bt_gatt_service_unregister(struct bt_gatt_service *svc);
2.2 特性与描述符操作
2.2.1 特性值操作
/* 通知特性值变化 */
int bt_gatt_notify(
struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *data,
uint16_t len
);
/* 指示特性值变化(需确认)*/
int bt_gatt_indicate(
struct bt_conn *conn,
struct bt_gatt_indicate_params *params
);
/* 读取特性值辅助函数 */
ssize_t bt_gatt_attr_read(
struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf,
uint16_t len,
uint16_t offset,
const void *value,
uint16_t value_len
);
/* 写入特性值辅助函数 */
ssize_t bt_gatt_attr_write(
struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *buf,
uint16_t len,
uint16_t offset,
uint8_t flags
);
2.2.2 描述符操作
/* 客户端特性配置描述符(CCC) */
#define BT_GATT_CCC(_changed, _perm) \
BT_GATT_DESCRIPTOR(BT_UUID_GATT_CCC, _perm, NULL, NULL, _changed)
/* 服务变更描述符 */
#define BT_GATT_SERVICE_CHANGED \
BT_GATT_DESCRIPTOR(BT_UUID_GATT_SC, BT_GATT_PERM_READ, NULL, NULL, NULL)
2.3 回调函数接口
/* 读取回调函数类型 */
typedef ssize_t (*bt_gatt_attr_read_func_t)(
struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf,
uint16_t len,
uint16_t offset
);
/* 写入回调函数类型 */
typedef ssize_t (*bt_gatt_attr_write_func_t)(
struct bt_conn *conn,
const struct bt_gatt_attr *attr,
const void *buf,
uint16_t len,
uint16_t offset,
uint8_t flags
);
/* CCC配置变更回调 */
typedef void (*bt_gatt_ccc_cfg_changed_t)(
const struct bt_gatt_attr *attr,
uint16_t value
);
2.4 服务端安全控制
2.4.1 权限设置
/* 常用权限组合 */
#define BT_GATT_PERM_READ BIT(0)
#define BT_GATT_PERM_WRITE BIT(1)
#define BT_GATT_PERM_READ_ENCRYPT (BT_GATT_PERM_READ | BT_GATT_PERM_ENCRYPT)
#define BT_GATT_PERM_WRITE_ENCRYPT (BT_GATT_PERM_WRITE | BT_GATT_PERM_ENCRYPT)
#define BT_GATT_PERM_READ_AUTHEN (BT_GATT_PERM_READ | BT_GATT_PERM_AUTHEN)
#define BT_GATT_PERM_WRITE_AUTHEN (BT_GATT_PERM_WRITE | BT_GATT_PERM_AUTHEN)
2.4.2 安全级别检查
/* 检查连接安全级别 */
int bt_gatt_check_perm(
struct bt_conn *conn,
const struct bt_gatt_attr *attr,
uint8_t mask
);
2.5 高级功能
2.5.1 服务变更指示
/* 标记服务变更范围 */
int bt_gatt_service_changed(struct bt_conn *conn,
uint16_t start_handle,
uint16_t end_handle);
2.5.2 数据库浏览
/* 遍历GATT数据库 */
void bt_gatt_foreach_attr(
uint16_t start_handle,
uint16_t end_handle,
bt_gatt_attr_func_t func,
void *user_data
);
3 服务端示例
3.1 设备信息服务实现
#include <bluetooth/bluetooth.h>
#include <bluetooth/gatt.h>
#include <bluetooth/uuid.h>
static uint8_t device_name[] = "Zephyr Server";
static ssize_t read_device_name(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
return bt_gatt_attr_read(conn, attr, buf, len, offset,
device_name, sizeof(device_name));
}
static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
ARG_UNUSED(attr);
printk("CCC Config Changed: %d\n", value);
}
BT_GATT_SERVICE_DEFINE(device_info_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_DEVICE_INFORMATION),
BT_GATT_CHARACTERISTIC(BT_UUID_DEVICE_NAME,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_device_name, NULL, device_name),
BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
);
void notify_device_name(struct bt_conn *conn)
{
bt_gatt_notify(conn, &device_info_svc.attrs[2], device_name, sizeof(device_name));
}
3.2 动态服务注册示例
static uint8_t dynamic_value[20];
static ssize_t read_dynamic_value(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
return bt_gatt_attr_read(conn, attr, buf, len, offset,
dynamic_value, sizeof(dynamic_value));
}
static struct bt_gatt_attr dynamic_attrs[] = {
BT_GATT_PRIMARY_SERVICE(BT_UUID_DIS),
BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MODEL_NUMBER,
BT_GATT_CHRC_READ,
BT_GATT_PERM_READ,
read_dynamic_value, NULL, NULL),
};
static struct bt_gatt_service dynamic_service = {
.attrs = dynamic_attrs,
.attr_count = ARRAY_SIZE(dynamic_attrs),
};
void register_dynamic_service(void)
{
int err = bt_gatt_service_register(&dynamic_service);
if (err) {
printk("Dynamic service register failed (err %d)\n", err);
}
}
3.3 Zephyr中的典型实现方式
static uint8_t battery_level = 50;
static ssize_t read_battery(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
return bt_gatt_attr_read(conn, attr, buf, len, offset,
&battery_level, sizeof(battery_level));
}
BT_GATT_SERVICE_DEFINE(battery_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_BAS),
BT_GATT_CHARACTERISTIC(BT_UUID_BAS_BATTERY_LEVEL,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_battery, NULL, &battery_level),
BT_GATT_CCC(battery_ccc_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
);