1. 程式人生 > >[BLE]低功耗藍芽之GAP、GATT

[BLE]低功耗藍芽之GAP、GATT

轉載自:

https://blog.csdn.net/qq_21842557/article/details/50771077

一、開篇

    本篇主要介紹一下關於BLE開發過程中必須瞭解的兩個協議:GAP(通用訪問協議)、GATT(通用屬性協議)。

兩個協議都隸屬於Host層,直接關係到應用層開發,與BLE開發人員的關係比較密切,其分別負責連線前資料廣播和連線後的資料傳輸。

 

三、試驗平臺

Software Version:BLE_STACK_CC26XX_2.1.0

Hardware Version:CC2640/CC2650

IDE:IAR 7.40

 

四、GAP
    1、藍芽低能耗技術“完成”一次連線(即掃描其它裝置、建立鏈路、傳送資料、認證和適當地結束)只需3ms。
而標準藍芽技術完成相同的連線週期需要數百毫秒。

    GAP層有4種不同型別的廣播:通用的、定向的、不可連線的以及可發現的。

    裝置每次廣播時,會在3個廣播通道上傳送相同的報文。這些報文被稱為一個廣播事件。除了定向報文以外,其他廣播事件均可以選擇20ms - 10.28s不等的間隔。通常,一個廣播中的裝置會每一秒廣播一次。廣播事件之間的時間稱為廣播間隔。主機可以控制該間隔。但是,裝置週期性的傳送廣播會有一個問題:由於裝置間的時鐘會不同程度的漂移,兩個裝置可能在很長一段時間同時廣播而造成千擾。為防止選一情況的發生,在上一次廣播事件發生後加入隨機延時。它們傳送下一個廣播事件時也很可能不再衝突。

    通用廣播:通用廣播是用途最廣的廣播方式。進行通用廣播的裝置能夠被掃描裝置掃描到,或者在接收到連線請求時作為從裝置進入一個連線。通用廣播可以在沒有連線的情況下發出,換句話說,沒有主從裝置之分。

    定向廣播:有時候,裝置間需要快速建立連線。如果從裝置想這麼做,就需要進行廣播。定向廣播事件就是為了儘可能快的建立連線。這種報文包含兩個地址:廣播者的地址和發起者的地址。發起裝置收到發紿自己的定向廣播報文後,可以立即傳送連線請求作為迴應。

    不可連線廣播:不想被連線的裝置使用不可連線廣播事件。這種廣播的典型應用包括裝置只想廣播資料,而不想被掃描或者連線。速也是唯一可用於只有發射機而沒有接收機裝置的廣播型別。不可連線廣播裝置不會進入連線態,因此,它只能根據主機的要求在廣播態和就緒態之間切換。

    可發現廣播:最後一種廣播事件是可發現廣播。這種廣播不能用於發起連線,但允許其他裝置掃描該廣播裝置。這意味著該裝置可以被發現,既可以廣播資料,又可以響應掃描,但不能建立連線。這是一種適用於廣播資料的廣播形式,動態資料可以包含於廣播資料之中,而靜態資料可以包含於掃描響應資料之中。可發現廣播不會進入連線態,而只能在停止後回到就緒態。

    如上面所述,BLE裝置可以進行廣播。但是,一個廣播裝置必須在廣播中包含一些有用的資料。這意味著可以通過4種廣播事件中的3種進行廣播:通用廣播、不可連線廣播以及可發現廣播。進行廣播時,需要在廣播報文中給資料打上標籤。之所以要這麼做,是因為並非所有裝置都能理解所有可能的廣播資料。因此,需要給廣播資料打上標籤並指出其長度。每個資料片段均起始於一個長度域,用以指示後面的型別及資料域的長度;接下來是型別域,接收機可根據其內容判斷自己是否能夠理解後面的資料。事例程式碼:

// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertisting)
static uint8_t advertData[] =
{
  // Flags; this sets the device to use limited discoverable
  // mode (advertises for 30 seconds at a time) instead of general
  // discoverable mode (advertises indefinitely)
  0x02,   // length of this data
  GAP_ADTYPE_FLAGS,
  DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // service UUID, to notify central devices what services are included
  // in this peripheral
  0x03,   // length of this data
  GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
#ifdef FEATURE_OAD
  LO_UINT16(OAD_SERVICE_UUID),
  HI_UINT16(OAD_SERVICE_UUID)
#else
  LO_UINT16(SIMPLEPROFILE_SERV_UUID),
  HI_UINT16(SIMPLEPROFILE_SERV_UUID)
#endif //!FEATURE_OAD
};


五、GATT
    通用屬性配置檔案(GATT)在屬性協議(ATT)的基礎上構建,為屬性協議傳輸和儲存資料建立了一些通用操作和框架。

