藍牙專題二(Bluez協議棧中間層協議概述)

由於生產藍牙設備的廠家衆多,設備外部接口的標準化問題直接關係着設備弄否方便的在不同的主機上進行應用。針對這一問題SIG在藍牙規範中定義了HCI層。HCI層保證了藍牙設備與藍牙主機接口的標準化。

1、 HCI協議概述
HCI層位於藍牙協議的中間層與底層,起着溝通兩者的作用(圖3.3中描述了HCI層在底層軟件中的位置)。同時,HCI層也是藍牙軟件與藍牙硬件之間的交互接口。藍牙軟件將通過HCI層提供的一系列接口完成與藍牙硬件的通信。具體到本文,就是藍牙軟件將通過HCI層的接口函數實現對藍牙適配器設置和控制。
HCI也可以讀取和設置遠程藍牙設備的相應參數。
 

 

2、HCI程序設計
在HCI層的程序設計中,主要完成的了三項基本功能。第一,完成對本地藍牙設備參數的讀取和設置;第二,負責對周圍設備進行掃描,並可以對遠程藍牙設備的基本參數進行讀取和設置;第三,提供一個HCI命令的發送接口,可以直接利用HCI命令控制本地藍牙適配器。
BlueZ的HCI層是基於上文描述的C/S模式進行的。一般來講,發起會話的藍牙設備將充當C/S模式的客戶端,而被連接的遠程設備扮演服務器端角色。在Linux中,藍牙應用啓動以後,其守護進程(守護進程,運行於後臺的,用於爲系統提供某項服務的程序)bluetoothd起到了C/S模型中服務器的作用,可以對來自遠程的查詢和鏈接請求進行響應。
(1) 本地設備參數讀取模塊實現
本地設備參數的讀取將通過get_dev_infor()函數調用完成。這個接口將給出本地設備的bd_addr、dev_name和dev_id等所有包含於hci_dev_info結構中的參數。這個結構體用於描述設備的基本參數。另外,本地參數讀取模塊還提供了單獨針對某一參數的接口。如,獲得本地設備名稱的get_localnameO,獲得本地bd_addr的get_local_addr0等。其實現流程與遠程設備參數讀取基本類似,只是不需要建立socket連接,不需要對遠程設備進行查詢,其數據處理方法和實現方法均一致。在此,僅以遠程設備的讀取流程進行敘述。
(2) 遠程設備參數讀取模塊實現
遠程設備參數讀取模塊的功能與上一模塊基本一致。所不同的是,在讀取時需要先完成對周圍設備查詢,得到遠程設備的bd_addr,並填充inquiry_info結構。而後,本地設備將與其建立連接,最終實現參數的傳遞。另外,這裏通過調用hciread_remotename0、hciread_remoteversion0和hci_read_remote_featuresO等函數來實現對遠程設備其他參數的讀取。
 

 

 

3 藍牙L2CAP協議編程概述
藍牙協議棧中,位於HCI層之上的是L2CAP層,即邏輯鏈路控制和適配層(Logical Link Control and Adaptation Protoc01)。本節將對L2CAP層編程進行介紹。
L2CAP在藍牙協議中的位置如圖3.9所示。它處於底層與高層協議之間。L2CAP通過協議多路複用、分段和重組操作以及組的概念,向高層協議提供面向鏈接和麪向無鏈接的數據服務。L2CAP允許高層協議和應用傳輸長達64Kb的L2CAP分組。
 

 

 

L2CAP在協議中的位置
(1)、L2CAP PDU格式
下圖描述了L2CAP層提供的面向連接和麪向無連接的兩種PDU(Protocol Data Units,協議數據單元)。
 

