跳转至

Hello ReadWrite

读写交互 — BLE GATT Read/Write Request

前置阅读:Hello BLEHello Notify

学习目标

  • 理解 BLE 中 Notify(Peripheral 主动推)和 Read/Write(Central 主动读/写)的本质区别
  • 掌握 Peripheral 端处理 Central 发来的 Read/Write Request
  • 掌握 Central 端 gattc_read/write 的使用
  • 理解 Write With Response 和 Write Without Response 的区别
  • 理解 Characteristic Properties 对读写操作的实际约束

规格与功能

在 hello-notify 的基础上,Central 主动读一个 Characteristic(设备名称),写一个 Characteristic(配置参数)。

规格项 说明
Characteristic 1 UUID 0x2A00, Property: READ, 值 = "BLE Device"
Characteristic 2 UUID 0x2A01, Property: WRITE, 值 = 设备配置参数
读操作 Central Read → Peripheral 返回设备名称
写操作 Central Write → Peripheral 校验 → 更新本地配置 → 确认

基本概念

三种交互模式

模式 方向 发起方 Peripheral 角色 Central 角色
Notify Peripheral → Central Peripheral 推送数据 notify_cb 接收
Read Peripheral → Central Central 返回数据 发起读 + 接收结果
Write Central → Peripheral Central 接收数据 + 确认 发起写 + 接收确认

SLE 中也有 Read/Write,但 Write 不区分 With Response / Without Response。这是 BLE 特有概念。

Write With Response vs Without Response

With Response Without Response
可靠性 Central 收到 Peripheral 确认 不确认
速度 较慢(等确认往返) 较快
适用 配置参数(必须确认写入成功) 高频数据流(丢一帧无所谓)
Characteristic Property CHAR_PROPERTY_WRITE CHAR_PROPERTY_WRITE_NO_RESPONSE

通信流程

sequenceDiagram
    participant C as Central
    participant P as Peripheral

    Note over C,P: 已连接、已发现服务

    C->>P: Read Request (char_uuid = 0x2A00)
    P-->>C: Read Response: "BLE Device"

    C->>P: Write Request (char_uuid = 0x2A01, timeout = 5000)
    P->>P: 校验数据合法性
    P-->>C: Write Response: SUCCESS

涉及 API

API 谁调用 用途
gattc_read() Central 发起读请求
gattc_write() Central 发起写请求
gatts_register_callbacks() Peripheral 注册回调(含 read/write handler)

案例说明

Central 连接后,先读取设备名称(Read),再修改配置参数(Write)。

案例操作指导

Central 串口输出:

[ble central] read device name: BLE Device
[ble central] write config: interval=2000ms
[ble central] write confirmed: SUCCESS

关键配置

  • Characteristic 1:CHAR_PROPERTY_READ(设备名称,只读)
  • Characteristic 2:CHAR_PROPERTY_WRITE(配置参数,可写)
  • Write 类型:WRITE_TYPE_DEFAULT(带响应——配置参数需要确认)

代码详解

Peripheral 端 Read Handler

static void read_request_cb(uint16_t conn_id, uint16_t char_handle)
{
    if (char_handle == g_device_name_handle) {
        // 返回设备名称
        char *device_name = "BLE Device";
        gatts_send_response(conn_id, char_handle,
                                      (uint8_t *)device_name, strlen(device_name));
    }
}

Peripheral 端 Write Handler

static void write_request_cb(uint16_t conn_id, uint16_t char_handle,
                              uint8_t *data, uint16_t len)
{
    if (char_handle == g_config_handle) {
        uint16_t new_value = *(uint16_t *)data;

        if (new_value < 100 || new_value > 60000) {
            // 校验失败 → 返回错误
            gatts_send_error(conn_id, char_handle, ERR_INVALID_VALUE);
            return;
        }

        g_config_value = new_value;
        gatts_send_response(conn_id, char_handle, NULL, 0);
        printf("[ble peripheral] config updated: %d\n", new_value);
    }
}

Central 端发起读写

// 读设备名称
gattc_read(g_conn_id, g_device_name_handle);

// 读结果回调
static void read_result_cb(uint16_t conn_id, uint16_t char_handle,
                            uint8_t *data, uint16_t len, uint8_t status)
{
    if (status == GATT_SUCCESS) {
        printf("[ble central] device name: %.*s\n", len, data);
    }
}

// 写配置参数
uint16_t new_interval = 2000;
gattc_write(g_conn_id, g_config_handle,
                     (uint8_t *)&new_interval, sizeof(new_interval),
                     WRITE_TYPE_DEFAULT);  // 带响应

// 写确认回调
static void write_confirm_cb(uint16_t conn_id, uint16_t char_handle, uint8_t status)
{
    if (status == GATT_SUCCESS) {
        printf("[ble central] write confirmed: SUCCESS\n");
    }
}