1)GATT定義了兩個角色:伺服器和客戶端。

    GATT的角色並不一定與特定的GAP角色有關聯,但可能由更高層級的配置檔案指定。GATT和ATT不是傳輸專用,也可以用於BR/EDR和低耗能。但是,由於GATT和ATT用作發現服務,故必須在低耗能技術中實施。GATT伺服器儲存通過屬性協議傳輸的資料,並接受GATT客戶端發出的屬性協議請求、指令及確認。GATT伺服器傳送請求回覆,而如果在配置時GATT伺服器發生特定事件,則會向GATT客戶端非同步傳送指示和通知。GATT還指定GATT伺服器中所載的資料格式。

    屬性在當經由屬性協議傳輸時,會被格式化為相關的服務和特性。服務可能包括許多特徵。特徵包括單一值和許多描述特徵值的描述符。

憑藉經定義的服務、特徵和特徵描述符架構,並非配置檔案特定的GATT客戶端仍然可以遍歷GATT伺服器,並向用戶顯示特徵值。特徵描述符可用於顯示特徵值的描述符,從而可讓使用者瞭解該值。

2)GATT配置檔案層級

    GATT配置檔案規格規定了交換配置檔案資料的架構。此架構定義了配置檔案所用的基本元素,例如服務和特徵。

該層級的最高層是配置檔案(profile)。配置檔案由實現用例所需的一個或多個服務組成。服務由特徵或有關其它服務的引用組成。每一個特徵包括一個值,還可能包括有關該值的可選資訊。服務、特徵以及特徵的元件(即特徵值和特徵描述符)構成了配置檔案資料,並全部儲存在伺服器的屬性中。

    英文原版(摘自Core_V4.1 vol 1:6.5,p226):The top level of the hierarchy is a profile. A profile is composed of oneor more services necessary to fulfill a use case. A service is composed of characteristicsor references to other services. Each characteristic contains a value and maycontain optional information about the value. Theservice and characteristic and the components of the characteristic (i.e.,value and descriptors) contain the profile data and are all stored in Attributes on theserver.

0

3)服務

    服務是資料和完成裝置或裝置的某些部分的特定功能或特徵的相關行為的集合。服務可能涉及其它主要或次要服務和/或構成該服務的特徵集合。

服務分為兩種型別:主要服務和次要服務。主要服務提供裝置的主要功能。次要服務提供裝置的輔助功能,引用自該裝置至少一項主要服務。

為了令早前的客戶端保持向後相容性,服務定義的其後修訂僅可增加新引用的服務或可選特徵。服務定義的其後修訂也不得改變該服務定義先前修訂的特徵。

服務可能用於一個或多個配置檔案,以實現特定用例。

4)特徵

    特徵,連同屬性和有關如何訪問該值的配置資訊以及有關如何顯示或表述該值的資訊,是用於服務的值。特徵定義包含特徵宣告、特徵屬性和值。它還可能包含描述該值或允許伺服器配置有關特徵值的描述符。

協議棧程式碼實現如下:

/*********************************************************************
 * Profile Attributes - variables
 */
// Simple Profile Service attribute
static CONST gattAttrType_t simpleProfileService = { ATT_BT_UUID_SIZE, simpleProfileServUUID };
// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;
// Characteristic 1 Value
static uint8 simpleProfileChar1 = 0;
// Simple Profile Characteristic 1 User Description
static uint8 simpleProfileChar1UserDesp[17] = "Characteristic 1";


/*********************************************************************
 * Profile Attributes - Table
 */
