Zephyr 中 BT_GATT_SERVICE_DEFINE 使用详解

目录

概述

[1 BT_GATT_SERVICE_DEFINE 的定义](#1 BT_GATT_SERVICE_DEFINE 的定义)

[1.1 宏定义说明](#1.1 宏定义说明)

[1.2 核心属性宏详解](#1.2 核心属性宏详解)

[2 使用示例](#2 使用示例)

[2.1 基本服务定义](#2.1 基本服务定义)

[2.2 带通知功能的温度服务](#2.2 带通知功能的温度服务)

[2.3 多特征复合服务](#2.3 多特征复合服务)

[3 高级用法介绍](#3 高级用法介绍)

[3.1 动态特征值更新](#3.1 动态特征值更新)

[3.2 安全连接处理](#3.2 安全连接处理)

[3.3 服务发现响应](#3.3 服务发现响应)

[3.4 自定义属性](#3.4 自定义属性)

[3.5 参考范例](#3.5 参考范例)

[3.5.1 服务组织结构](#3.5.1 服务组织结构)

[3.5.2 功耗优化](#3.5.2 功耗优化)

[3.5.3 错误处理](#3.5.3 错误处理)

[4 常见问题解决](#4 常见问题解决)

[5 配置选项 (prj.conf)](#5 配置选项 (prj.conf))


概述

BT_GATT_SERVICE_DEFINE 是 Zephyr 蓝牙协议栈中用于定义和注册 GATT 服务 的核心宏。它允许开发者以声明式的方式创建完整的 GATT 服务结构,包括服务本身、特征、描述符以及相关回调函数。该宏是构建 Zephyr 蓝牙服务的基石,通过合理组织服务结构、实现高效回调函数和优化资源配置,可以创建稳定可靠且功能丰富的 GATT 服务。

1 BT_GATT_SERVICE_DEFINE 的定义

1.1 宏定义说明

1) 宏定义原型

cpp 复制代码
BT_GATT_SERVICE_DEFINE(_name, _attrs...)

2) 参数说明

参数 说明
_name 服务名称(用于在代码中引用)
_attrs 服务属性列表(服务声明、特征、描述符等)

3) 核心功能

  1. 服务声明:定义服务及其 UUID

  2. 特征定义:包含特征值、属性、权限和回调

  3. 描述符添加:如 CCCD(客户端特征配置描述符)

  4. 自动注册:服务在蓝牙协议栈初始化时自动注册

  5. 内存管理:自动分配服务所需的内存空间

1.2 核心属性宏详解

1) 服务声明宏

cpp 复制代码
BT_GATT_PRIMARY_SERVICE(&service_uuid)
参数 说明
service_uuid 服务UUID (16位、32位或128位)

2) 特征声明宏

cpp 复制代码
BT_GATT_CHARACTERISTIC(&char_uuid, properties, perm, read_func, write_func, user_data)
参数 说明
char_uuid 特征UUID
properties 特征属性 (BT_GATT_CHRC_READ, WRITE, NOTIFY, INDICATE 等)
perm 访问权限 (BT_GATT_PERM_READ, WRITE, ENCRYPT 等)
read_func 读回调函数 (NULL 表示直接访问)
write_func 写回调函数 (NULL 表示直接写入)
user_data 指向特征值的指针

3) 常用描述符宏

功能 参数
BT_GATT_CCC(cfg_changed, perm) 客户端特征配置描述符 cfg_changed: CCC变更回调 perm: 访问权限
BT_GATT_CUD(description, perm) 特征用户描述描述符 description: 描述字符串 perm: 访问权限
BT_GATT_CPF(format) 特征呈现格式描述符 format: 数据格式结构体
BT_GATT_DESCRIPTOR(uuid, perm, read, write, value) 通用描述符 完整参数控制

2 使用示例

2.1 基本服务定义

cpp 复制代码
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

// 定义自定义UUID
#define BT_UUID_CUSTOM_SERVICE_VAL \
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)

#define BT_UUID_CUSTOM_CHAR_VAL \
    BT_UUID_128_ENCODE(0x87654321, 0x4321, 0x8765, 0x4321, 0x0fedcba98765)

static const struct bt_uuid_128 custom_service_uuid = 
    BT_UUID_INIT_128(BT_UUID_CUSTOM_SERVICE_VAL);

static const struct bt_uuid_128 custom_char_uuid = 
    BT_UUID_INIT_128(BT_UUID_CUSTOM_CHAR_VAL);

// 特征值变量
static uint8_t char_value = 0;

// 读回调函数
static ssize_t read_char_value(struct bt_conn *conn,
                              const struct bt_gatt_attr *attr,
                              void *buf, uint16_t len, uint16_t offset)
{
    const uint8_t *value = attr->user_data;
    return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(*value));
}

// 写回调函数
static ssize_t write_char_value(struct bt_conn *conn,
                               const struct bt_gatt_attr *attr,
                               const void *buf, uint16_t len, uint16_t offset,
                               uint8_t flags)
{
    uint8_t *value = attr->user_data;
    
    if (offset + len > sizeof(*value)) {
        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
    }
    
    memcpy(value + offset, buf, len);
    return len;
}

// 定义服务
BT_GATT_SERVICE_DEFINE(custom_service,
    // 服务声明
    BT_GATT_PRIMARY_SERVICE(&custom_service_uuid),
    
    // 特征声明
    BT_GATT_CHARACTERISTIC(&custom_char_uuid.uuid,
                           BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
                           BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
                           read_char_value, write_char_value, &char_value),
    
    // 客户端特征配置描述符(CCCD)
    BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    
    // 特征用户描述描述符
    BT_GATT_CUD("Custom Characteristic", BT_GATT_PERM_READ)
);

2.2 带通知功能的温度服务

cpp 复制代码
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

// 使用标准UUID
static struct bt_uuid_16 temp_service_uuid = BT_UUID_INIT_16(0x1809); // 健康温度计
static struct bt_uuid_16 temp_meas_uuid = BT_UUID_INIT_16(0x2A1C);    // 温度测量

// 温度数据
static int32_t temperature = 2500; // 25.00°C
static bool notify_enabled = false;

// CCCD变更回调
static void temp_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    notify_enabled = (value == BT_GATT_CCC_NOTIFY);
}

// 温度读取回调
static ssize_t read_temperature(struct bt_conn *conn,
                               const struct bt_gatt_attr *attr,
                               void *buf, uint16_t len, uint16_t offset)
{
    const int32_t *value = attr->user_data;
    return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(*value));
}

// 温度服务定义
BT_GATT_SERVICE_DEFINE(temp_service,
    BT_GATT_PRIMARY_SERVICE(&temp_service_uuid),
    
    // 温度测量特征
    BT_GATT_CHARACTERISTIC(&temp_meas_uuid.uuid,
                           BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_READ,
                           read_temperature, NULL, &temperature),
    
    // CCCD配置
    BT_GATT_CCC(temp_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
);

// 更新温度值并通知
void update_temperature(int32_t new_temp)
{
    temperature = new_temp;
    
    if (notify_enabled) {
        bt_gatt_notify(NULL, &temp_service.attrs[2], &temperature, sizeof(temperature));
    }
}

2.3 多特征复合服务

cpp 复制代码
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

// 定义UUID
static struct bt_uuid_128 multi_service_uuid = 
    BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x00000001,0x0000,0x1000,0x8000,0x00805F9B34FB));

static struct bt_uuid_128 char1_uuid = 
    BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x00000002,0x0000,0x1000,0x8000,0x00805F9B34FB));

static struct bt_uuid_128 char2_uuid = 
    BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x00000003,0x0000,0x1000,0x8000,0x00805F9B34FB));

// 特征值
static uint8_t char1_value = 0;
static uint16_t char2_value = 0;

// 服务定义
BT_GATT_SERVICE_DEFINE(multi_feature_service,
    BT_GATT_PRIMARY_SERVICE(&multi_service_uuid),
    
    // 特征1
    BT_GATT_CHARACTERISTIC(&char1_uuid.uuid,
                           BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
                           BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
                           NULL, NULL, &char1_value),
    
    // 特征2
    BT_GATT_CHARACTERISTIC(&char2_uuid.uuid,
                           BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_READ,
                           NULL, NULL, &char2_value),
    
    BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    
    // 特征描述符
    BT_GATT_DESCRIPTOR(&bt_uuid_description, 
                       BT_GATT_PERM_READ, 
                       bt_gatt_attr_read_description, 
                       NULL, "Feature 2"),
    
    // 自定义描述符
    BT_GATT_DESCRIPTOR(BT_UUID_CUSTOM_DESCRIPTOR,
                       BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
                       custom_descriptor_read, custom_descriptor_write,
                       NULL)
);

3 高级用法介绍

3.1 动态特征值更新

cpp 复制代码
// 在服务定义中
static uint8_t dynamic_value[20];
BT_GATT_CHARACTERISTIC(&dynamic_char_uuid, 
                      BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
                      BT_GATT_PERM_READ, 
                      read_dynamic_value, NULL, NULL)

// 读回调函数
static ssize_t read_dynamic_value(struct bt_conn *conn,
                                 const struct bt_gatt_attr *attr,
                                 void *buf, uint16_t len, uint16_t offset)
{
    // 动态生成值
    generate_dynamic_data(dynamic_value, sizeof(dynamic_value));
    
    return bt_gatt_attr_read(conn, attr, buf, len, offset, 
                            dynamic_value, sizeof(dynamic_value));
}

// 通知所有连接的客户端
void notify_dynamic_value(void)
{
    bt_gatt_notify(NULL, &service.attrs[2], dynamic_value, sizeof(dynamic_value));
}

3.2 安全连接处理

cpp 复制代码
BT_GATT_SERVICE_DEFINE(secure_service,
    BT_GATT_PRIMARY_SERVICE(&secure_service_uuid),
    
    // 需要加密的特征
    BT_GATT_CHARACTERISTIC(&secure_char_uuid,
                           BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
                           BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT,
                           read_secure_data, write_secure_data, &secure_data),
    
    // 需要MITM保护的描述符
    BT_GATT_DESCRIPTOR(&bt_uuid_secure_desc,
                       BT_GATT_PERM_READ_AUTHEN | BT_GATT_PERM_WRITE_AUTHEN,
                       read_auth_desc, write_auth_desc, NULL)
);

// 写回调中的安全验证
static ssize_t write_secure_data(struct bt_conn *conn,
                                const struct bt_gatt_attr *attr,
                                const void *buf, uint16_t len, uint16_t offset,
                                uint8_t flags)
{
    // 验证连接安全级别
    if (bt_conn_get_security(conn) < BT_SECURITY_L3) {
        return BT_GATT_ERR(BT_ATT_ERR_AUTHENTICATION);
    }
    
    // 处理数据写入
    memcpy(attr->user_data, buf, len);
    return len;
}

3.3 服务发现响应

cpp 复制代码
// 在服务定义中添加包含服务
static struct bt_uuid_16 included_service_uuid = BT_UUID_INIT_16(0x180A);

BT_GATT_SERVICE_DEFINE(main_service,
    BT_GATT_PRIMARY_SERVICE(&main_service_uuid),
    
    // 包含设备信息服务
    BT_GATT_INCLUDE_SERVICE(&device_info_service.attrs),
    
    // 主服务特征...
);

// 设备信息服务定义
BT_GATT_SERVICE_DEFINE(device_info_service,
    BT_GATT_PRIMARY_SERVICE(&bt_uuid_device_information),
    
    BT_GATT_CHARACTERISTIC(&bt_uuid_model_number,
                           BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ,
                           read_model_number, NULL, "Zephyr-ModelX"),
    
    BT_GATT_CHARACTERISTIC(&bt_uuid_firmware_rev,
                           BT_GATT_CHRC_READ,
                           BT_GATT_PERM_READ,
                           read_fw_version, NULL, "1.2.3")
);

3.4 自定义属性

cpp 复制代码
// 自定义属性结构
static struct bt_gatt_attr custom_attrs[] = {
    BT_GATT_PRIMARY_SERVICE(&custom_service_uuid),
    BT_GATT_CHARACTERISTIC(&custom_char_uuid, ...),
    BT_GATT_DESCRIPTOR(...)
};

// 使用自定义属性定义服务
BT_GATT_SERVICE_DEFINE(custom_attr_service,
    custom_attrs[0],
    custom_attrs[1],
    custom_attrs[2]
);

// 动态添加特征
int add_dynamic_characteristic(void)
{
    static struct bt_uuid_128 dyn_char_uuid = BT_UUID_INIT_128(...);
    static uint8_t dyn_value = 0;
    
    struct bt_gatt_attr dyn_attr = BT_GATT_CHARACTERISTIC(&dyn_char_uuid, ...);
    
    // 动态添加属性到服务
    return bt_gatt_service_add_attr(&custom_attr_service, &dyn_attr);
}

3.5 参考范例

3.5.1 服务组织结构

cpp 复制代码
// 推荐的服务文件结构

/* custom_service.h */
#pragma once
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

#ifdef __cplusplus
extern "C" {
#endif

// 服务UUID声明
extern const struct bt_uuid_128 custom_service_uuid;
extern const struct bt_uuid_128 custom_char1_uuid;
extern const struct bt_uuid_128 custom_char2_uuid;

// 服务API
void custom_service_init(void);
void custom_service_update_value(uint8_t new_value);

#ifdef __cplusplus
}
#endif

/* custom_service.c */
#include "custom_service.h"

// UUID定义
const struct bt_uuid_128 custom_service_uuid = ...;
const struct bt_uuid_128 custom_char1_uuid = ...;
const struct bt_uuid_128 custom_char2_uuid = ...;

// 特征值
static uint8_t char1_value = 0;
static uint16_t char2_value = 0;

// 服务实现
BT_GATT_SERVICE_DEFINE(custom_svc,
    BT_GATT_PRIMARY_SERVICE(&custom_service_uuid),
    // 特征定义...
);

void custom_service_init(void)
{
    // 初始化逻辑
}

void custom_service_update_value(uint8_t new_value)
{
    char1_value = new_value;
    // 通知逻辑...
}

3.5.2 功耗优化

cpp 复制代码
// 在服务定义中使用通知抑制
static bool notifications_active = false;

BT_GATT_SERVICE_DEFINE(power_optimized_service,
    BT_GATT_PRIMARY_SERVICE(&power_service_uuid),
    
    BT_GATT_CHARACTERISTIC(&power_char_uuid,
                           BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
                           BT_GATT_PERM_READ,
                           read_power_value, NULL, &power_value),
    
    BT_GATT_CCC(power_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
);

// CCC回调
static void power_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    notifications_active = (value & BT_GATT_CCC_NOTIFY);
    
    if (notifications_active) {
        // 启用高频率更新
        start_high_freq_sampling();
    } else {
        // 禁用高频率更新
        stop_high_freq_sampling();
    }
}

// 数据更新函数
void update_power_value(uint16_t value)
{
    if (!notifications_active) return;
    
    power_value = value;
    bt_gatt_notify(NULL, &power_optimized_service.attrs[2], &power_value, sizeof(power_value));
}

3.5.3 错误处理

cpp 复制代码
// 特征读回调中的错误处理
static ssize_t read_with_validation(struct bt_conn *conn,
                                   const struct bt_gatt_attr *attr,
                                   void *buf, uint16_t len, uint16_t offset)
{
    if (!is_data_valid()) {
        return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
    }
    
    if (offset > MAX_VALID_OFFSET) {
        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
    }
    
    return bt_gatt_attr_read(conn, attr, buf, len, offset, 
                            attr->user_data, DATA_SIZE);
}

// 写回调中的错误处理
static ssize_t write_with_validation(struct bt_conn *conn,
                                    const struct bt_gatt_attr *attr,
                                    const void *buf, uint16_t len, uint16_t offset,
                                    uint8_t flags)
{
    if (offset + len > MAX_DATA_SIZE) {
        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
    }
    
    if (!validate_input(buf, len)) {
        return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
    }
    
    memcpy(attr->user_data + offset, buf, len);
    return len;
}

4 常见问题解决

1) 服务未显示

  • 检查配置 :确保 prj.conf 包含 CONFIG_BT=yCONFIG_BT_GATT=y

  • 验证UUID:使用蓝牙调试工具检查服务UUID是否正确

  • 检查权限:确保客户端有足够的安全权限

2) 特征不可写

  • 验证属性 :特征必须包含 BT_GATT_CHRC_WRITE 属性

  • 检查权限 :特征权限必须包含 BT_GATT_PERM_WRITE

  • 安全级别 :可能需要加密连接 (添加 BT_GATT_PERM_WRITE_ENCRYPT)

3) 通知不工作

  1. 启用通知:客户端必须写入CCCD启用通知

  2. 检查属性 :特征必须包含 BT_GATT_CHRC_NOTIFY

  3. 连接验证:确保有活动的蓝牙连接

  4. 资源限制 :增加 CONFIG_BT_CONN_TX_MAX

4) 内存不足

  • 增加堆大小 :在 prj.conf 中设置 CONFIG_BT_BUF_CMD_TX_COUNT=10

  • 限制连接数 :设置 CONFIG_BT_MAX_CONN=3 (默认值)

  • 优化特征:减少特征数量和大小

5 配置选项 (prj.conf)

配置的参数如下:

bash 复制代码
# 基础蓝牙配置
CONFIG_BT=y
CONFIG_BT_GATT=y

# 服务配置
CONFIG_BT_DEVICE_NAME="My GATT Device"
CONFIG_BT_DEVICE_APPEARANCE=384 # 通用传感器

# 安全配置
CONFIG_BT_SMP=y
CONFIG_BT_PRIVACY=y
CONFIG_BT_GATT_AUTO_SEC_REQ=y

# 性能优化
CONFIG_BT_BUF_ACL_RX_SIZE=255
CONFIG_BT_BUF_ACL_TX_SIZE=255
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_ATT_PREPARE_COUNT=5

# 调试支持
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_DEBUG_GATT=y