面向連接:
長度:2字節,表示數據載荷的長度(不包括L2CAP PDU包頭);
CID:Channel ID,2字節,指示數據包的目的端信道
數據載荷:0到65535字節。
面向無鏈接:
長度:2字節,表示數據載荷的長度(不包括PDU包頭,但包括PSM);
CID:Channel ID,0x0002,2字節,指示數據包的目的端信道;
PSM:爲高層接收無鏈接的L2CAP PDU數據提供標識;
數據載荷:O到65535字節。
(2)、分段和重組
分段是指將L2CAP PDU分割成衆多較小的分組並傳給下層協議。而重組則是將底層協議傳來的數據分組重新組合成L2CAP PDU的過程。分段和重組(SAR)操作用於支持最大傳輸單位(MTU),以提高傳輸效率。這樣可以有效的降低擁塞。
由於L2CAP層不存在有關BB PDU的信息,更不瞭解它的傳輸分組長度,所以L2CAP本身並不完成低層PDU的分段和重組,一般SAR在HCI層完成。L2CAP通過在PDU中提供L2CAP PDU的長度信息,使重組機制得以檢查出是否已正確
重組了PDU(HCI層根據數據HCI—PDU中的Flags字段進行L2C川P-PDU的重組,該字段指示L2CAP—PDU的分片是開始還是繼續),從而使分段和重組更方便。
分組過程在下圖中已經給出,而重組的過程就是分組的逆過程。
 

分段和重組過程實例
(3)、L2CAP程序設計
L2CAP作爲適配層,在藍牙主機一段承擔了鏈路管理的任務。凼此,L2CAP程序璺完成藍牙鏈路的建立及斷肝等鏈路管理工作。同時,L2CAP是RFCOMM和SDP的傳輸層協議,他還應該爲這兩層協議提供數據傳輸的接VI。BlueZ爲L2cAP層封裟了標準socket接口。因此,L2cAP層同樣將採用C/S模式。與HCI層的C/S模型一樣,L2CAP層同樣足由本地藍牙設備充當客戶端.由遠程藍牙設備完成服務器的功能。L2CAP層的所有接口都將是在實現了客戶端與服務器連接的前提下進行的,下面將先介紹連接的建立。
(1)L2CAP客戶端編程
L2CAP的客戶端程序的整體流程就是圖3.2中所描述的客戶端的部分,只是其中所調用的函數要按照L2CAP層的需要進行設置。首先,將介紹socket中一個表示socket地址的結構:
 

 

 

調用socket(PF_BLUETOOTH,SOCK_RAW,BTPROTO,BTPROTO-_L2CAP),創建基於L2CAP協議的socket。而後將本地藍牙地址作爲參數,調用bind()將其與本地的藍牙適配器進行綁定。接下來設置遠程藍牙設備(服務器)的sockaddr_12結構,並調用通過cormect0函數向遠程藍牙設備提出連接請求。連接建立之後,對數據的發送和接收緩衝區進行初始化,之後可以利用read()和write0函數實現與服務器的數據接收和發送。
(2)L2CAP服務器
服務器端,調用的socket()的參數與客戶端形同。當程序進入listen0之後,當接收到數據後,主程序將創建一個receiver thread()線程完成數據的讀入和處理。而主程序將繼續進行偵聽,等待接收新的數據。
(4)、GAP剖面程序設計
GAP剖面爲藍牙的普通接入剖面,完成後續所有藍牙服務的設備基本信息設置和鏈路創建功能。GAP剖面是基於HIC協議和L2CAP協議共同完成的。其中的很多功能都是通過HCI層的接口完成的。GAP剖面主要爲下面幾個方面提供UI:
(1)藍牙設備地址bd_addr;
(2)藍牙設備名稱dev_name;
(3)藍牙密碼PIN;
(4)藍牙設備類型dev_class。
同時,還應提供藍牙連接的建立、拆除,藍牙設備的綁定等功能。GAP的功能是調用HCI和L2CAP層的接口共同完成的。其功能模塊如下圖。

 

 

