1. 程式人生 > >TI低功耗藍芽(BLE)GATT介紹

TI低功耗藍芽(BLE)GATT介紹

TI低功耗藍芽(BLE)介紹

本文件翻譯和修改自參考資料:CC2540Bluetooth Low Energy Software Developer’s Guide (Rev. B),部分圖片直接引用自該文件,不一一說明。初稿,待修改。

一、概述

1、BLE藍芽協議棧結構


附圖6 BLE藍芽協議棧結構圖

分為兩部分:控制器和主機。對於4.0以前的藍芽,這兩部分是分開的。所有profile(姑且稱為劇本吧,用來定義裝置或元件的角色)和應用都建構在GAP或GATT之上。下面由結構圖的底層元件開始介紹。 

·        PHY層,工作車間,1Mbps自適應跳頻GFSK(高斯頻移鍵控),執行在免證的2.4GHz

·        LL層為RF控制器,控制室,控制裝置處於準備(standby)、廣播、監聽/掃描(scan)、初始化、連線,這五種狀態中一種。五種狀態切換描述為:未連線時,裝置廣播資訊(向周圍鄰居講“我來了”),另外一個裝置一直監聽或按需掃描(看看有沒有街坊鄰居家常裡短可聊,打招呼“哈,你來啦”),兩個裝置連線初始化(搬幾把椅子到院子),裝置連線上了(開聊)。發起聊天的裝置為主裝置,接受聊天的裝置為從裝置,同一次聊天只能有一個意見領袖,即主裝置和從裝置不能切換。

·        HCI層,為介面層,通訊部,向上為主機提供軟體應用程式介面(API),對外為外部硬體控制介面,可以通過串列埠、SPI、USB來實現裝置控制。

·        L2CAP層,物流部,行李打包盒拆封處,提供資料封裝服務

·        SM層,保衛處,提供配對和密匙分發,實現安全連線和資料交換

·        ATT層,庫房,負責資料檢索

·        GATT層,出納/庫房前臺,出納負責處理向上與應用打交道,而庫房前臺負責向下把檢索任務子程序交給ATT庫房去做,其關鍵工作是把為檢索工作提供合適的profile結構,而profile由檢索關鍵詞(characteristics)組成。

·        GAP層,祕書處,對上級,提供應用程式介面,對下級,管理各級職能部門,尤其是指示LL層控制室五種狀態切換,指導保衛處做好機要工作。

TI的這款CC2540器件可以單晶片實現BLE藍芽協議棧結構圖的所有元件,包括應用程式。

2、任務排程---OSAL作業系統抽象層

正如一個公司為了實現擴大產能和產品多樣化,建立了多個辦公室和工廠一樣,藍芽為了實現同多個裝置相連,或實現多功能,也實現了功能擴充,這就產生了排程問題。因為,雖然軟體和協議棧可擴充,但終究最底層的執行部門只有一個。

為了實現多事件和多工切換,需要把事件和任務對應的應用,以及其相關的提供支撐“辦公室”和“工廠”打包起來,並起一個名字OSAL作業系統抽象層,類似於集團公司以下的子公司

3、裝置改造---HAL硬體抽象層

如果實現軟體和硬體的低耦合,使軟體不經改動或很少改動即可應用在另外的硬體上,這樣就方便硬體改造、升級、遷移後,軟體的移植。HAL硬體抽象層正是用來抽象各種硬體的資源,告知給軟體。其作用類似於嵌入式系統裝置驅動的定義硬體資源的h標頭檔案。其角色類似於現代工廠的裝置管理部

4、BLE低功耗藍芽系統架構


附圖7 BLE低功耗藍芽系統架構圖,圖中的Task用附圖6BLE藍芽協議棧結構圖來描述

BLE低功耗藍芽軟體有2個主要組成: OSAL作業系統抽象層和 HAL硬體抽象層,多個Task任務和事件在OSAL管理下工作,而每個任務和事件又包括3個組成:BLE 協議棧,profiles和應用程式。