static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] = 
{
  // Simple Profile Service
  { 
    { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */
    GATT_PERMIT_READ,                         /* permissions */
    0,                                        /* handle */
    (uint8 *)&simpleProfileService            /* pValue */
  },
    // Characteristic 1 Declaration
    { 
      { ATT_BT_UUID_SIZE, characterUUID },
      GATT_PERMIT_READ, 
      0,
      &simpleProfileChar1Props 
    },
      // Characteristic Value 1
      { 
        { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE, 
        0, 
        &simpleProfileChar1 
      },
      // Characteristic 1 User Description
      { 
        { ATT_BT_UUID_SIZE, charUserDescUUID },
        GATT_PERMIT_READ, 
        0, 
        simpleProfileChar1UserDesp 
      },      
5)關於控制代碼handle 和UUID

    Handle即是地址(記住它,類比於C語言的指標操作)

    屬性控制代碼:一臺裝置可以有許多的屬性,例如溫度感測器可能包含溫度屬性、裝置名稱屬性和電池電量屬性。

表面看來,通過屬性型別似乎足以判別某種屬性。比如使用溫度屬性來獲取溫度,通過裝置名稱屬性來獲取裝置名等。但是,如果裝置包含了兩種溫度屬性,比如一個室內溫度感測器加上室外溫度感測器,情況會變得怎樣。這時你便無法直接讀取溫度感測器,而必須讀取第一個或第二個溫度屬性。考慮到可能有任意多個溫度感測器,問題將變得更加複雜。

為了解決這個同題,我們使用了一個16位的地址,也就是屬性控制代碼。

有效的控制代碼範圍從0x0001--xFFFF。

0x0000為無效控制代碼,不能用於定址屬性。
可以根據在軟硬體或嵌入式方面的背景,把控制代碼(Handle)相應地想象為記憶體地址、埠號、屬性值對應的硬體暫存器地址。

    屬性型別:可以被公開的資料有許許多多的型別:溫度、壓強、體積、距離、功率、時間、充電狀態、開關狀態、狀態機的狀態等。所公開的資料的種類稱作屬性型別。

為了區分如此多的資料型別,一串128位的數字被用來標識屬性的型別。這個唯一標識碼就叫做通用唯一識別碼(UUID),128位的UUID相當長,裝置間為了識別資料的型別需要傳送長達16個位元組的資料。

為了提高傳輸效率,藍芽技術聯盟( SIG)定義了一種稱為“藍芽UUID基數”的128位通用唯一識別碼,結合一個較短的16位數使用。

二者仍然遵循通用唯一識別碼的分配規則,只不過在裝置間傳輸常用的UUID時,只發送較短的16位版本,接收方收到後補上藍芽的UUID基數即可。

藍芽UUID基數如下:

00000000—0000—1000—8000—00805F9B34FB

例如要傳送的16位識別碼位0X2A01,完整的128位UUID便是:

00002A01—0000—1000—8000—00805F9B34FB

    由上所述,所以在協議棧程式碼中經常見到的都是16位的UUID而不常見128位的UUID的原因所在,下面是官方demo的UUID,供參考。
// Simple Profile Service UUID
#define SIMPLEPROFILE_SERV_UUID               0xFFF0
    
// Key Pressed UUID
#define SIMPLEPROFILE_CHAR1_UUID            0xFFF1
#define SIMPLEPROFILE_CHAR2_UUID            0xFFF2
#define SIMPLEPROFILE_CHAR3_UUID            0xFFF3
#define SIMPLEPROFILE_CHAR4_UUID            0xFFF4
#define SIMPLEPROFILE_CHAR5_UUID            0xFFF5
談到16位的UUID,通常不直接使用數值,而是冠以一個名稱並加上書名號(這些UUID可以在gatt_profile_uuid.h中檢視到)

0x1800 - 0x26FF用作服務類通用唯一識別碼

0x2700 - 0x27FF用於標識計量單位

0x2800 - 0x28FF用於區分屬性型別

0x2900 - 0x29FF用作特性描述

0x2A00- 0x7FFF用於區分特性型別

UUID,就是用來唯一識別一個特徵值的ID。

handle,就是對應的attribute的一個控制代碼。

具體細節詳見:Generic Attribute Profile (GATT)

摘抄一部分原始碼供參考:

/**
 * GATT Service UUIDs
 */
#define IMMEDIATE_ALERT_SERV_UUID       0x1802  // Immediate Alert
#define LINK_LOSS_SERV_UUID             0x1803  // Link Loss
#define TX_PWR_LEVEL_SERV_UUID          0x1804  // Tx Power
#define CURRENT_TIME_SERV_UUID          0x1805  // Current Time Service
#define REF_TIME_UPDATE_SERV_UUID       0x1806  // Reference Time Update Service

/**
 * GATT Characteristic UUIDs
 */
#define ALERT_LEVEL_UUID                0x2A06  // Alert Level
#define TX_PWR_LEVEL_UUID               0x2A07  // Tx Power Level
#define DATE_TIME_UUID                  0x2A08  // Date Time
#define DAY_OF_WEEK_UUID                0x2A09  // Day of Week
#define DAY_DATE_TIME_UUID              0x2A0A  // Day Date Time
#define EXACT_TIME_256_UUID             0x2A0C  // Exact Time 256

/**
 * GATT Unit UUIDs
 */
#define GATT_UNITLESS_UUID                    0x2700  // <Symbol>, <Expressed in terms of SI base units>
#define GATT_UNIT_LENGTH_METER_UUID           0x2701  // m, m
#define GATT_UNIT_MASS_KGRAM_UUID             0x2702  // kg, kg
    所有對特徵值的操作,都是通過對UUID 的搜尋得到對應的handle之後,通過handle來操作特徵值的。對於藍芽通訊來說,其都是通過一個個不同的UUID來標識區分不同的服務,區分不同的特性,甚至服務和特性之間的類別。


六、總結

    不知道寫什麼了,就這樣吧,後續想到了寫吧,學習BLE也不久,路還很長。路漫漫其修遠兮,吾將上下而求索~~~

    PS:該死的房價。。。。啊啊啊啊啊啊。。。。

    參考:1)藍芽技術聯盟官方網站

               2)Bluetooth開發者門戶

               3)Bluetooth Spec Core_V4.1