- 導(dǎo)語(yǔ)
該篇文章,主要講述BLE中的GATT profile。
1、什么是GATT
GATT是generic attribute的簡(jiǎn)稱,顧名思義,其描述的是BLE的屬性應(yīng)用規(guī)范。所謂的屬性,我們可以理解為數(shù)據(jù)庫(kù)中的一張表,是一個(gè)可以被查找的數(shù)據(jù);在BLE中,我們使用handle句柄來進(jìn)行尋址,handle句柄值是唯一的。
在實(shí)際應(yīng)用場(chǎng)景中,需要多個(gè)service來支持 ,每個(gè)service下面同時(shí)有多個(gè)特性(character),每個(gè)特性要有較為詳細(xì)的描述,如這個(gè)特性的值和一些簡(jiǎn)單的說明等。無論是服務(wù)、特性,都要進(jìn)行區(qū)分,BLE中使用UUID進(jìn)行了區(qū)分。除此之外,作為數(shù)據(jù),我們肯定是要對(duì)其進(jìn)行訪問的,這就要提供相應(yīng)的訪問權(quán)限,如可讀、可寫等。
屬性
屬性由屬性句柄、屬性類型、屬性值等組成。
屬性句柄就是我們來進(jìn)行數(shù)據(jù)查找的依據(jù);
屬性類型使用UUID來進(jìn)行區(qū)分,SIG對(duì)屬性類型進(jìn)行了分類:
0x1800 ~ 0x26FF 用作服務(wù)類通用唯一識(shí)別碼
0x2700 ~ 0x27FF 用于標(biāo)識(shí)計(jì)量單位
0x2800 ~ 0x28FF 用于區(qū)分屬性類型
0x2900 ~ 0x29FF 用作特性描述
0x2A00 ~ 0x2AFF 用于區(qū)分特性類型
特性
在BLE規(guī)范中,特性一般包括聲明、數(shù)值和描述三個(gè)部分,其中前兩者是強(qiáng)制實(shí)現(xiàn)的。
2、GATT能干啥
簡(jiǎn)單來講,BLE利用GATT來進(jìn)行數(shù)據(jù)的傳輸。
3、 怎么來分析GATT
GATT中的service or characteristic,本質(zhì)上都是attribute,為了使用的方便,BLE對(duì)這些又進(jìn)行了邏輯上的抽象。
以電池服務(wù)為例:
一個(gè)電池服務(wù)(service)包含一個(gè)電池電量特性(characteristic),其一般包含以下幾個(gè)屬性:primary service 電池服務(wù)、當(dāng)前電量的特性定義、當(dāng)前電量的特性值。由于用戶通常會(huì)希望能夠進(jìn)行低電量提醒,所以在設(shè)計(jì)的時(shí)候,這個(gè)電量特性值不僅是可讀的,而且是可以通知的。

以下是battery service在Android中的實(shí)現(xiàn)。
/*******************************************************************************
**
** Function Battery_Instantiate
**
** Description Instantiate a Battery service
**
*******************************************************************************/
UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info)
{
tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
UINT16 srvc_hdl;
tGATT_STATUS status = GATT_ERROR;
tBA_INST *p_inst;
tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ;
if (battery_cb.inst_id == BA_MAX_INT_NUM)
{
GATT_TRACE_ERROR("MAX battery service has been reached");
return 0;
}
p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if ,
&uuid,
battery_cb.inst_id ,
BA_MAX_ATTR_NUM,
p_reg_info->is_pri);
if (srvc_hdl == 0)
{
GATT_TRACE_ERROR("Can not create service, Battery_Instantiate() failed!");
return 0;
}
battery_cb.inst_id ++;
p_inst->app_id = app_id;
p_inst->p_cback = p_reg_info->p_cback;
/* add battery level
*/
uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL;
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
prop |= GATT_CHAR_PROP_BIT_NOTIFY;
if ((p_inst->ba_level_hdl = GATTS_AddCharacteristic(srvc_hdl,
&uuid,
BATTER_LEVEL_PERM,
prop)) == 0)
{
GATT_TRACE_ERROR("Can not add Battery Level, Battery_Instantiate() failed!");
status = GATT_ERROR;
}
else
{
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
{
uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
p_inst->clt_cfg_hdl = GATTS_AddCharDescriptor(srvc_hdl,
(GATT_PERM_READ|GATT_PERM_WRITE),
&uuid);
if (p_inst->clt_cfg_hdl == 0)
{
GATT_TRACE_ERROR("Add battery level client notification FAILED!");
}
}
/* need presentation format descriptor? */
if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT)
{
uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl,
GATT_PERM_READ,
&uuid))
== 0)
{
GATT_TRACE_ERROR("Add battery level presentation format descriptor FAILED!");
}
}
/* need presentation format descriptor? */
if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF)
{
uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl,
GATT_PERM_READ,
&uuid))
== 0)
{
GATT_TRACE_ERROR("Add battery level report reference descriptor FAILED!");
}
}
/* start service
*/
status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport);
}
if (status != GATT_SUCCESS)
{
battery_cb.inst_id --;
uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY;
GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id);
srvc_hdl = 0;
}
return srvc_hdl;
}
- 總結(jié)
本篇文章旨在簡(jiǎn)明的講述GATT是什么,能干什么,怎么去使用GATT,讀者有什么疑惑,可以一起討論。