附圖7同樣可以用現代工廠模式來類比,如附圖8。


附圖8 BLE低功耗藍芽軟體5個主要組成用現代工廠架構來類比。

有了上面的簡介,下面對OSAL、HAL和BLE進行稍微深入的介紹。

二、OSAL作業系統抽象層

1、軟體功能由OSAL管理下的事件來實現

OSAL作為排程核心,BLE協議棧、profile定義、所有的應用都圍繞它來實現。OSAL不是傳統大家使用的作業系統,而是一個允許軟體建立和執行事件的迴圈。

軟體功能是由任務事件來實現的,建立一個任務事件需要以下工作:

·        建立task identifier任務ID;

·        編寫任務初始化(task initialization routine)程序,並需要新增到OSAL初始化程序中,這就是說系統啟動後不能動態新增功能;

·        編寫任務處理程式;

·        如有需要提供訊息服務。

BLE協議棧的各層都是以OSAL任務方式實現,由於LL控制室的時間要求最為迫切,所以其任務優先順序最高。為了實現任務管理,OSAL通過訊息處理(messageprocess),儲存管理,計時器定時等附加服務實現。

2、系統啟動流程

為了使用OSAL,在main函式的最後要啟動一個名叫osal_start_system的程序,該程序會呼叫由特定應用決定的啟動函式osalInitTasks(來啟動系統)。osalInitTasks逐個呼叫BLE協議棧各層的啟動程序來初始化協議棧。隨後,設定一個任務的8bit任務ID(task ID),跳入迴圈等待執行任務,系統啟動完成。

3、任務事件與事件處理

程序優先順序和任務ID

·        任務優先順序決定於任務ID,任務ID越小,優先順序越高

·        BLE協議棧各層的任務優先順序比應用程式的高

·        初始化協議棧後,越早調入的任務,任務ID越高,優先順序越低,即系統傾向於處理新到的任務

事件變數和旗語

每個事件任務由對應的16bit事件變數來標示,事件狀態由旗號(taskflag)來標示。如果事件處理程式已經完成,但其旗號並沒有移除,OSAL會認為事情還沒有完成而繼續在該程式中不返回。比如,在SimpleBLEPeripheral例項工程中,當事件START_DEVICE_EVT發生,其處理函式SimpleBLEPeripheral_ProcessEvent就執行,結束後返回16bit事件變數,並清除旗語SBP_START_DEVICE_EVT。

事件處理表單

每當OSAL事件檢測到了有任務事件,其相應的處理程序將被新增到由處理程序指標構成的事件處理表單中,該表單名叫taskArr(taskarray)。taskArr中各個事件程序的順序和osalInitTasks初始化函式中任務ID的順序是對應的。

事件排程的方法

有兩種,最簡單的方法是使用osal_set_event函式(函式原型在OSAL.h檔案中),在這個函式中,使用者可以像定義函式引數一樣設定任務ID和事件旗語。第二種方法是使用osal_start_timerEx函式(函式原型在OSAL_Timers.h檔案中),使用方法同osal_set_event函式,而第三個以毫秒為單位的引數osal_start_timerEx則指示該事件處理必須要在這個限定時間內,通過定時器來為事件處理計時。

4、儲存管理

類似於Linux嵌入式系統記憶體分配C函式mem_alloc,OSAL利用osal_mem_alloc提供基本的儲存管理,但osal_mem_alloc只有一個用於定義byte數的引數。對應的記憶體釋放函式為osal_mem_free。

5、程序間通訊—通過訊息機制實現

不同的子系統通過OSAL的訊息機制通訊。訊息即為資料,資料種類和長度都不限定。

訊息收發過程描述如下:

接收資訊,呼叫函式osal_msg_allocate建立訊息佔用記憶體空間(已經包含了osal_mem_alloc函式功能),需要為該函式指定空間大小,該函式返回記憶體空間地址指標,利用該指標就可把所需資料拷貝到該空間。