設備信息:利用HCI層中的接口完成對本地和遠程設備名稱和設備類型的讀取和設置。而設備類型是一個有三個字節長的數組組成。其中共包含着三項內容:服務類型、設備大類和設備子類。設備大類用於區別設備是屬於電話、計算機、打印機或者輸入設備等。而設備子類用於區別同一類設備中的不同產品,如計算機中的PC機,筆記本電腦等。而服務類型表示着設備可提供的服務種類。這個24bits的信息並不是按照3個字節劃分的。從高到底分別是11 bits的服務類型碼(每一位表示一種服務,若該位被置位,則表示測設備可以提供這種服務),5bits設備大類,6bits設備小類和兩個爲0的格式類型。程序中存儲了設備類型的類表,可根據具體數值進行查詢。
設備配對:設備配對(Pairing)是藉助PIN在兩個藍牙設備之間建立一種安全關係的應用。在GAP應用中,利用HCI層的PIN_Code_Request_Reply命令進行PIN碼傳遞的。GAP應用程序響應PIN Code Request,提醒用戶進行PIN碼輸入,而後由用戶輸入PIN碼。輸入的PIN碼必須和另一藍牙主機端的一致,否則無法建立配對關係。
設備連接:這個模塊完成的是藍牙連接的建立和撤銷。建立藍牙連接的過程與L2CAP客戶端和服務器建立連接的方法基本相同。只是在程序中要通過調用setsockopt0和L2CAP_LM參數對藍牙進行鏈路配置。建立連接後調用getsoekopt0對12cap_options和12cap_conninfo結構進行填充。這兩個結構中存儲着L2CAP鏈路的參數。
 

btping命令:實際上應該是12ping,是利用L2CAP的迴應請求命令L2CAP_ECHO_RSP和迴應應答命令L2CAP_ECHO_REQ實現的用於鏈路測試的命令。他與操作系統中用於網絡測試的命令ping功能一樣。Ping命令以遠程主機的IP地址作爲參數,而btping以其bd addr作爲參數。其他功能基本一致。
模式設置:模式設置主要針對的是藍牙設備的發現模式,連接模式和配對模式等三項模式進行的。其中,連接模式和配對模式都僅有“可以"和“不可以"兩種模式。而發現模式則提供了不可發現、有限可發現和普通可發現三種。這些設置也是通過調用HCI層的函數完成。
4 藍牙RFCOMM協議編程概述
RFCOMM協議是基於L2CAP協議的串口仿真協議,旨在提供一個類似9針RS232的仿真串口。本文涉及的LAP和DUN應用都建立在這一層的基礎之上。BlueZ同樣也定義了這一層的標準socket接口。下面將先對RFCOMM協議進行簡要介紹。
(1)、RFCOMM協議概述
RFCOMM協議是基於ETSI標準的TS07.10的串口仿真協議。它不僅可以提供兩個藍牙設備間的多串口仿真,同時也支持多個藍牙設備之間的串口仿真。下圖給出了RFCOMM的參考模型。
 

上圖中各要素的功能描述如下:
應用:採用串口通信的程序;
端口仿真實體:端口仿真實體將特定系統通信接口映射到RFCOMM服務。端口仿真實體和RFCOMM構成一個端口驅動器;
服務註冊/發現:在本地註冊服務信息。併爲遠程查詢者提供服務查詢結果。
L2CAP:協議複用和SAR;
基帶:藍牙規範的基帶協議。
(2)、RFCOMM程序設計
RFCOMM層程序主要是爲上層應用提供數據接口,而沒有進行相應的實例化。本文基於對RFCOMM協議的研究,實現了RFCOMM層的基本通信功能。可利用這一層次的數據發送和接收接口實現數據的無線傳輸。使用SDP的功能完成信道查詢等任務。RFCOMM建立在L2CAP信道之上,PSM爲0x0003。
RFCOMM層編程同樣採用C/S模式。與L2CAP層的C/S模式一樣,由本地發起連接的藍牙主機充當客戶端,由遠程響應藍牙連接請求的設備充當服務器。由於程序實現的基本流程與前文所述的C/S模式的流程基本一致,所以此處只敘述不同的地方。這裏需要注意的一般有兩方面,一個是結構體sockaddr_rc的配置,一個是端口的綁定。
 

