ESP32蓝牙开发笔记(十五)

在 ESP32 的 BLE 开发中,esp_ble_gatts_add_char_descr 是用于向特征(Characteristic)中添加描述符(Descriptor)的核心函数。描述符用于提供特征的额外信息(如客户端特征配置、用户描述等)。以下是该函数的详细说明、参数解析及示例代码:


函数原型

cpp 复制代码
esp_err_t esp_ble_gatts_add_char_descr(
    uint16_t service_handle,          // 服务句柄
    esp_bt_uuid_t *descr_uuid,        // 描述符的 UUID
    esp_gatt_perm_t perm,              // 描述符的访问权限
    esp_attr_value_t *descr_val,       // 描述符的初始值(可选)
    esp_attr_control_t *control        // 描述符的属性控制(安全模式等)
);

参数详解

1. service_handle(服务句柄)
  • 来源 :由 esp_ble_gatts_create_service 或 esp_ble_gatts_add_service 创建服务后返回的句柄。
  • 作用:指定描述符所属的服务(实际属于服务中的某个特征)。
2. descr_uuid(描述符 UUID)
  • 类型 :esp_bt_uuid_t,描述符的标准或自定义 UUID。
  • 常用预定义值 :
    • CCCD(客户端特征配置描述符)​ :0x2902,用于启用通知(Notify)或指示(Indicate)。
    • 用户描述符 :0x2901,用于提供人类可读的特征描述。
    • 特征扩展属性 :0x2900,用于声明扩展属性。
3. perm(权限)
  • 类型 :esp_gatt_perm_t,定义客户端对描述符的访问权限。
  • 常用值 :
    • ESP_GATT_PERM_READ:允许读
    • ESP_GATT_PERM_WRITE:允许写
    • ESP_GATT_PERM_READ_ENCRYPTED:需要加密读
    • ESP_GATT_PERM_WRITE_ENCRYPTED:需要加密写
4. descr_val(初始值)
  • 类型 :esp_attr_value_t,可选参数。如果设为 NULL,描述符初始值为空。

  • 示例 :

    cpp 复制代码
    // CCCD 默认初始值为 0x0000(通知和指示均禁用)
    esp_attr_value_t descr_val = {
        .attr_max_len = 2,
        .attr_len = 2,
        .attr_value = {0x00, 0x00}
    };
5. control(属性控制)
  • 类型 :esp_attr_control_t,通常用于配置安全模式。如果不需要特殊配置,可设为 NULL。

  • 示例 :

    cpp 复制代码
    esp_attr_control_t control = {
        .auto_rsp = ESP_GATT_AUTO_RSP  // 自动响应读/写请求
    };

返回值

  • ESP_OK:描述符添加成功。
  • 其他错误码:失败(如无效句柄、内存不足等)。

示例代码

步骤 1:添加特征
cpp 复制代码
// 先添加特征(假设已创建服务)
uint16_t char_handle;
esp_ble_gatts_add_char(
    service_handle,
    &char_uuid,
    perm,
    property,
    NULL, NULL, &char_handle
);
步骤 2:添加 CCCD 描述符
cpp 复制代码
// 定义 CCCD 的 UUID(0x2902)
esp_bt_uuid_t cccd_uuid = {
    .len = ESP_UUID_LEN_16,
    .uuid = {.uuid16 = 0x2902}
};

// 描述符权限(允许读写)
esp_gatt_perm_t perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;

// 添加 CCCD 描述符
esp_err_t ret = esp_ble_gatts_add_char_descr(
    service_handle,
    &cccd_uuid,
    perm,
    NULL,   // 初始值为空(客户端首次读取会返回 0x0000)
    NULL    // 使用默认控制
);

if (ret != ESP_OK) {
    ESP_LOGE("GATTS", "添加描述符失败: %s", esp_err_to_name(ret));
}
步骤 3:处理客户端写入 CCCD 的事件

在 GATT 事件回调中处理客户端对 CCCD 的写入操作:

