Linux下Bluez的编程实现
2019獨角獸企業重金招聘Python工程師標準>>>
藍牙的各個協議棧的簡介?2
1.1、藍牙技術?2
1.1、藍牙協議棧?2
1.2、藍牙技術的特點?4
1.2.1、藍牙協議棧體系結構?4
1.2.2、藍牙協議棧低層模塊?5
1.2.3、軟件模塊?5
1.3、藍牙的一些Profile 6
2、Bluez和D-Bus 8
2.1、Bluez和D-Bus體系結構?8
2.2、D-Bus介紹?10
2.3、Bluez的安全接口?14
2.4、Bluez適配器接口?19
2.5、Bluez配對?19
2.6、Bluez綁定?20
3、Bluez編程實現?21
3.1、藍牙開發關鍵技術剖析?21
3.1.1、連接機制分析?21
3.1.2、自動連接?21
3.1.3、時鐘設計?22
3.1.4、配對列表管理?23
3.1.5、藍牙文件傳輸模式?23
3.2、hci層介紹?23
3.2.1、hci層介紹?23
3.2.2、hci層編程?24
3.3、L2CAP層編程?28
3.3.1、L2CAP協議簡介?28
3.3.2、L2CAP編程方法?29
3.4、SDP協議簡介?30
4、Openobex 31
4.1、Openobex簡介?31
4.2、Openobex與bluez編程實現?33
Obexftp 35
5.1、obexftp簡介?35
5.2、基于Obexftp的應用程序開發?35
6、參考資料?35
?
藍牙的各個協議棧的簡介
1.1、藍牙技術
??藍牙(Bluetooth)技術是由Ericsson、IBM、Intel、Nokia和Toshiba公司于1998年5月共同提出開發的,并聯合成立了藍牙特殊利益小組(SIG),負責開發無線協議規范并設定交互操作的需求。其本質是設備間的無線鏈接,意在于代替有線電纜。
1.1、藍牙協議棧
協議棧是指一組協議的集合,舉個例子,把大象裝到冰箱里,總共要3步。每步就是一個協議,3步組成一個協議棧。把應用層數據包發出去,也要好幾步,TCP/UDP頭,IP頭,ether頭,每步也是一個協議。另外每層都有一些特殊的協議。所有這些統稱協議棧。藍牙協議棧就是SIG定義的一組協議的規范,目標是允許遵循規范的藍牙應用能夠進行相互間操作,如圖1.1藍牙協議棧
?
圖1.1?藍牙協議棧
在藍牙協議體系中,底層、中間層、應用層按序排列構成了藍牙協議棧,如左圖所示。底層(硬件層)和中間協議層(軟件層)之間?的接口使用主機控制器接口(HCI)。HCI是軟硬件之間必不可少的接口,其功能是解釋并傳遞兩層之間的消息和數據。軟件通過HCI調用底層LMP/BB和RF等硬件。HCI以下的功能由藍牙設備實施;HCI以上的功能由軟件運行,在主機上實現。HCI對于上、下兩層數據的傳輸都是透明的。
在藍牙協議棧中,最主要的是藍牙核心協議,包括基帶協議(BP)、鏈路管理協議(LMP)、鏈接控制和適配協議(L2CAP)、服務發現協議(SDP)等。藍牙設備基本上都需要核心協議,其他協議則按藍牙設備的需要而選定。
?
1.2、藍牙技術的特點
1.2.1、藍牙協議棧體系結構
整個藍牙協議體系結構可分為底層硬件模塊、中間協議層和高端應用層三大部分。鏈路管理層(LMP)、基帶層(BBP)和藍牙無線電信道構成藍牙的底層模塊。BBP層負責跳頻和藍牙數據及信息幀的傳輸。
LMP層:負責連接的建立和拆除以及鏈路的安全和控制,它們為上層軟件模塊提供了不同的訪問人口,但是兩個模塊接口之間的消息和數據傳遞必須通過藍牙主機控制器接口的解釋才能進行。也就是說,中間協議層包括邏輯鏈路控制與適配協議(L2CAP)、服務發現協議(SDP)、串口仿真協議(RFCOMM)和電話控制協議規范(TCS)。
L2CAP:完成數據拆裝、服務質量控制、協議復用和組提取等功能,是其他上層協議實現的基礎,因此也是藍牙協議棧的核心部分。
SDP:為上層應用程序提供一種機制來發現網絡中可用的服務及其特性。在藍牙協議棧的最上部是高端應用層,它對應于各種應用模型的剖面,是剖面的一部分。目前定義了13種剖面。
1.2.2、藍牙協議棧低層模塊
藍牙的低層模塊是藍牙技術的核心,是任何藍牙設備都必須包括的部分。
藍牙工作在2.4GHZ的ISM頻段。采用了藍牙結束的設備講能夠提供高達720kbit/s?的數據交換速率。
藍牙支持電路交換和分組交換兩種技術,分別定義了兩種鏈路類型,即面向連接的同步鏈路(SCO)和面向無連接的異步鏈路(ACL)。
為了在很低的功率狀態下也能使藍牙設備處于連接狀態,藍牙規定了三種節能狀態,即停等(Park)狀態、保持(Hold)狀態和呼吸(Sniff)狀態。這幾種工作模式按照節能效率以升序排依次是:Sniff模式、Hold模式、Park模式。
藍牙采用三種糾錯方案:1/3前向糾錯(FEC)、2/3前向糾錯和自動重發(ARQ)。前向糾錯的目的是減少重發的可能性,但同時也增加了額外開銷。然而在一個合理的無錯誤率環境中,多余的投標會減少輸出,故分組定義的本身也保持靈活的方式,因此,在軟件中可定義是否采用FEC。一般而言,在信道的噪聲干擾比較大時藍牙系統會使用前向糾錯方案,以保證通信質量:對于SCO鏈路,使用1/3前向糾錯;對于ACL鏈路,使用2/3前向糾錯。在無編號的自動請求重發方案中,一個時隙傳送的數據必須在下一個時隙得到收到的確認。只有數據在收端通過了報頭錯誤檢測和循環冗余校驗(CRC)后認為無錯時,才向發端發回確認消息,否則返回一個錯誤消息。
藍牙系統的移動性和開放性使得安全問題變得及其重要。雖然藍牙系統所采用的調頻技術就已經提供了一定的安全保障,但是藍牙系統仍然需要鏈路層和應用層的安全管理。在鏈路層中,藍牙系統提供了認證、加密和密鑰管理等功能。每個用戶都有一個個人標識碼(PIN),它會被譯成128bit的鏈路密鑰(Link Key)來進行單雙向認證。一旦認證完畢,鏈路就會以不同長度的密碼(Encryphon Key)來加密(此密碼以shit為單位增減,最大的長度為128bit)鏈路層安全機制提供了大量的認證方案和一個靈活的加密方案(即允許協商密碼的長度)。當來自不同國家的設備互相通信時,這種機制是極其重要的,因為某些國家會指定最大密碼長度。藍牙系統會選取微微網中各個設備的最小的最大允許密碼長度。例如,美國允許128bit的密碼長度,而西班牙僅允許48bit,這樣當兩國的設備互通時,將選擇48bit來加密。藍牙系統也支持高層協議棧的不同應用體內的特殊的安全機制。例如兩臺計算機在進行商業卡信息交流時,一臺計算機就只能訪問另一臺計算機的該項業務,而無權訪問其他業務。藍牙安全機制依賴PIN在設備間建立信任關系,一旦這種關系建立起來了,這些PIN就可以存儲在設備中以便將來更快捷地連接。
1.2.3、軟件模塊
L2CAP是數據鏈路層的一部分,位于基帶協議之上。L2CAP向上層提供面向連接的和無連接的數據服務,它的功能包括:協議的復用能力、分組的分割和重新組裝(Segmentation And Reaassembly)以及提取(Group Abstraction)。L2CAP允許高層協議和應用發送和接受高達64K Byte的數據分組。
SDP為應用提供了一個發現可用協議和決定這些可用協議的特性的方法。藍牙環境下的服務發現與傳統的網絡環境下的服務發現有很大的不同,在藍牙環境下,移動的RF環境變化很大,因此業務的參數也是不斷變換的。SDP將強調藍牙環境的獨特的特性。藍牙使用基于客戶/服務器機制定義了根據藍牙服務類型和屬性發現服務的方法,還提供了服務瀏覽的方法。
RFCOMM是射頻通信協議,它可以仿真串行電纜接口協議,符合ETSI0710串口仿真協議。通過RFCOMM,藍牙可以在無線環境下實現對高層協議,如PPP、TCP/IP、WAP等的支持。另外,RFCOMM可以支持AT命令集,從而可以實現移動電話機和傳真機及調制解調器之間的無線連接。
藍牙對語音的支持是它與WLAN相區別的一個重要的標志。藍牙電話控制規范是一個基于ITU-T建議Q.931的采用面向比特的洗衣,它定義了用于藍牙設備間建立語音和數據呼叫的呼叫控制信令以及用于處理藍牙TCS設備的移動性管理過程。
1.3、藍牙的一些Profile
藍牙里面profile的定義,profile既是配置文件,配置文件定義了可能的應用,藍牙配置文件表達了一般行為,藍牙設備可以通過這些行為與其它設備進行通信。藍牙技術定義了廣泛的配置文件,描述了許多不同類型的使用案例。按照藍牙規格中提供的指導,開發商可以創建應用程序以與其它符合藍牙規格的設備協同工作。 到目前為止,藍牙一共有22個profile,在www.bluetooth.com§上有詳細的文檔說明。
已經實現了的協議棧:
Widcomm:?第一個windows上的協議棧,由Widcomm公司開發,也就是現在的Broadcom .
Microsoft Windows stack: Windows XP SP2中包括了這個內建的協議棧,開發者也可以調用其API開發第三方軟件。
Toshiba stack:?它也是基于Windows的,不支持第三方開發,但它把協議棧授權給一些laptop商)。它支持的Profile有:?SPP, DUN, FAX, LAP, OPP, FTP, HID, HCRP, PAN, BIP, HSP, HFP , A2DP, AVRCP, GAVDP)
BlueSoleil:?著名的IVT公司的產品,這個應該是個中國公司。該產品可以用于桌面和嵌入式,他也支持第三方開發,DUN, FAX, HFP, HSP, LAP, OBEX, OPP, PAN SPP, AV, BIP, FTP, GAP, HID, SDAP, and SYNC。
Bluez: Linux官方協議棧,該協議棧的上層用Socket封裝,便于開發者使用,通過DBUS與其它應用程序通信。
Affix: NOKIA公司的協議棧,在Symbian系統上運行。
BlueDragon:東軟公司產品,支持的Profile:SDP、Serial-DevB、AVCTP、AVRCP-Controller、AVRCP-Target、Headset-AG、Headset-HS、OPP-Client、OPP-Server、CT-GW、CT-Term、Intercom、FT-Server、FT-Client、GAP、SDAP、Serial-DevA、AVDTP、GAVDP、A2DP-Source、A2DP-Sink。
BlueMagic:美國Open Interface?公司for portable embedded divce的協議棧,iphone(apple),nav-u(sony)等很多電子產品都用該商業的協議棧,BlueMagic 3.0是第一個通過bluetooth?協議棧1.1認證的協議棧,那么我現在就在用它,那么該棧用起來簡單,API清晰明了。實現了的profile有:HCI,L2CAP,RFCOMM,A/V,Remote,Control,A/V,Streaming,BIP,BPP,DUN,FAX,FTP,GAP,Hands-Free,and,Headset,HCRP,HID,OBEX,OPP,PAN,BNEP,PBAP,SAP,SPP,Synchronization,SyncML,Telephony,XML.
BCHS-Bluecore Host Software:?藍牙芯片CSR的協議棧,同時他也提供了一些上層應用的Profile的庫。
Windows CE:微軟給Windows CE開發的協議棧,但是windows ce本身也支持其它的協議棧。
BlueLet:IVT公司for embedded product的清量級協議棧。
2、Bluez和D-Bus
2.1、Bluez和D-Bus體系結構
?
The?BlueZ?D-Bus?interfaces aim to provide seamless Bluetooth technology integration into the desktop. A central Bluetooth daemon "hcid"(planned to be renamed to bluetoothd) is responsible for take care of all tasks that can’t or shouldn’t be handled inside the Linux kernel. These jobs include PIN code and link key management for the authentication and encryption, caching of device names and services and also central control of the Bluetooth hardware. The interface exported allows to abstract the internals of GNOME, KDE,Maemo,?OpenMoko, ... applications from any technical details of the Bluetooth specification. Even other application will get access to the Bluetooth technology without any hassle.
Bluez和D-bus接口,提供了藍牙技術和桌面系統的完美集成。藍牙的中心守護進程hcid的職責就是處理那些不能被linux內核處理的任務,包括處理為鑒權和加密過程中需要的PIN碼和密鑰、緩存設備的名稱和服務類型,同時也是藍牙硬件的控制中心。
The BlueZ?D-Bus?services are exported through the system message bus. Every D-Bus enabled desktop has a system message bus instance running. This bus is used to broadcast system events, such as new hardware devices, network connection status, and so forth. The session message bus is not suitable for this architecture since the Bluetooth hardware/connections are shared by all desktop sessions.
Bluez和D-bus服務通過系統消息總線提供。每個D - Bus使桌面有一個系統消息總線實例運行。這個bus是用來廣播系統時間,如新的硬件設備、網絡連接狀態等等。會話消息總線對這種體系結構是不適合的,因為藍牙硬件/連接被所有桌面會話共享。
The BlueZ D-Bus Architecture goal are:
-
Abstract Bluetooth HCI commands/events。
-
Provide an easy interface to setup Bluetooth adapter and manage the services
Bluez和D-bus體系結構的目標:
-
抽象hci層命令和事件。
-
提供簡單的接口來啟動藍牙適配器和管理藍牙服務。
The hcid is the main entity of the architecture. It implements methods to setup the Bluetooth adapters, retrieve remote device properties, control the pairing procedure and control the services registration/searches. The following figure shows a high level relationship between the entities.
Hcid是該體系結構的主體。它實現啟動藍牙適配器的方法、獲取遠端設備屬性、控制配對過程和控制服務的注冊和搜索。下圖顯示了一個高層次的實體之間的關系。
?
2.2、D-Bus介紹
什么是D-Bus?
D-BUS?是一種進程間通信的方式,從架構上來說,分為三層:
一個庫,libdbus,允許2個進程間交換信息。
一個消息總線守護進程, 它使用libdbus庫。其他進程都可以與它連接。它可以將消息從一個進程發給另外任意數量的其他進程。現在有一些基于特定應用框架的dbus庫函數封裝,例如libdbus-glib?和libdbus-qt,也有與一些語言綁定的形式,例如Python等。這些封裝的API旨在令D-BUS編程更加簡單,libdbus傾向于提供更低層次的調用。很多libdbus API只在綁定的組件中可用。
libdbus僅支持一對一的連接,就像原始?socket通訊方式一樣。但它傳遞的不是以字節為單位的數據流,而是具有一定意義的消息包。消息的消息頭部表示消息種類,消息體用來裝載數據。Libdbus也可以允許實現特定的傳輸通道,從而來完成比如像認證之類的應用細節(libdbus also abstracts the exact transport used (sockets vs. whatever else), and handles details such as authentication.)。
消息總線守護進程將D-bus上連接的所有程序構成一個輪形hub。Libdbus為中心,它和應用程序建立一對一的連接。每個應用程序通過通道發送消息到消息總線,然后總線進程將消息轉發到其他連接到hub的應用程序。可以把消息總線理解為一個路由器。Dbus服務在一個操作系統中存在多個進程。第一個進程是一個全局進程,就如sendmail?或Apache?的系統守護進程一樣。這個進程具有高度的安全限制,一般用于系統進程間的通訊。其他的dbus進程都是用戶進程,針對于每個登錄的用戶建立。這些實例允許用戶會話中的應用程序相互通信。Dbus全局進程和用戶進程是相互獨立的,他們并沒有內在的依賴關系。
D-Bus應用
有很多種IPC或者網絡通信系統,如:CORBA,DCE,DCOM,DCOP,XML-RPC,SOAP,MBUS,ICE等。Dbus的目的主要是下面兩點:
在同一個桌面會話中,進行桌面應用程序之間的通訊。
桌面程序和內核或者守護進程之間通信。
D-Bus概念
對象路徑(Native Objects and Object Paths):D-Bus的底層接口,和libdbus相關,它提供一種叫對象路徑(object path),用于讓高層接口綁定到各個對象中去,允許遠端應用程序指向他們。Object path就像一個文件路徑。
方法和信號(Methods and Signals):每個對象都有一些成員,有兩種成員:方法(methods)和信號(signals),在對象中,方法可以被調用。信號會被廣播,感興趣的對象可以處理這個信號,同時信號中也可以帶有相關的數據。
接口(Interfaces):每個對象都有一個或者多個接口,一個接口就是多個方法和信號的集合。這個概念和Glib, Qt或者Java中的是一致的。接口定義了對象實例的類型。dbus使用簡單的命名空間字符串來表示接口,如org.freedesktop.Introspectable。可以說dbus接口相當于C++中的純虛類。
代理(Proxies):使用代理對象就是讓調用者感覺在直接使用遠程對象一樣。d-bus的底層接口完成了一些比較低級和繁瑣的調用過程,比如必須先調用創建方法形成消息包,然后發送,然后等待接受和處理返回的消息。所以,高層的接口就可以使用代理對象提供的接口屏蔽這些細節。所以,當調用代理對象的方法時,代理內部會轉換成dbus的方法調用,等待消息返回,對返回結果解包,返回給相應的方法。可以看看下面的例子,使用dbus底層接口編寫的代碼:
Message message = new Message(”/remote/object/path”, “MethodName”, arg1, arg2);
Connection connection = getBusConnection();
connection.send(message);
Message reply = connection.waitForReply(message);
if (reply.isError()) {
} else {
Object returnValue = reply.getReturnValue();
}
使用代理對象編寫的代碼:
Proxy proxy = new Proxy(getBusConnection(), “/remote/object/path”);
Object returnValue = proxy.MethodName(arg1, arg2);
客戶端代碼減少很多。
總線名稱(Bus Names):當一個應用程序連接上bus daemon時,daemon會分配一個唯一的名字給它。以冒號(:)開始,這些名字在daemon的生命周期中是不會改變的,可以認為這些名字就是一個?IP地址。當這個名字映射到應用程序的連接上時,應用程序可以說擁有這個名字。同時應用可以聲明額外的容易理解的名字,比如可以取一個名字?com.mycompany.TextEditor,可以認為這些名字就是一個域名。其他應用程序可以往這個名字發送消息,執行各種方法。
名字還有第二個重要的用途,可以用于跟蹤應用程序的生命周期。當應用退出(或者崩潰)時,與bus的連接將被OS內核關掉,bus將會發送通知,告訴剩余的應用程序,該程序已經丟失了它的名字。名字還可以檢測應用是否已經啟動,這可以用來實現單實例啟動程序。
地址(Addresses):使用d-bus的應用程序既可以是server也可以是client,server監聽到來的連接,client連接到server,一旦連接建立,消息就可以流轉。如果使用dbus daemon,所有的應用程序都是client,daemon監聽所有的連接,應用程序初始化連接到daemon。dbus地址指明server將要監聽的地方,client將要連接的地方,例如,地址:unix:path=/tmp/abcdef表明?server將在/tmp/abcdef路徑下監聽unix域的socket,client也將連接到這個socket。一個地址也可以指明是TCP /IP的socket,或者是其他的。
當使用bus daemon時,libdbus會從環境變量中(DBUS_SESSION_BUS_ADDRESS)自動認識“會話daemon”的地址。如果是系統?daemon,它會檢查指定的socket路徑獲得地址,也可以使用環境變量(DBUS_SESSION_BUS_ADDRESS)進行設定。當dbus中不使用daemon時,需要定義哪一個應用是server,哪一個應用是client,同時要指明server的地址,這不是很通常的做法。
D-bus工作原理
Calling a Method – Behind the Scenes
在dbus中調用一個方法包含了兩條消息,進程A向進程B發送方法調用消息,進程B向進程A發送應答消息。所有的消息都由daemon進行分派,每個調用的消息都有一個不同的序列號,返回消息包含這個序列號,以方便調用者匹配調用消息與應答消息。調用消息包含一些參數,應答消息可能包含錯誤標識,或者包含方法的返回數據。
方法調用的一般流程:
1.使用不同語言綁定的dbus高層接口,都提供了一些代理對象,調用其他進程里面的遠端對象就像是在本地進程中的調用一樣。應用調用代理上的方法,代理將構造一個方法調用消息給遠端的進程。
2.在DBUS的底層接口中,應用需要自己構造方法調用消息(method call message),而不能使用代理。
3.方法調用消息里面的內容有:目的進程的bus name,方法的名字,方法的參數,目的進程的對象路徑,以及可選的接口名稱。
4.方法調用消息是發送到bus daemon中的。
5.bus daemon查找目標的bus name,如果找到,就把這個方法發送到該進程中,否則,daemon會產生錯誤消息,作為應答消息給發送進程。
6.目標進程解開消息,在dbus底層接口中,會立即調用方法,然后發送方法的應答消息給daemon。在dbus高層接口中,會先檢測對象路徑,接口,方法名稱,然后把它轉換成對應的對象(如GObject,QT中的QObject等)的方法,然后再將應答結果轉換成應答消息發給daemon。
7.bus daemon接受到應答消息,將把應答消息直接發給發出調用消息的進程。
8.應答消息中可以包容很多返回值,也可以標識一個錯誤發生,當使用綁定時,應答消息將轉換為代理對象的返回值,或者進入異常。
bus daemon不對消息重新排序,如果發送了兩條消息到同一個進程,他們將按照發送順序接受到。接受進程并需要按照順序發出應答消息,例如在多線程中處理這些消息,應答消息的發出是沒有順序的。消息都有一個序列號可以與應答消息進行配對。
Emitting a Signal – Behind the Scenes
在dbus中一個信號包含一條信號消息,一個進程發給多個進程。也就是說,信號是單向的廣播。信號可以包含一些參數,但是作為廣播,它是沒有返回值的。
信號觸發者是不了解信號接受者的,接受者向daemon注冊感興趣的信號,注冊規則是”match rules”,記錄觸發者名字和信號名字。daemon只向注冊了這個信號的進程發送信號。
信號的一般流程如下:
當使用dbus底層接口時,信號需要應用自己創建和發送到daemon,使用dbus高層接口時,可以使用相關對象進行發送,如Glib里面提供的信號觸發機制。
信號包含的內容有:信號的接口名稱,信號名稱,發送進程的bus name,以及其他參數。
任何進程都可以依據”match rules”注冊相關的信號,daemon有一張注冊的列表。
daemon檢測信號,決定哪些進程對這個信號感興趣,然后把信號發送給這些進程
每個進程收到信號后,如果是使用了dbus高層接口,可以選擇觸發代理對象上的信號。如果是dbus底層接口,需要檢查發送者名稱和信號名稱,然后決定怎么做。
2.3、Bluez的安全接口
pin_helper concept has been removed starting with bluez-utils 3.X. and has been replaced with a feature called passkey agents. An application that wants to handle passkey requests must use the "hcid" security interface to register a passkey agent. Currently, two types of passkey agents are supported: default and device specific. A "specific" passkey agent handles all passkey requests for a given remote device while a default handles all requests for which a specific agent was not found. "specific" passkey agents are useful to address pre-defined passkey values or environments where the user interaction is not allowed/difficult.
When the?CreateBonding?method is called the "hcid" daemon will verify if there is a link key stored in the file system. If it is available an error is returned, and if not, a D-Bus message is sent to the registered passkey agent asking for a passkey.
Each Passkey Agent is represented by a D-Bus object path. The "hcid" distinguishes the agents based on their unique bus names and their object paths.
Pin_help的理念在bluez-util 3.x時已經被移除,并被密鑰代理所代替。任何想處理密鑰請求的應用程序必須使用hcid安全接口來注冊密鑰代理。現在支持兩種類型的密鑰代理:默認和設備特定。一個"特定"的密鑰代理處理所有遠端的密鑰請求,一個默認的密鑰代理,處理特定的代理所沒有發現的所有密鑰請求。"特定"的密鑰代理對處理那些和用戶交互困難或者不允許用戶交互的設備的預定義的密鑰值或環境非常有用。
當CreateBonding方法被調用時,hcid守護進程將確認當前的文件系統中是否保存了鏈接密鑰,若可以找到,就返回一個錯誤。若找不到,D-Bus消息將被發出來為密鑰請求的設備,注冊一個密鑰代理。每個密鑰代理被D-Bus對象路徑所體現,hcid依據唯一的總線名稱和對象路徑來區分代理。
Architecture
-
Step 1: Represents the passkey agent registration
-
Step 2: Represents a client calling?CreateBonding
-
Step 3: Represents the hcid asking for a passkey valu
體系結構
-
第一步:表示密鑰代理注冊
-
第二步:表示客戶調用CreateBonding
-
第三步:代表hcid請求密鑰值。
Message Flow
In the following figure, the "CreateBonding" method call is hidden. The "PIN Request" HCI event is generated when there is not a link available in the file system. In this case "Link Key Request Negative Reply" command is sent triggering the "Pin Request" event.
在下面得圖表中,CreateBonding方法的調用被隱藏。當沒有一個可用鏈接時,"PIN Request"HCI層事件被產生,在這種情況下,"Link Key Request Negative Reply"命令被發送來回應"Pin Request"?事件。
-
Step 1: Represents the D-Bus message sent to register the default/device specific passkey agent.
-
Step 2: Represents the HCI "PIN Request" event sent by the Bluetooth Host Controller.
-
Step 3: Represents the D-Bus message sent to the default/device speficic passkey agent requesting a passkey.
-
Step 4: Represents the "Auth Complete" event where the status contains "LMP Response Timeout"(The remote didn't type the passkey).
-
Step 5: Represents the "hcid" issuing a "Cancel" to a previous Request call.
-
Step 6: Represents the D-Bus message sent to release the passkey agent: basically sent when the hcid exits.
-
第一步:D-Bus發送消息來注冊默認的或者特定的密鑰代理。
-
第二步:藍牙主機控制器發送HCI?層"PIN Request"事件。
-
第三步:D-Bus發送消息到默認的或者特定的密鑰代理,請求密鑰。
-
第四步:"Auth Complete"完成事件,如果這種狀態包含"LMP Response Timeout"。
-
第五步:hcid發出“Cancel”命令給D-Bus。
-
第六步:當hcid退出時,D - Bus的信息發送到釋放密鑰代理
2.4、Bluez適配器接口
Description?
The "Adapter" interface provides methods to setup the local adapter(s), search remote devices, pairing and search for services.
This interface is considered stable and no change is planned.
For each available adapter the hcid register an adapter object instance provided in the path "/org/bluez/hci{0, 1, 2, ...}".
適配器接口提供,啟動適配器、搜索設別、配對、和搜索服務的方法。這個接口被認為是穩定的,沒有改變計劃。對每個可用的適配器,hcid為其注冊一個適配器對象實例,在路徑?"/org/bluez/hci{0, 1, 2, ...}"里。
2.5、Bluez配對
Description
Services that need ask the user to accept/reject an operation such as accept OBEX objects or accept an incoming connection can use the?Security?API to request the userspace registered authorization agent responsible.
Development warnings/recommendations
Just one Authorization request per time is allowed.
NotConnected error is returned if a connection is not found between the devices is not found.
Trusted Devices
The BlueZ daemon keeps a list of trusted devices. Trusted means that authorization is not required to accept incoming connections or other operations that need the user response. Once a given device is added to the list, the BlueZ daemon will reply authorized without call the Authorization agent.
Authorization Agent
Authorization agents are applications responsible for address authorization requests. For more information check the BlueZ D-Bus API and implementation references:
-
utils/daemon/auth-agent.c is a authorization agent implementation able to handle device specific and default
-
bluez-gnome?passkey/authorization agent implementation distributed by the BlueZ community
Canceling
For security reason, only the requestor can cancel a pending authorization operation.
2.6、Bluez綁定
Description
The purpose of bonding is to create a relation between two Bluetooth devices based on a common link key (a bond). The link key is created and exchanged(pairing) during the bonding procedure and is expected to be stored by both Bluetooth devices, to be used for future authentication[definition from Bluetooth Core Spec].
The Bonding procedure is done through the BlueZ?Adapter?interface.
Development warnings/recommendations
Just one Bonding request per time is allowed.
Bonding is not allowed if there is a discovery running.
Pending remote name is canceled if a CreateBonding message is received.
The Bonding takes some seconds, therefore it is recommended set a D-Bus callback to handle the message reply for this operation.
Passkey Agent
Currently, two types of passkey agents are supported:
Device Specific: handles all passkey requests for a given remote device
Default: Handles the remaining requests(not addressed by device specific agents)
For more information check the BlueZ D-Bus API and implementation references:
-
utils/daemon/passkey-agent.c is a passkey agent implementation able to handle device specific and default
-
bluez-gnome?passkey agent implementation distributed by the BlueZ community=
3、Bluez編程實現
3.1、藍牙開發關鍵技術剖析
3.1.1、連接機制分析
物理信道(physical channel)是藍牙系統的最底層結構,通過偽隨機跳頻序列、發送時槽定時、接入碼及幀頭編碼來表征。藍牙針對不同應用定義了一系列物理信道,包括用于匹克網內設通信的匹克網物理信道、用于尋呼設備的尋呼掃描物理信道和用于查找設備的查找掃描物理信道。兩臺設備必須采用相同的物理信道才能進行通信。
主從設備建立連接的過程就是建立相同匹克網信道的過程,該過程確保主從設備以同樣的定時和次序進行載波頻率的跳變,進行數據傳輸,同時可以根據匹克網接入碼和幀頭編碼進行數據過濾和解析,避免和其他設備在同一個頻段上的相撞。
尋呼掃描物理信道(page scan physical channel)用于主設備尋呼從設備,是設備建立連接的必經階段。尋呼掃描跳頻序列和尋呼請求幀的設備接入碼(DAC)是由從設備物理地址運算,處于可被連接模式的從設備以固定的周期(由page scan interval決定)在一個固定的時間窗(由page scan window決定)內以某個跳頻頻率監聽主設備的尋呼請求。
3.1.2、自動連接
為了方便用戶的使用,大多藍牙設備都實現了自動連接功能,根據以上對藍牙連接機制的分析,設計自動連接方案時必須考慮設備在不同的工作狀態下采用不同的物理信道和跳頻序列,而不能按照人為的邏輯隨意設置,否則會給用戶帶來不便。
以車載免提裝置為例,上電自動連接對駕駛員來說可以提高使用車載免提的自覺性,降低行車期間通話帶來的風險。采用搜索方式判斷設備是否在有效范圍內,按照優先級從低到高連接,最后一次連接的手機為優先級最高的,然后按照配對列表的逆序而優先級依次降低。鏈路丟失后的自動連接只針對最后一部手機,這樣可以實現服務的連續性。
3.1.3、時鐘設計
藍牙核心規范要求時鐘頻率精度為±20ppm,如果載波頻率不穩定,則會發生“過零點”錯誤(zero-cross)。載波頻率由本地時鐘(晶振)做為PLL的參考時鐘倍頻產生。一般說來,藍牙設備的時鐘設計便是指晶振電路的設計及微調。決定晶振工作精度的兩個重要參數是制造公差和溫度穩定度,如果選擇有源晶振作為本地時鐘,需要滿足:制造公差+溫度穩定度≤±20ppm,有源晶振內部集成晶體和相應的振蕩電路,匹配精確,頻率穩定性高,而且抗干擾性能好,缺點是成本較高。§
圖1?????震蕩電路設計
本文自行設計的振蕩電路如圖1所示。
選擇溫度穩定性高、制造公差低的高精度晶體,通過振蕩電路設計實現諧振頻率的精確調整,這是由晶體負載電容的匹配及可調實現的。負載電容是指CRY_IN和CRY_OUT兩端的電容值,在晶體的CRY_IN引腳上并聯一個可調電容,調整該電容便可以對諧振頻率進行精密微調。晶體負載電容計算公式如下:
Cload=Cint+(Cin+Ctrim)×Cout/(Cin+Ctrim+Cout)
Cint包括IC內部電容(一般為固定值)以及PCB雜散電容(3pF~5pF)。
3.1.4、配對列表管理
為了保證鏈路級的安全,藍牙通信要求設備在連接建立前進行“雙向認證”。認證成功的前提是設備雙方存儲了相同的鏈路密鑰Kab,配對是產生初始密鑰Kint的階段,Kint由PIN碼、從設備藍牙地址和主設備發給從設備的一個隨機數由一套固定的算法計算出來,只要PIN碼一致,主從設備生成的的Kint也是一致的。鏈路密鑰的輸入是主從設備的藍牙地址和主從設備各一隨機數,只要主從設備能互換隨機數,便能得到一致的Kab。主設備將隨機數RandA與Kint異或的結果發給從設備,從設備只將該結果與Kint異或便得到RandA,即
§
配對列表的管理包括添加、替代及刪除,添加配對設備是在非易失性存儲中存儲該設備的藍牙地址及Kab。刪除配對設備需要謹慎處理,如果存在連接,需要先斷開連接然后刪除,因為如果刪掉該設備而有一種應用的連接沒有斷開,會存在臨時密鑰用于當前應用,這時不經配對也可以連接上其他應用,違反了藍牙安全性要求
3.1.5、藍牙文件傳輸模式
文件傳輸的目的是使兩個終端之間的數據交換成為可能,傳輸時使用的協議如圖3.1所示,可傳送的文件有doc、jpg、ppt、xls、wav等文件,還包括遠端文件夾瀏覽功能。傳輸文件的設備可歸結成C/S結構。客戶可從服務器下載文件,或向服務器上傳文件。服務器是一種使用對象交換協議(OBEX)文件夾列表格式的遠端藍牙設備,其支持目標交換服務、文件夾瀏覽功能,還允許客戶修改、創建文件或文件夾。
3.2、hci層介紹
3.2.1、hci層介紹
Host Controller Interface(HCI)?就是用來溝通Host和Module。Host通常就是PC,?Module則是以各種物理連接形式(USB,serial,pc-card等)連接到PC上的bluetooth Dongle。HCI則比較特殊,它一部分在軟件中實現,用來給上層協議和程序提供訪問接口(Bluez中,hci.c hci_usb.c,hci_sock.c等).另一部分也是在Firmware中實現,用來將軟件部分的指令等用底層協議明白的方式傳遞給底層。
居于PC的上層程序與協議和居于Modules的下層協議之間通過HCI溝通,有4種不同形式的傳輸:Commands, Event, ACL Data, SCO/eSCO Data.。
HCI Command:HCI Command是Host向Modules發送命令的一種方式。
HCI Event:Modules向Host發送一些信息,使用HCI Event。
3.2.2、hci層編程
對本地dongle進行操作:
得到Host上插入Dongle數目以及Dongle信息
實現步驟如下:
// 0.?分配一個空間給?hci_dev_list_req。這里面將放所有Dongle信息。
struct hci_dev_list_req *dl;
struct hci_dev_req *dr;
struct hci_dev_info di;
int i;
if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t)))) {
perror("Can't allocate memory");
exit(1);
}
dl->dev_num = HCI_MAX_DEV;
dr = dl->dev_req;
//1.?打開一個HCI socket.
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
perror("Can't open HCI socket.");
exit(1);
}
// 2.?使用HCIGETDEVLIST,得到所有dongle的Device ID。存放在dl中。
if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
perror("Can't get device list");
exit(1);
}
// 3?使用HCIGETDEVINFO,得到對應Device ID的Dongle信息。
di.dev_id = (dr+i)->dev_id;
ioctl(ctl, HCIGETDEVINFO, (void *) &di);
這樣就能得到所有Dongle信息。
?
struct hci_dev_info {
uint16_t dev_id; //dongle Device ID
char name[8]; //Dongle name
?
bdaddr_t bdaddr; //Dongle bdaddr
?
uint32_t flags; //Dongle Flags:如:UP,RUNING,Down等。
uint8_t type; //Dongle連接方式:如USB,PC Card,UART,RS232等。
?
uint8_t features[8];
?
uint32_t pkt_type;
uint32_t link_policy;
uint32_t link_mode;
?
uint16_t acl_mtu;
uint16_t acl_pkts;
uint16_t sco_mtu;
uint16_t sco_pkts;
?
struct hci_dev_stats stat; //此Dongle的數據信息,如發送多少個ACL Packet,正確多少,錯誤多少,等等。
};
打開一個HCI Socket---int hci_open_dev(int dev_id)
這個function用來打開一個HCI Socket。它首先打開一個HCI protocol的Socket(房間),并將此Socket與device ID=參數dev_id的Dongle綁定起來。只有bind后,它才將Socket句柄與Dongle對應起來。
注意,所有的HCI Command發送之前,都需要使用?hci_open_dev打開并綁定。
關閉一個HCI Socket
int hci_close_dev(int dd) //簡單的關閉使用hci_open_dev打開的Socket。
向HCI Socket(對應一個Dongle)發送?request
int hci_send_req(int dd, struct hci_request *r, int to)
BlueZ提供這個function非常有用,它可以實現一切Host向Modules發送Command的功能。
參數1:HCI Socket。
參數2:Command內容。
參數3:以milliseconds為單位的timeout.
下面詳細解釋此function和用法:
當應用程序需要向Dongle(對應為一個bind后的Socket)發送Command時,調用此function.
其中,參數一dd對應一個使用hci_open_dev()打開的Socket(Dongle)。
參數三to則為等待Dongle執行并回復命令結果的timeout.以毫秒為單位。
參數二hci_request * r?最為重要,首先看它的結構:
struct hci_request {
uint16_t ogf; //Opcode Group
uint16_t ocf; //Opcode Command
int event; //此Command產生的Event類型。
void *cparam; //Command?參數
int clen; //Command參數長度
void *rparam; //Response?參數
int rlen; //Response?參數長度
};
ogf,ocf不用多說,對應前面的圖就明白這是Group Code和Command Code。這兩項先確定下來,然后可以查HCI Spec。察看輸入參數(cparam)以及輸出參數(rparam)含義。至于他們的結構以及參數長度,則在~/include/net/bluetooth/hci.h中有定義。
?
例1:得到某個連接的Policy Setting.
HCI Spec以及~/include/net/bluetooth/hci.h中均可看到,OGF=OGF_LINK_POLICY(0x02). OCF=OCF_READ_LINK_POLICY(0x0C).
因為這個Command用來讀取某個ACL連接的Policy Setting。所以輸入參數即為此連接Handle.
返回參數則包含3部分,status(Command是否順利執行),?handle(連接Handle)。?policy(得到的policy值)
這就又引入了一個新問題,如何得到某個ACL連接的Handle。
可以使用ioctl HCIGETCONNINFO得到ACL?連接Handle。
ioctl(dd, HCIGETCONNINFO, (unsigned long) cr);
Connect_handle = htobs(cr->conn_info->handle);
所以完整的過程如下:
?
struct hci_request HCI_Request;
read_link_policy_cp Command_Param;
read_link_policy_rp Response_Param;
// 1.得到ACL Connect Handle
if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0)
{
return -1;
}
Connect_handle = htobs(cr->conn_info->handle);
memset(&HCI_Request, 0, sizeof(HCI_Request));
memset(&Command_Param, 0 , sizeof(Command_Param));
memset(&Response_Param, 0 , sizeof(Response_Param));
// 2.填寫Command輸入參數
Command_Param.handle = Connect_handle;
HCI_Request.ogf = OGF_LINK_POLICY; //Command組ID
HCI_Request.ocf = OCF_READ_LINK_POLICY; //Command ID
HCI_Request.cparam = &Command_Param;
HCI_Request.clen = READ_LINK_POLICY_CP_SIZE;
HCI_Request.rparam = &Response_Param;
HCI_Request.rlen = READ_LINK_POLICY_RP_SIZE;
if (hci_send_req(dd, &HCI_Request, to) < 0)
{
perror("\nhci_send_req()");
return -1;
}
//如果返回值狀態不對
if (Response_Param.status) {
return -1;
}
//得到當前policy
*policy = Response_Param.policy;
幾個更基礎的function
static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) //bdaddr copy
static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)//bdaddr?比較
得到指定Dongle BDAddr
int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to);
參數1:HCI Socket,使用hci_open_dev()打開的Socket(Dongle)。
參數2:輸出參數,其中會放置bdaddr.
參數3:以milliseconds為單位的timeout.
讀寫Dongle Name
int hci_read_local_name(int dd, int len, char *name, int to)
int hci_write_local_name(int dd, const char *name, int to)
參數1:HCI Socket,使用hci_open_dev()打開的Socket(Dongle)。
參數2:讀取或設置Name。
參數3:以milliseconds為單位的timeout.
注意:這里的Name與IOCTL HCIGETDEVINFO?得到hci_dev_info中的name不同
得到HCI Version
int hci_read_local_version(int dd, struct hci_version *ver, int to)
得到已經UP的Dongle BDaddr
int hci_devba(int dev_id, bdaddr_t *bdaddr);
dev_id: Dongle Device ID.
bdaddr:輸出參數,指定Dongle如果UP, 則放置其BDAddr
得到BDADDR不等于參數bdaddr的Dongle Device ID
int hci_get_route(bdaddr_t *bdaddr)
?
查找Dongle,發現Dongle Bdaddr不等于參數bdaddr的第一個Dongle,則返回此Dongle Device ID。
?
所以,如果: int hci_get_route(NULL),則得到第一個可用的Dongle Device ID。
將BDADDR轉換為字符串
int ba2str(const bdaddr_t *ba, char *str)
對遠程dongle進行操作:
inquiry?遠程Bluetooth Device
int hci_inquiry(int dev_id, int len, int nrsp, const uint8_t *lap, inquiry_info **ii, long flags)
hci_inquiry()用來命令指定的Dongle去搜索周圍所有bluetooth device.并將搜索到的Bluetooth Device bdaddr?傳遞回來。
參數1:dev_id:指定Dongle Device ID。如果此值小于0,則會使用第一個可用的Dongle。
參數2:len:?此次inquiry的時間長度(每增加1,則增加1.25秒時間)
參數3:nrsp:此次搜索最大搜索數量,如果給0。則此值會取255。
參數4:lap:BDADDR中LAP部分,Inquiry時這塊值缺省為0X9E8B33.通常使用NULL。則自動設置。
參數5:ii:存放搜索到Bluetooth Device的地方。給一個存放inquiry_info指針的地址,它會自動分配空間。并把那個空間頭地址放到其中。
參數6:flags:搜索flags.使用IREQ_CACHE_FLUSH,則會真正重新inquiry。否則可能會傳回上次的結果。
返回值是這次Inquiry到的Bluetooth Device?數目。
注意:如果*ii不是自己分配的,而是讓hci_inquiry()自己分配的,則需要調用bt_free()來幫它釋放空間。
得到指定BDAddr的reomte device Name
int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to)
參數1:使用hci_open_dev()打開的Socket。
參數2:對方BDAddr.
參數3:name?長度。
參數4:(out)放置name的位置。
參數5:等待時間。
讀取連接的信號強度
int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to)
注意,所有對連接的操作,都會有一個參數,handle.這個參數是連接的Handle。?前面講過如何得到連接Handle的。
3.3、L2CAP層編程
3.3.1、L2CAP協議簡介
Logical Link Control and Adaptation Protocol(L2CAP)邏輯連接控制和適配協議為上層協議提供面向連接和無連接的數據服務,并提供多協議功能和分割重組操作。L2CAP?充許上層協議和應用軟件傳輸和接收最大長度為?64K?的L2CAP?數據包。
L2CAP?基于通道(channel)?的概念。 通道?(Channel)?是位于基帶?(baseband)?連接之上的邏輯連接。每個通道以多對一的方式綁定一個單一協議?(single protocol)。多個通道可以綁定同一個協議,但一個通道不可以綁定多個協議。 每個在通道里接收到的?L2CAP?數據包被傳到相應的上層協議。 多個通道可共享同一個基帶連接。也就是說,所有L2CAP數據均通過HCI傳輸到Remote Device。且上層協議的數據,大都也通過L2CAP來傳送。L2CAP可以發送Command。例如連接,斷連等等。
3.3.2、L2CAP編程方法
L2CAP編程非常重要,它和HCI基本就是Linux Bluetooth編程的基礎了。幾乎所有協議的連接,斷連,讀寫都是用L2CAP連接來做的。
1.創建L2CAP Socket
socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
domain=PF_BLUETOOTH, type可以是多種類型。protocol=BTPROTO_L2CAP.
2.綁定:
// Bind to local address
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(&addr.l2_bdaddr, &bdaddr); //bdaddr為本地Dongle BDAddr
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Can't bind socket");
goto error;
}
3.連接
?
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(addr.l2_bdaddr, src);
addr.l2_psm = xxx;
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Can't connect");
goto error;
}
?
注意:
struct sockaddr_l2 {
sa_family_t l2_family; //必須為?AF_BLUETOOTH
unsigned short l2_psm; //與前面PSM對應,這一項很重要
bdaddr_t l2_bdaddr; //Remote Device BDADDR
unsigned short l2_cid;
};
4.?發送數據到Remote Device:
send()或write()都可以。
5.?接收數據:
revc()?或read()
以下為實例:
注:在Bluetooth下,主動去連接的一端作為主機端。被動等別人連接的作為Client端。
背景知識1:Bluetooth設備的狀態
之前HCI編程時,是用?ioctl(HCIGETDEVINFO)得到某個Device Info(hci_dev_info).其中flags當時解釋的很簡單。其實它存放著Bluetooth Device(例如:USB Bluetooth Dongle)的當前狀態:
其中,UP,Down狀態表示此Device是否啟動起來。可以使用ioctl(HCIDEVUP)等修改這些狀態。
另外:就是Inquiry Scan, PAGE Scan這些狀態:Inquiry Scan狀態表示設備可被inquiry. Page Scan狀態表示設備可被連接。
參考:L2CAP編程,http://blog.csdn.net/baozhongchao/archive/2009/10/26/4728751.aspx
3.4、SDP協議簡介
Service Discovery Protocol(SDP)提供一種能力,讓應用程序有方法發現哪種服務可用以及這種服務的特性。服務發現協議(SDP或Bluetooth SDP)在藍牙協議棧中對藍牙環境中的應用程序有特殊的含意,發現哪個服務是可用的和確定這些可用服務的特征。SDP定義了bluetooth client發現可用bluetooth server服務和它們的特征的方法。這個協議定義了客戶如何能夠尋找基于特定屬性的服務而不讓客戶知道可用服務的任何知識。SDP提供發現新服務的方法,在當客戶登錄到正在操作的藍牙服務器的一個區域時是可用的時。
Service discovery機制提供client應用程序偵測server應用程序提供的服務的能力,并且能夠得到服務的特性。服務的品質包含服務type或服務class。SDP也提供SDP server與SDP client之間的通訊。SDP server維護著一個服務條目(service record)列表.每個服務條目描述一個單獨的服務屬性。?SDP client可以通過發送SDP request來得到服務條目。如果一個client或者依附于client之上的應用程序決定使用某個service.?它創建一個單獨的連接到service提供者。?SDP?只提供偵測Service的機制,但不提供如何利用這些Service的機制。這里其實是說:SDP只提供偵測Service的辦法,但如何用,SDP不管。每個Bluetooth Device最多只能擁有一個SDP Server。如果一個Bluetooth Device只擔任Client,那它不需要SDP Server。但一個Bluetooth Device可以同時擔當SDP Server和SDP client.
Service Record(Service?條目):
一個service是一個實體為另一個實體提供信息,執行動作或控制資源。一個service可以由軟件,硬件或軟硬件結合提供。所有的Service信息都包含于一個Service Record內。一個Service Record?包含一個Service attribute(Service屬性) list。在一個SDP Server內,每個Service Record擁有一個32-bit的唯一性數據。通常,這個唯一性只是在每個SDP Server內部。 如果SDP Server S1?和SDP Server S2擁有同樣的一個Service Record。那他們在不同SDP Sever內的獨特數值并不一定相同。SDP在SDP Server增加或減少Service Record時,并不會通知SDP client.
Service Attribute(Service?屬性):
每個Service屬性描述servcie的特性.一個Service Attribute由2部分:
Attribute ID + Attribute Value。
Attribute ID:16-bit無符號整數,用于區別一個Service Record內的其它屬性。
Attribute Value:Attribute值。
Service Class:
每個Service?都是某個Service Class的實例. Service Class定義了Service Record中包含的Service?屬性。屬性ID,屬性值都被定義好了。每個Service Class也有一個獨特ID。這個Service Class標識符包含在屬性值ServiceClassIDList屬性中。并描繪為UUID。自從Service Record中的屬性格式以及含義依賴于Service Class后,ServiceClassIDList屬性變得非常重要。
Searching For Service:
Service Search transaction(事務?)允許client得到Service Record Handle。一旦SDP Client得到Service Record Handle,它就可以請求這個Record內具體屬性的值。
如果某個屬性值UUID,則可以通過查找UUID查到這個屬性。
UUID:?universally unique identifier.(唯一性標識符)
SDP協議棧使用request/response模式工作,每個傳輸過程包括一個request protocol data unit(PDU)和一個response PDU. SDP使用L2CAP連接傳輸數據。在發送Request PDU但未收到Response PDU之前,不能向同一個server再發送Request PDU。
PDU:protocol Data unit
PDU ID:用來識別PDU。
TransactionID:
用來識別Request PUD以及Response PUD。并用來對比某個Response PUD是否對應著Request PUD。
4、Openobex
4.1、Openobex簡介
Welcome to the Open OBEX project. The overall goal of this project is to make an open source implementation of the Object Exchange (OBEX) protocol. OBEX is a session protocol and can best be described as a binary HTTP protocol. OBEX is optimised for ad-hoc wireless links and can be used to exchange all kind of objects like files, pictures, calendar entries (vCal) and business cards (vCard).
OBEX was specified by the IrDA? (Infrared Data Association), and although the protocol is very good for Infrared connections, it is not limited to it. In fact OBEX does not specify the top or bottom API making it very flexible and can run over most transports like TCP/IP and Bluetooth. Therefore OBEX is also called IrOBEX when used over the Infrared medium. There are some transport modules for serial links (cable OBEX) too.
Today, OBEX is builtin in many devices e.g. PDA's like the?Palm§?Pilot, and mobile phones like theSony Ericsson§?R320, R520, T68, T610, T630, K700 and many later phones,?Siemens§?S25, S35, S45, S55, S65?Nokia§?NM207 and Nokia 9110 Communicator. The HP?Scanner?§?CapShare 920 can also talk OBEX in addition to JetSend.?Microsoft§?Windows2000 has also builtin OBEX support.
Link types currently supported by OpenOBEX are:
INFRARED DATA ASSOCIATION ? (IrDA)?http://www.irda.org§
USB-IF, Inc.?http://www.usb.org§
Bluetooth(TM)?http://www.bluetooth.com§
Support for TCP/IP links, file descriptors and custom transports is also provided.
OBEX全稱為Object Exchange,中文對象交換,所以稱之為對象交換協議。它在此軟件當中有著核心地位,文件傳輸和IrMC同步都會使用到它。OBEX協議構建在IrDA架構的上層. OBEX協議通過簡單的使用“PUT”和“GET”命令實現在不同的設備、不同的平臺之間方便、高效的交換信息。支持的設備廣泛,例如PC,PDA,電話,攝像頭,自動答錄機,計算器,數據采集器,手表等等。OBEX協議定義了一種柔性的概念——objects。也即是對象。這些對象可以包括文件,診斷信息,電子商務卡片,銀行的存款等等。Objects在這里沒有高級的技術含義,而是視你的應用而定。OBEX協議小到可作“命令和控制”功能,例如對電視機,錄像機等的操作。大道可以做很復雜的操作,例如數據庫的事務處理和同步。
OBEX能夠具有以下幾個特點:
1、??友好的應用——可實現快速開發。
2、??緊縮——可用在資源有限的小型設備上。
3、??跨平臺
4、??柔性的數據支持。
5、??方便的作為其他Internet傳輸協議的上層協議。
6、??可擴展性——提供了對未來需求的擴充支持而不影響以存在的實現。例如可擴展安全,數據壓縮等。
7、? 可測試可調試。
4.2、Openobex與bluez編程實現
如下表:基于OBEX和BlueZ的數據傳輸的步驟
| 步驟 | 函數 | 意義 |
| 1 | OBEX_Init() | 用于初始化一個obex instance handle; arg1:OBEX_TRANS_BLUETOOTH用于聲明傳輸協議為bluetooth; arg2:callback function; arg3:flag=OBEX_FL_KEEPSERVER,接收到請求后,服務器可以繼續接收其他客戶端的請求; |
| 2 | OBEX_SetUserData() | 設置用戶自己的變量,該函數的使用完全取決于用戶自己; |
| 3 | BtOBEX_ServerRegister() | 一個專用于藍牙協議的服務端函數,用于監聽客戶端發送的請求。該函數內部創建了一個?socket(調用socket(AF_BLUETOOTH,SOCK_STREAM,BTPROTO_RFCOMM)),bind該socket到本地藍牙地址,將該socket轉化為監聽sockt,之后該socket才能夠監聽端口上來自客戶端的連接請求; |
| 4 | OBEX_HandleInput() | 函數用于讀取并處理接收到的數據,如果沒有數據到達,該函數將會阻塞;該函數內部調用了selet()函數,向系統登記了參數handle的客戶端sockt與服務端sockt,讓系 ? 統監聽socket上的事件,如果是服務端socket上有數據到達,則調用accept()函數為客戶端創建一個新的sockt,如果OBEX_Init()的flag不是設置為OBEX_FL_KEEPSERVER,則關掉服務端socket,禁止其他客戶端的連接請求; |
| 5 | CALLBACK?: (OBEX_EV_ACCEPTHINT) | ? |
| 6 | OBEX_ServerAccept() | 該函數返回上述客戶端的socket。 函數內部重新創建了一個obex instance handle,并將上述服務器handle的參數復制到該handle,獲得服務器handle的fd(accept為客戶端創建的socket)后,清除服務器本身的fd; 該函數同時也為新創建的obex instance handle設置callback function及Userdata;至此,已經為客戶端創建了一個與服務端完全獨立的obex instance handle,此后該服務端的操作都由該handle標識,而服務器的socket則繼續監聽其他客戶端的連接請求。 |
| 7 | CALLBACK?: OBEX_EV_REQDONE | OBEX_CMD_CONNECT |
| 8 | CALLBACK?: OBEX_EV_REQHINT | 一個請求即將到來。 調用OBEX_ObjectSetRsp(object,OBEX_RSP_CONTINUE,OBEX_RSP_SUCCESS)設置響應操作碼 |
| 9 | CALLBACK?: OBEX_EV_REQCHECK | 第一個接收到的請求包已經被解析 |
| 10 | CALLBACK?: OBEX_EV_PROGRESS | 收到n個此事件,說明客戶端正在傳輸文件內容 |
| 11 | CALLBACK?: OBEX_EV_REQ | OBEX_CMD_PUT OBEX_ObjectSetRsp(object,OBEX_RSP_CONTINUE,OBEX_RSP_SUCCESS)設置響應操作碼;此時,客戶端文件傳輸完畢,需進行處理: OBEX_ObjectGetNextHeader()分別取得文件的名稱與內容; |
| 12 | CALLBACK?: OBEX_EV_REQDONE | OBEX_CMD_PUT |
| 13 | CALLBACK?: OBEX_EV_REQHINT | 一個請求即將到來 |
| 14 | CALLBACK?: OBEX_EV_REQ | OBEX_CMD_DISCONNECT OBEX_ObjectSetRsp(object,OBEX_RSP_SUCCESS,OBEX_RSP_SUCCESS)設置響應操作碼 |
| 15 | CALLBACK?: OBEX_EV_REQDONE | OBEX_CMD_DISCONNECT; OBEX_TransportDisconnect(handle)斷開連接; 注意:該函數只是將socket關閉,并沒有釋放handle所占用的資源,所以在應用時需要釋放handle占用的資源; |
| 16 | OBEX_Cleanup() | 關掉obex handle并釋放該handle占用的資源。 (該函數同樣關閉了客戶端及服務端socket) |
?
如下表:OpenOBEX的代碼說明:
?
| 文件編號 | 文件名 | 作用 |
| 1 | obex_connect.c/.h | 處理CONNECT PDU,打包和解包 |
| 2 | obex_header.c/.h | PDU處理的公共函數及數據類型定義 |
| 3 | obex_object.c/.h | 對象處理函數,客戶端和服務器公用代碼 |
| 4 | obex_server.c/.h | 服務器端處理代碼 |
| 5 | obex_client.c/.h | 客戶端處理代碼 |
| 6 | obex_transport.c/.h | 傳輸接口的抽象 |
| 7 | irobex.c/.h | 基于紅外的傳輸方式 |
| 8 | usbobex.c/.h | 基于USB的傳輸方式 |
| 9 | inobex.c/.h | 基于TCP/IP的傳輸方式 |
| 10 | btobex.c/.h | 基于藍牙的傳輸方式 |
?
Obexftp
5.1、obexftp簡介
The main goal of this project is to make mobile devices that feature the OBEX protocol and that adhere to the OBEX FTP standard accessible using an open source implementation.
ObexFTP is a library bundling everything needed for OBEX transfers and exposing it via a simple interface. Quite a number of language bindings are provided using SWIG or other means. There is a sample command line client "obexftp" and a server "obexftpd" included. Besides FTP the ObexFTP library provides access to the PUSH, GOEP and SYNCH services. It runs on Linux, FreeBSD, NetBSD and Win32.
5.2、基于Obexftp的應用程序開發
參考代碼
6、參考資料
D-bus官網,http://dbus.freedesktop.org/doc/dbus-tutorial.html§
D-bus中文介紹,http://blog.sina.com.cn/s/blog_5412ede60100eml7.html§
Bluetooth官網,www.bluetooth.com§
Openobex官網,http://dev.zuckschwerdt.org/openobex/wiki/ObexIntroduction§
Openobex API,http://dev.zuckschwerdt.org/openobex/doxygen/
轉載于:https://my.oschina.net/u/994235/blog/113213
總結
以上是生活随笔為你收集整理的Linux下Bluez的编程实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: t2mk是什么文件
- 下一篇: HP DL388G5 安装64位linu