前兩項的意義與前文一致。由於在一個RFCOMM會話上可以建立60路連接,每路連接都有自己的信道號。因此,在建立連接時,準確填寫這個參數是連接實現的前提。在程序中,設計了get_channeloi函數用於獲得目標設備所使用的信道號。這裏取得的連接就是後來要綁定的目標。也就是說,所有的RFCOMM Socket都應該與RFCOMM的一個信道綁定。
5 藍牙SDP協議編程概述
SDP,即服務發現協議(Service Discovery Protocol)。服務發現是大多數通信系統都具有的功能。它的存在能保證基於同一通信協議的陌生設備間互相瞭解對方的功能,並列出兩者之間可以採用的通信方式。藍牙協議棧中的SDP是與RFCOMM協議處於同一層面的協議,爲用戶提供藍牙應用的服務查詢。
(1)、SDP  C /S結構
與RFCOMM協議一樣,SDP協議也是以L2CAP爲傳輸層協議的,並採用C/S模式實現應用(如圖3.16)。
 

一般來說,藍牙設備應該可以充當SDP C/S結構中的任意一端。一般來說,SDP服務由運行在本地設備上的SDP客戶端發起。它通過L2CAP協議實現連接和數據傳遞,從而與運行在遠程設備上的SDP服務器完成通信。SDP服務器在遠程設備上維護着一個服務記錄數據庫,記錄着該設備可以提供的藍牙服務的服務屬性。由於服務記錄數據庫和SDP服務器都運行於同一藍牙設備中,因此藍牙協議下的服務發現不需要藉助第三方設備便可以完成,這給藍牙應用的簡化提供了便利的條件。
(2)、服務記錄和服務屬性
SDP服務器維護的SDP數據庫就是由很多個“服務記錄"組成的。服務器將通過服務記錄句柄訪問這些服務記錄。服務記錄句柄列表中包含着多個長度爲32bits的服務記錄句柄。服務記錄句柄與服務記錄呈一一對應關係。而且,服務句柄將依據SDP服務器的不同而不同。服務屬性是用於描述某一服務特徵的。服務屬性由屬性ID和屬性值組成。屬性ID是一個16bits的無符號整數,用於定義服務類型。而屬性值則是一個與屬性ID關聯的長度不確定的數據段。
(3)、數據表示
SDP協議將屬性值用一種很巧妙的方式進行表示,滿足了它不定長的特點。一個數據元有數據段和報文頭組成。報文頭由類型描述符,元素尺寸索引和元素尺寸組成。其具體對應規則請參見參考文獻l、2、4、5和16等。在此僅給出一個簡單的例子。參見圖3.20。
 

(4)、服務搜索
當SDP客戶端與遠程設備上的SDP服務器完成了前期的L2CAP連接後,SDP客戶端便可以在遠程SDP服務器上完成相應的查詢。查詢過程如下:
 