cpp 复制代码
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
    switch (event) {
        case ESP_GATTS_WRITE_EVT: {
            // 检查是否为 CCCD 描述符写入
            if (param->write.handle == descr_handle) {
                uint16_t cccd_value = *(uint16_t*)param->write.value;
                if (cccd_value & ESP_GATT_CLIENT_CHAR_CFG_NOTIFY) {
                    ESP_LOGI("GATTS", "客户端启用了通知");
                }
                if (cccd_value & ESP_GATT_CLIENT_CHAR_CFG_INDICATE) {
                    ESP_LOGI("GATTS", "客户端启用了指示");
                }
            }
            break;
        }
        // 其他事件处理...
    }
}

关键注意事项

  1. 描述符必须属于某个特征 :
    • 描述符必须添加到已存在的特征所属的服务中,且通常紧随特征添加之后调用。
  2. CCCD 的特殊性 :
    • CCCD 的 UUID 必须为 0x2902,且其值长度为 2 字节(0x0000 表示禁用,0x0001 启用通知,0x0002 启用指示)。
  3. 动态更新描述符值 :
    • 使用 esp_ble_gatts_set_attr_value 可动态更新描述符值。
  4. 权限匹配 :
    • 若描述符支持写操作(如 CCCD),perm 必须包含 ESP_GATT_PERM_WRITE。

错误排查

  • 无效句柄 :确保 service_handle 有效且属于已创建的服务。
  • UUID 错误 :CCCD 必须使用 0x2902,否则客户端无法识别。
  • 权限不足 :客户端尝试写入描述符时,若未配置 ESP_GATT_PERM_WRITE 会导致写入失败。

完整流程示意图

cpp 复制代码
创建服务 (esp_ble_gatts_create_service)
   |
   v
添加特征 (esp_ble_gatts_add_char)
   |
   v
添加描述符 (esp_ble_gatts_add_char_descr)
   |
   v
启动服务 (esp_ble_gatts_start_service)
   |
   v
处理读写事件 (ESP_GATTS_READ_EVT / WRITE_EVT)

通过 esp_ble_gatts_add_char_descr,可以为特征添加必要的描述符,实现更复杂的 BLE 交互逻辑(如通知、指示)。

相关推荐
qq_284274056 小时前
机械原理笔记:平面机构自由度计算(复合铰链、局部自由度、虚约束)与四杆机构入门(含考点)
笔记·学习·平面·自动化·制造
qq_284274057 小时前
数控铣床与加工中心笔记:铣刀与刀柄系统、G54试切对刀、镜像加工指令、孔加工工艺(钻扩铰镗)与固定循环G73/G83/G81/G76/G87/G84
笔记·学习·自动化·制造
Titan20248 小时前
MySQL访问个人学习笔记
笔记·学习·mysql
深圳老胡9 小时前
STM32CubeMX 生成 CMake 工程,用 VSCode 编译与调试的完整流程
笔记·stm32·单片机·代码规范
坤坤子吖9 小时前
C++智能指针:RAII、shared_ptr与内存泄漏
开发语言·c++·笔记·学习
乐橙开放平台10 小时前
智慧连锁客流检测和离岗检测怎么对接
大数据·人工智能·笔记·物联网·自动化·音视频·智能家居
零基础12310 小时前
FinalShell 使用教程:从安装到高效运维
运维·经验分享·笔记·finalshell
ACP广源盛1392462567310 小时前
Type‑C 扩展坞方案选型笔记|国产 DP1.4 转 HDMI2.0 桥接芯片 GSV2201S @ACP评估
c语言·开发语言·笔记·硬件架构·硬件工程·国产芯片
敲个大西瓜11 小时前
langchain笔记(一)
redis·笔记·langchain
带金箍的至尊宝11 小时前
系统架构设计师笔记 05:第2章硬件与软件基础,冯诺依曼结构怎么考
数据库·笔记·系统架构