原理与用法
(G)ATT Server 可以通过两种方式将特性(Characteristics)的数值传递到 Client:Client 订阅 (Server 主动发送 Indication 或者 Notification)和 Client 主动读取。
Client 主动读取分为“静态”与“动态”两种情况:
-
静态数值存储于 ATT 数据库内,协议栈直接提取数值传递到 Client
-
对于动态数值,协议栈每次读取数值时会两次调用回调函数(
att_read_callback
):第一次数据指针为空,用来获取数值长度; 第二次数据指针不为空,回调函数此时将数据写入数据指针指向的内存。
这里动态数值的回调是一种同步读取。对于需要消耗较多时间才能读取数据的情况,比如初始化传感器并等待数据稳定, 同步读取的方法并不合适。
SDK 6.1 里新增了一种延迟读取 (Deferred read) 的方法,步骤如下:
-
回调函数
att_read_callback
在第一次被调用(数据指针为空)时返回ATT_DEFERRED_READ
; -
app 开始获取数据;
-
数据就绪之后,调用
att_server_deferred_read_response
发送数据。
示例
GATT Relay 首先克隆一个指定设备(设备 A)的广播数据,然后连接到该设备,克隆它的 GATT Profile,再发送克隆得到的广播数据等待连接。 用其它设备(设备 B)连接到 GATT Relay 后,GATT Relay 会把设备 B 里的 GATT Client 发起的所有请求转发到设备 A, 再将响应转发回设备 B。
这个例子里回调函数使用延迟读取方式,待 GATT Client 从设备 A 获得数据后,调用 att_server_deferred_read_response
将结果传递到设备 B。
void gatt_read_callback(uint8_t packet_type, uint16_t _, const uint8_t *packet, uint16_t size)
{
switch (packet[0])
{
case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
{
uint16_t value_size;
const gatt_event_value_packet_t *value =
gatt_event_characteristic_value_query_result_parse(packet, size, &value_size);
att_server_deferred_read_response(handle_to_master,
handle_map_from_slave[value->handle],
value->value, value_size);
}
break;
//...
}
}
static uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset,
uint8_t * buffer, uint16_t buffer_size)
{
if (buffer == NULL)
{
uint16_t handle = handle_map_to_slave[att_handle];
gatt_client_read_value_of_characteristic_using_value_handle(gatt_read_callback,
handle_to_slave,
handle);
return ATT_DEFERRED_READ;
}
// ...
}