傳送資料,呼叫函式osal_msg_send,需為該函式指定傳送目標任務,OSAL通過旗語SYS_EVENT_MSG告知目標任務,目標任務的處理函式呼叫osal_msg_receive來接收發來的資料。建議每個OSAL任務都有一個訊息處理函式,每當任務收到一個訊息後,通過訊息的種類來確定需要本任務做相應處理。訊息接收並處理完成,呼叫函式osal_msg_deallocate來釋放記憶體(已經包含了osal_mem_free函式功能)。

三、硬體抽象層HAL

當新的硬體平臺做好後,只需修改HAL,而不需修改HAL之上的協議棧的其他元件和應用程式。

四、BLE低功耗藍芽協議棧

1、BLE庫檔案

TI藍芽協議棧是以單獨一個庫檔案提供的,並沒有提供原始碼,因此不做深入說明。對於TI的BLE例項應用,這個單獨庫檔案已經夠用,列出了所有的庫檔案。


附圖9 BLE庫檔案

由於GAP和GATT與使用者程式直接互動,因此下文對庫檔案中GAP和GATT一一講解。

2、GAP祕書處

2.1角色(即服務,功能)

GAP執行在如下四種角色的一種:

·        Broadcaster        廣播員—我在,但只可遠觀,不可連線。

·        Observer             觀察員—看看誰在,但我只遠觀,不連線。

·        Peripheral           外設(從機)—我在,誰要我就跟誰走,協議棧單層連線。

·        Central                 核心(主機)—看看誰在,並且願意跟我走我就帶她/他走,協議棧單層或多層連線,目前最多支援3個同時連線。

雖然指標顯示BLE可以同時扮演多個角色,但是在TI提供的BLE例項應用中預設只支援外設角色。每一種角色都由一個劇本(roleprofile)來定義。

2.2連線

主從機連線過程

一個典型的低功耗藍芽系統同時包含外設和核心(主機),兩者的連線過程如下:

外設角色向外傳送自己的資訊(裝置地址、名字等),主機收到外設廣播資訊後,傳送掃描請求(scanrequest)給外設,外設響應主機的請求,連線建立完成。

連線引數

主要有通訊間隙(connectioninterval)、外設鄙視(slavelatency)、最大耐心等待時間(supervisiontimeout)等,下面簡單說明。

·        通訊間隙—藍芽通訊是間斷的、跳頻的,每次連線都可能選擇不同的子頻帶。跳頻的好處是避免頻道擁塞,間斷連線的好處是節省功耗,通訊間隙就是指兩次連線之間的時間間隔。這個間隔以1.25ms為基本單位,最小6單位最大3200單位,間隙越小通訊越及時,間隙越大功耗越低。

·        外設鄙視—外設與主機建立連線以後,沒事的時候主機總會定期傳送問候資訊到外設,外設懶得搭理,這些主機發送的資訊就浮雲般飄過。可以忽略的連線事件個數從0到499個,最多不超過32秒。有效連線間隙= 連線間隙x (1+ 外設鄙視).

·        最大耐心等待時間—指的是為了建立一個連線,主機允許的最大等候時間,在這個時間內,不停的嘗試連線。範圍是10個~3200個通訊間隙基本單位(1.25ms)。

以上三引數大小設定優劣是顯而易見的,在此也飄過。連線引數的設定請參看後文“5.1GAP外設劇本”小節。

連線異常處理

舉例說明連線異常,如主機採用從機並不舒坦的引數來請求連線,有如主從機已經連線了,但從機有想法了,要改引數條約。通過“連線引數更新請求(ConnectionParameter Update Request)”來解決問題,交由L2CAP“收發室物流處”處理。連線引數上文已經說了,不再敘述。

加密處理