Stepl.服務搜索請求。
客戶端向服務器發送SDP ServiceSearchRequest,其包含的第一個參數是ServiceSearchPattem,他是一個數據元序列。而其中的每一個數據元都是一個UUID(Universally Unique Identifiers,通用唯一標識符)。服務器會將這個表中的UUID值與其維護的服務記錄表匹配。如果某一UUID匹配成功說明這個UUID對應的服務是服務器具備的,否則將是不可用的應用。UUID在所有可以使用的區域內永遠是唯一的。UUID是一個長128bRs的定位符,用於表示一種服務。SDP就是通過UUID實現對不同服務的區分和匹配
Step 2.服務搜索應答。
當遠程設備上的服務器接到客戶端發來的SDP 後,將以.ServiceSearchRequestSDP ServiceSearchResponse數據包進行恢復。這個數據包中,包含着四個參數:TotalServiceRecordCount、CurrentServiceRecordCount、ServiceRecordHandleList和ContinuationState,分別表示服務器端設備所能提供的服務總數,當前可用的服務記錄數,服務記錄句柄列表和鏈接狀態。
Step 3.服務屬性查詢請求。
在完成Step 2的操作之後,客戶端得到了服務記錄旬柄列表。而後將根據該列表裏面的旬柄值進行服務屬性查詢。客戶端會向遠程設備上的服務器發送SDP ServiceAttributeRequest,這其中就包含了服務記錄句柄。同時客戶端還會告知服務器它所需應答的最大長度、其所需服務屬性的屬性ID和連接狀態等參數。
Step 4.服務屬性查詢應答。
服務器接到SDP ServiceAttributeRequest之後,將根據客戶端要求的服務記錄句柄值和所需要服務屬性,生成應答數據包SDP_ServiceAttributeResponse。並將其發送到客戶端。
至此,一個服務查詢過程結束。
(5)、SDP程序設計
SDP程序設計是基於BlueZ的sap .和.進行的。其中提供了層_libhsdph SDP的接口函數。本文設計的SDP程序完成的是SDP客戶端的作用,主要實現的是對遠程設備的所提供的服務及其服務屬性的查詢。另外,這裏也將給出一些接口,供RFCOMM層程序調用。比如,在RFCOMM客戶端在建立RFCOMM會話時需要的信道號,就需要通過SDP程序進行讀取。而這裏的SDP剖面實際上就是SDP
程序實現的功能。
本地設備在查詢某種服務時,一般分兩步完成。第一步,設備查詢。調用HCI層函數對查詢周邊設備,獲得設備基本信息。第二步,服務檢索。利用之前搜尋的結果連接相關設備完成服務查詢。第一步設備查詢的方法在前文中已經進行了敘述,這裏不再重複。本節將重點介紹第二個步驟。服務檢索仍然可分爲兩步進行。第一步,服務查詢;第二步,查詢應答處理。在進行服務查詢時,SDP客戶端程序,應生成相應服務的UUID,並以此UUD進行搜索。其查詢流程如下:
 

查詢服務流程
圖中連接目標設備時調用的是sdp_connect()函數,這個函數建立了L2CAP連接。因此,在SDP層的編程中,要利用L2CAP的數據讀取函數完成數據的發送和接收。生成UUID的時候調用的是sdp_uuid_creat()函數,並將系統定義的UUID宏作爲參數,最後生成的是用於發送的UUID數據格式。之後的鏈表中將存取所查詢的服務和相應的服務屬性。在發送查詢請求sdp_servicesearch_attr_req()時,SDP服務器將根據查詢服務列表中的UUID進行相關設備的查詢。查詢結束後會在response_list中存儲查詢結果。這個結果將作爲服務查詢階段的結果傳遞給下一步驟的程序,作爲輸入數據使用。
程序的第二步完成對查詢數據的處理和顯示工作。在介紹數據處理方法之前,需要先對sdp_list_t、sdp_record_t和sdp_data_t等三個重要的結構加以介紹。這三個結構體描述了整個SDP查詢結果的數據結構。
 

sdp_list_t是BlueZ中定義的一個表示鏈表的結構體,他的數據元素被聲明爲void類型的指針,這樣使它可以支持多種數據格式。sdp_record_t則是一個SDP記錄的數據單元。而sdp_data_t則是SDP數據的最終數據格式。這裏用聯合的概念定義了通用變量。下面,將通過一個SPD數據結構圖說明數據處理的方法。
 

上圖中response_list鏈表中的數據均爲SDP記錄。每一個SDP記錄經過sdp_gec_access_protos()函數處理後,都會返回一個protocol sequence鏈表。這個鏈表中記錄着該設備可提供的連接方式。同時,這個鏈表的每一個節點都連接這一個protocol鏈表,這個鏈表記錄着該節點的連接方式所支持的上層協議。而protocol鏈表中的節點又都指向一個sdp_data_t類型的attribute鏈表,這裏記錄的是諸如協議類型,當前應用的端口號的屬性。因此,進行的SDP服務搜索,就是將指定的UUID值與上述數據匹配,若匹配成功證明設備具有這種功能,否則不具備。本文用了四層嵌套循環實現了這一數據結構的遍歷。另外,根據查詢的級別的不同,遍歷的層次也不禁相同。當然,在查詢時也可設定一定的查詢範圍,對不關心的服務及屬性不進行的讀取,這樣可以節省程序運行的時間,提高效率。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章