一、背景
1.1 GATT協(xié)議
GATT(Generic Attributes Profile)的縮寫,中文是通用屬性協(xié)議,是已連接的低功耗藍(lán)牙設(shè)備之間進(jìn)行通信的協(xié)議。
一旦兩個(gè)設(shè)備建立起了連接,GATT 就開始起作用了,這也意味著,你必需完成前面的GAP協(xié)議。
GATT使用了 ATT(Attribute Protocol)協(xié)議,ATT 協(xié)議把 Service,Characteristic 對應(yīng)的數(shù)據(jù)保存在一個(gè)查找表中,查找表使用 16bit ID 作為每一項(xiàng)的索引。
GATT定義的多層數(shù)據(jù)結(jié)構(gòu)簡要概括起來就是 服務(wù)(Service) 可以包含多個(gè) 特征(Characteristic),每個(gè)特征包含 屬性(Properties) 和 值(Value),還可以包含多個(gè) 描述(Descriptor)。
1.2 屬性協(xié)議(ATT)
屬性協(xié)議層 負(fù)責(zé)數(shù)據(jù)檢索,允許一個(gè)設(shè)備暴露一些數(shù)據(jù)塊給其他設(shè)備,其他設(shè)備稱之為“屬性”。
在ATT環(huán)境中,展示屬性的設(shè)備稱之為服務(wù)器,與它配對的設(shè)備稱之為客戶端。鏈路層的主機(jī)從機(jī)和這里的服務(wù)器、客服端是兩種概念,主設(shè)備既可以是服務(wù)器,也可以是客戶端。從設(shè)備毅然。
1.3 GATT通信中角色
從GATT的角度來看,處于連接狀態(tài)時(shí)的兩個(gè)設(shè)備,它們各自充當(dāng)兩種角色中的一種:
服務(wù)端(Server)
包含被GATT客戶端讀取或?qū)懭氲奶卣鲾?shù)據(jù)的設(shè)備。
客戶端(Client)
從GATT服務(wù)器中讀取數(shù)據(jù)或向GATT服務(wù)器寫入數(shù)據(jù)的設(shè)備。
外圍設(shè)備(從機(jī))作為 GATT 服務(wù)端(Server),它維持了 ATT 的查找表以及 service 和 characteristic 的定義;
客戶端和服務(wù)器的GATT角色獨(dú)立于外圍設(shè)備和中央設(shè)備的GAP角色。外圍設(shè)備可以是GATT客戶端或GATT服務(wù)器,中心可以是GATT客戶端或GATT服務(wù)器。
image
1.4 Bluedroid主機(jī)架構(gòu)
在 ESP-IDF 中,使用經(jīng)過大量修改后的 BLUEDROID 作為藍(lán)牙主機(jī) (Classic BT + BLE)。BLUEDROID 擁有較為完善的功能,?持常用的規(guī)范和架構(gòu)設(shè)計(jì),同時(shí)也較為復(fù)雜。經(jīng)過大量修改后,BLUEDROID 保留了大多數(shù) BTA 層以下的代碼,幾乎完全刪去了 BTIF 層的代碼,使用了較為精簡的 BTC 層作為內(nèi)置規(guī)范及 Misc 控制層。修改后的 BLUEDROID 及其與控制器之間的關(guān)系如下圖:
二、API說明
以下 GATT 接口位于 bt/host/bluedroid/api/include/api/esp_gattc_api.h
2.1 esp_ble_gattc_search_service
2.2 esp_ble_gattc_get_char_by_uuid
2.3 esp_ble_gattc_get_descr_by_char_handle
2.4 esp_ble_gattc_get_attr_count
2.5 esp_ble_gattc_write_char
2.6 esp_ble_gattc_write_char_descr
2.7 esp_ble_gattc_register_for_notify
三、發(fā)現(xiàn)服務(wù)
本篇是關(guān)于GATT客戶端發(fā)現(xiàn)服務(wù)和讀寫特征值,連接服務(wù)端的流程查看 ESP32學(xué)習(xí)筆記(32)——BLE GAP主機(jī)端連接
MTU配置事件還用于開始發(fā)現(xiàn)客戶端剛剛連接到的服務(wù)器中可用的服務(wù)。要發(fā)現(xiàn)服務(wù),可以使用esp_ble_gattc_search_service()函數(shù)。該函數(shù)的參數(shù)包括GATT接口、應(yīng)用程序配置文件連接ID和客戶端感興趣的應(yīng)用程序UUID。
我們正在尋找的服務(wù)定義為:
#define REMOTE_SERVICE_UUID 0x00FFstatic esp_bt_uuid_t remote_filter_service_uuid = {
.len = ESP_UUID_LEN_16,
.uuid = {.uuid16 = REMOTE_SERVICE_UUID,},};
隨后進(jìn)行查找服務(wù):
esp_ble_gattc_search_service(gattc_if, param->cfg_mtu.conn_id, &remote_filter_service_uuid);
break;
找到的服務(wù)結(jié)果(如果有的話)將從ESP_GATTC_SEARCH_RES_EVT返回。對于找到的每個(gè)服務(wù),將觸發(fā)事件來打印所發(fā)現(xiàn)服務(wù)的信息,具體取決于UUID的大?。?p>
case ESP_GATTC_SEARCH_RES_EVT: {
esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id;
conn_id = p_data->search_res.conn_id;
if (srvc_id->id.uuid.len == ESP_UUID_LEN_16 && srvc_id->id.uuid.uuid.uuid16 == REMOTE_SERVICE_UUID) {
get_server = true;
gl_profile_tab[PROFILE_A_APP_ID].service_start_handle = p_data->search_res.start_handle;
gl_profile_tab[PROFILE_A_APP_ID].service_end_handle = p_data->search_res.end_handle;
ESP_LOGI(GATTC_TAG, 'UUID16: %x', srvc_id->id.uuid.uuid.uuid16);
}
break;
如果客戶端找到了它要查找的服務(wù),就將get_server標(biāo)記設(shè)置為true,并保存開始句柄值和結(jié)束句柄值,稍后將使用它們來獲得該服務(wù)的所有特征。在返回所有服務(wù)結(jié)果之后,將完成搜索并觸發(fā)ESP_GATTC_SEARCH_CMPL_EVT事件。
四、獲取特征
此示例實(shí)現(xiàn)從預(yù)定義服務(wù)獲取特征數(shù)據(jù)。我們想要獲得特征的服務(wù)UUID是0x00FF,我們感興趣的特征UUID是0xFF01:
#define REMOTE_NOTIFY_CHAR_UUID 0xFF01
使用esp_gatt_srvc_id_t結(jié)構(gòu)定義服務(wù):
/**
* @brief Gatt id, include uuid and instance id
*/typedef struct {
esp_bt_uuid_t uuid; /*!< UUID */
uint8_t inst_id; /*!< Instance id */} __attribute__((packed)) esp_gatt_id_t;
在這個(gè)例子中,我們定義了我們想要獲取特征的服務(wù):
static esp_gatt_srvc_id_t remote_service_id = {
.id = {
.uuid = {
.len = ESP_UUID_LEN_16,
.uuid = {.uuid16 = REMOTE_SERVICE_UUID,},
},
.inst_id = 0,
},
.is_primary = true,};
定義之后,我們可以使用esp_ble_gattc_get_characteristic()函數(shù)從該服務(wù)獲取特征,該函數(shù)在服務(wù)搜索完成并且找到了它正在尋找的服務(wù)之后,在ESP_GATTC_SEARCH_CMPL_EVT事件中調(diào)用。
case ESP_GATTC_SEARCH_CMPL_EVT:
if (p_data->search_cmpl.status != ESP_GATT_OK){
ESP_LOGE(GATTC_TAG, 'search service failed, error status = %x', p_data->search_cmpl.status);
break;
}
conn_id = p_data->search_cmpl.conn_id;
if (get_server){
uint16_t count = 0;
esp_gatt_status_t status = esp_ble_gattc_get_attr_count( gattc_if,
p_data->search_cmpl.conn_id,ESP_GATT_DB_CHARACTERISTIC, gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, gl_profile_tab[PROFILE_A_APP_ID].service_end_handle,
INVALID_HANDLE,
&count);
if (status != ESP_GATT_OK){
ESP_LOGE(GATTC_TAG, 'esp_ble_gattc_get_attr_count error');
}
if (count > 0){
char_elem_result = (esp_gattc_char_elem_t*)malloc (sizeof(esp_gattc_char_elem_t) * count);
if (!char_elem_result){
ESP_LOGE(GATTC_TAG, 'gattc no mem');
}else{
status = esp_ble_gattc_get_char_by_uuid( gattc_if,
p_data->search_cmpl.conn_id,
gl_profile_tab[PROFILE_A_APP_ID].service_start_handle,
gl_profile_tab[PROFILE_A_APP_ID].service_end_handle,
remote_filter_char_uuid,
char_elem_result,
&count);
if (status != ESP_GATT_OK){
ESP_LOGE(GATTC_TAG, 'esp_ble_gattc_get_char_by_uuid error');
}
/* Every service have only one char in our 'ESP_GATTS_DEMO' demo,
so we used first 'char_elem_result' */
if (count > 0 && (char_elem_result[0].properties
&ESP_GATT_CHAR_PROP_BIT_NOTIFY)){
gl_profile_tab[PROFILE_A_APP_ID].char_handle =
char_elem_result[0].char_handle;
esp_ble_gattc_register_for_notify (gattc_if,
gl_profile_tab[PROFILE_A_APP_ID].remote_bda,
char_elem_result[0].char_handle);
上一篇:ESP32學(xué)習(xí)筆記(34)——BLE一主多從連接
下一篇:ESP32學(xué)習(xí)筆記(32)——BLE GAP主機(jī)端連接
推薦閱讀最新更新時(shí)間:2025-06-23 19:43

設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級數(shù)字信號控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲(chǔ)html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測試
- 使用 Semtech 的 SC2516 的參考設(shè)計(jì)
- 使用 IXYS 的 Z8917529FSCRXXX 的參考設(shè)計(jì)
- 使用 Broadcom Inc 的 ACPL-339J 的參考設(shè)計(jì)
- 使用 ROHM Semiconductor 的 BD49K46G-TL 的參考設(shè)計(jì)
- LT1076CT-5 5V 降壓型開關(guān)穩(wěn)壓器的典型應(yīng)用電路
- 適用于汽車應(yīng)用的 A5970D 1A 降壓穩(wěn)壓器的典型應(yīng)用
- TRK-S12ZVHY64: 適用于摩托車儀表板應(yīng)用的S12 MagniV
- LTC6262ITS8 低功率、低失真 ADC 驅(qū)動(dòng)器、運(yùn)算放大器的典型應(yīng)用
- AD9913/PCBZ,用于 AD9913、10 位、250 MSPS 數(shù)模轉(zhuǎn)換器的評估板
- LTC3830、3.3V 至 5V 反相轉(zhuǎn)換器
- 南芯科技推出高集成度多口移動(dòng)電源解決方案,助力充電寶市場穩(wěn)健發(fā)展
- 英飛凌推出具有超低導(dǎo)通電阻的CoolSiC? MOSFET 750 V G2,適用于汽車和工業(yè)功率電子應(yīng)用
- DigiKey 慶祝 B 站賬號粉絲突破 10 萬,贈(zèng)送驚喜禮包
- 碳化硅企業(yè) Wolfspeed 啟動(dòng)破產(chǎn)重組,預(yù)計(jì) 2025 年三季度末完成司法重整
- 蘋果被曝考慮放棄自研模型 轉(zhuǎn)而與Anthropic或OpenAI合作
- ?百度文心4.5來襲!英特爾Day0即支持端側(cè)部署
- 【廣瀨電機(jī)】關(guān)于中國發(fā)明專利侵權(quán)訴訟達(dá)成和解的公告
- 英飛凌BMS解決方案推動(dòng)電動(dòng)汽車創(chuàng)新
- 地平線的L3判斷與實(shí)踐路徑
- 汽車網(wǎng)絡(luò)升級攻略:CAN-CAN FD-車載以太網(wǎng)
- 2018年中國軟件百強(qiáng)榜:華為騰訊百度居前三
- 劉鵬:“中興事件”后 國家對合規(guī)問題更加重視
- 中興通訊:同意向中國銀行申請300億元綜合授信額度
- 小米IPO定價(jià)17港元 位于17至22港元招股區(qū)間低端
- 挖礦盛宴已經(jīng)開始走下坡路|一句話點(diǎn)評
- ARM 之LCD和LCD控制器
- avr單片機(jī)熔絲位設(shè)置方法及步驟及設(shè)置注意事項(xiàng)
- AVR單片機(jī)生成負(fù)壓的原理解析
- 基于AVR單片機(jī)端口的操作方法解析
- 以AVR單片機(jī)為核心的全自動(dòng)太陽能工程熱水器控制器設(shè)計(jì)