利用配對實現,利用密匙來加密授權連線。典型的過程是:外設向主機請求口令一個(passkey)以便進行配對,待主機發送了正確的口令之後,連線通訊通過主從機互換密碼來校驗。由於藍芽通訊是間斷通訊,如果一個應用需要經常通訊,而每次通訊都要重新申請連線,那將是勞神費力的,為此GAP安全衛士(SM,security profile)提供了一種長期簽證(long-termset of keys),叫做繫結(bonding),這樣每次建立連線通關流程就簡便快捷了。

3、出納GATT

GATT負責兩個裝置間通訊的資料互動。共有兩種角色:出納員(GATTClient)和銀行(GATTServer),銀行提供資金,出納從銀行存取款。銀行可以同時面對多個出納員。這兩種角色和主從機等角色是無關的。

GATT把工作拆分成幾部分來實現:讀關鍵詞(CharacteristicValue)和描述符(CharacteristicDescriptor),用來去庫房查詢提取資料。寫讀關鍵詞和描述符。

GATT銀行(GATTServer)的業務部門(API)主要提供兩個主要的功能:一是服務功能,註冊或銷燬服務(serviceattribute),並作為回撥函式(callbackfunction);二是管理功能,新增或刪除GATT銀行業務。

一個角色定義的劇本可以同時定義多個角色,每個角色的服務、關鍵詞、關鍵值、描述符(service,characteristic, characteristic value and descriptors)都以控制代碼(attributes)形式儲存在角色提供的服務上。所有的服務都是一個gattAttribute_t型別的array,在檔案gatt.h.中定義。

4、呼叫GAP和GATT的一般過程

·        API呼叫

·        協議棧響應並返回

·        協議棧傳送一個OSAL訊息(資料)去呼叫相應任務事件

·        呼叫任務去接收和處理訊息

·        訊息清除

以裝置初始化為GAP外設角色來舉例說明,外設角色由其劇本(GAPperipheral role profile)來決定,例項程式在檔案peripheral.c內。

·        呼叫API函式GAP_DeviceInit。

·        GAP檢查了一下說,好,可以初始化,返回值為SUCCESS (0x00),並通知BLE幹活。

·        BLE協議棧傳送OSAL訊息給外設角色劇本(peripheral roleprofile),訊息內容包括要幹什麼(eventvalue)GAP_MSG_EVENT和指標是什麼(opcodevalue,引數)。

·        角色劇本的服務任務就收到了事件請求SYS_EVENT_MSG,表示有訊息來了。

·        角色劇本接收訊息,並拆看到底是什麼事,接著把訊息資料轉換(cast)成具體要幹事情,並完成相應的工作(這裡為gapDeviceInitDoneEvent_t)。

·        角色劇本清除訊息並返回。

再舉一個例子:GATT客戶端裝置想從GATT伺服器端讀取資料,即GATT出納想從GATT銀行那邊取點錢出來

·        應用程式呼叫GATT子程序API函式GATT_ReadCharValue,傳遞的引數為連線控制代碼、關鍵詞控制代碼和自身任務的ID。

·        GATT答應了這個請求,返回值為SUCCESS (0x00),向下告知BLE有活幹了。

·        BLE協議棧在下次建立藍芽連線時,傳送取錢的指令給銀行,當銀行說好,我們正好有櫃員沒事在幹剪指甲,於是把錢取出來交給了BLE。

·        BLE接著就把取到的錢包成訊息(OSAL message),通過出納GATT返回給了應用程式。訊息內包含GATT_MSG_EVENT和修改了的ATT_READ_RSP。

·        應用程式接收到了從OSAL來的SYS_EVENT_MSG事件,表示錢可能到了

·        應用程式接收訊息,拆包檢查,並把需要的錢拿走。

·        最後,應用程式把包裝袋銷燬,沒事了,返回。

5、GAP角色劇本profiles

在TI的BLE例項應用中提供了3中GAP角色劇本,保衛處角色,和幾種GATT出納/庫管示例程式服務角色。

5.1 GAP外設劇本

其API函式在peripheral.h中定義,包括:

·        GAPROLE_ADVERT_ENABLED—廣播使能。

·        GAPROLE_ADVERT_DATA—包含在廣播裡的資訊。

·        GAPROLE_SCAN_RSP_DATA—外設用於回覆主機掃描請求的資訊。

·        GAPROLE_ADVERT_OFF_TIME—表示外設關閉廣播持續時間,該值為零表示無限期關閉廣播直到下一次廣播使能訊號到來。

·        GAPROLE_PARAM_UPDATE_ENABLE—使能自動更新連線引數,可以讓外設連線失敗時自動調整連線引數以便重新連線。

·        GAPROLE_MIN_CONN_INTERVAL—設定最小連線間隙,預設值為80個單位(每單位1.25ms)。

·        GAPROLE_MIN_CONN_INTERVAL—設定最大連線間隙,預設值為3200個單位。

·        GAPROLE_SLAVE_LATENCY—外設鄙視引數,預設為零。

·        GAPROLE_TIMEOUT_MULTIPLIER--最大耐心等待時間,預設為1000個單位。

GAPRole_StartDevice函式用來初始化GAP外設角色,其唯一的引數是gapRolesCBs_t,這個引數是一個包含兩個函式指標的結構體,這兩函式是pfnStateChange和pfnRssiRead,前者標示狀態,後者標示RSSI已經被讀走了。

5.2 多角色同時扮演

前文5.1中裝置配置為外設,這裡以裝置同時為外設和廣播員兩種角色。方法為:去除前文外設的定義劇本peripheral.c和peripheral.h,新增新的劇本peripheralBroadcaster.c和peripheralBroadcaster.h;定義處理器值(preprocessorvalue)PLUS_BROADCASTER。

5.3 GAP主機劇本

與外設劇本相似,主機劇本的API函式在central.h中定義,包括GAPCentralRole_GetParameter和GAPCentralRole_SetParameter以及其他。如GAPROLE_PARAM_UPDATE_ENABLE連線引數自動更新使能的功能,跟外設角色的一樣。

GAPCentralRole_StartDevice函式用來初始化GAP主機角色,其唯一的引數是gapCentralRolesCBs_t,,這個引數是一個包含兩個函式指標的結構體,這兩函式是eventCB和rssiCB,每次GAP時間發生,前者都會被呼叫,後者標示RSSI已經被讀走。

5.4 GAP繫結管理器劇本

用於保持長期的連線。同時支援外設配置和主機配置。當建立了配對連線後,如果繫結使能,繫結管理器就維護這個連線。主要引數有:GAPBOND_PAIRING_MODE,GAPBOND_MITM_PROTECTION,GAPBOND_IO_CAPABILITIES,GAPBOND_IO_CAP_DISPLAY_ONLY,GAPBOND_BONDING_ENABLED

GAPBondMgr_Register函式用來初始化GAP主機角色,其唯一的引數是gapBondCBs_t,,這個引數是一個包含兩個函式指標的結構體,這兩函式是pairStateCB和passcodeCB,前者返回狀態,後者用於配對時產生6為數字口令(passcode)。

5.5怎樣編寫一個劇本來建立(定義)新的角色(功能、服務)

以SimpleGATT Profile為劇本名稱,包含兩個檔案simpleGATTProfile.c和simpleGATTProfile.h。包含如下主要API函式:

·        SimpleProfile_AddService—用於初始化的程序,作用是新增服務控制代碼(serviceattributes)到控制代碼組(attributetable)內,暫存器讀取和回寫。

·        SimpleProfile_SetParameter—設定劇本(profile)關鍵詞(characteristics)

·        SimpleProfile_GetParameter—獲取獲取設定劇本關鍵詞

·        SimpleProfile_RegisterAppCBs

·        simpleProfile_ReadAttrCB

·        simpleProfile_WriteAttrCB

·        simpleProfile_HandleConnStatusCB

這個例項劇本共有5個關鍵詞:

·        SIMPLEPROFILE_CHAR1

·        …

·        SIMPLEPROFILE_CHAR5

【完,待修改】