調試Bluetooth時的一些札記



         
LCL層是BT的鏈路控制功能的一部分,它從軟件或被命令配置或控制的其他控制器上取命令,然後執行鏈路控制任務。

藍牙技術的系統結構分爲三大部分:底層硬件模塊、中間協議層和高層應用。底層硬件部分包括無線跳頻(RF)、基帶(BB)和鏈路管理(LM)。無線跳頻層通過2.4GHz無需授權的ISM頻段的微波,實現數據位流的過濾和傳輸,本層協議主要定義了藍牙收發器在此頻帶正常工作所需要滿足的條件。基帶負責跳頻以及藍牙數據和信息幀的傳輸。鏈路管理負責連接、建立和拆除鏈路並進行安全控制。

當WLAN設備和藍牙設備靠得很近並試圖同時收發無線信號時就會發生干擾。這兩種技術採用不同的方法進行信號傳送:載波偵聽多路訪問(CSMA)和跳頻擴頻。前者用於802.11b/g收發器,它在發送信號前會偵聽空閒信道。所發送的信號帶寬大約20MHz,將佔用間距爲25MHz、最多3個非重疊信道中的一個進行傳輸。

核心協議:BaseBand、LMP、L2CAP、SDP
基帶(BaseBand)協議描述了完成低層鏈路建立維護和執行基帶協議的鏈路控制器的規範;鏈路管理協議(Link Manager Protocol)定義了鏈路的建立與控制的規範,在接收側信號由解釋及過濾;邏輯鏈路控制與適配協議(Logical Link Control and Adaptation Protocol)支持高層協議複用、數據包分段重組、QoS信息服務並獲得相應的信息;RFCOMM是ETSITS07.10的子集,提供L2CAP之上的串口防真;TCSBinary定義了在藍牙設備間建立語音與數據呼叫控制信令;其他的一些協議都是已有的其他組織的協議。
除上述協議層外,規範還定義了主機控制接口(HCI),它爲基帶控制器、連接管理器、硬件狀態和控制寄存器提供命令接口,用以向設備供應商提供像USB和UART(通用異步收發器)的通用接口。絕大多數藍牙設備都需要核心協議(加上無線部分),而其他協議則根據應用的需要而定。

在一藍牙微網(Piconet)中,藍牙組件分爲Master與Slave。其中,開啓連接的藍牙裝置稱爲Master,而其它在Plconet中的藍牙裝置稱爲Slave。在Piconet建立好後,則Master與Slave的角色可以互換。藍牙標準使用跳頻(FH)技術來作爲信號的再調變方式以克服無線通信的多路徑衰減及共頻道干擾。其中跳頻序列與頻道接入碼由Piconet中Master來決定,而Piconet中也只允許使用一組跳頻序列以作爲 Master與一個以上的Slave間的通信調變。另外,在藍牙空中接口中,定義了兩種Master與Slave間的鏈路以建立兩者間的連接。分別爲點對點同步連接導向鏈路(SCO)與點對多點異步無連接鏈路(ACL)。
對於藍牙的無線接入過程控制器主要分爲Standby與Connection兩大狀態。在這兩大狀態下又分爲傳呼(Page)、傳呼掃描(Page Scan)、詢呼(Inquiry)、與詢呼掃描(Inquiry Scan)四大子狀態.
http://hi.baidu.com/whyspai/blog/category/Bluetooth
http://hi.baidu.com/anly_jun/blog/category/android%D1%A7%CF%B0
------------------------------------------------------------------------------------------------------
專業術語掃盲:

1.射頻:
射頻(RF)是Radio Frequency的縮寫。表示可以輻射到空間的電磁頻率,頻率範圍從300MHz~30GHz之間。射頻簡稱RF射頻就是射頻電流,它是一種高頻交流變化電磁波的簡稱。每秒變化小於1000次的交流電稱爲低頻電流,大於10000次的稱爲高頻電流,而射頻就是這樣一種高頻電流。有線電視系統就是採用射頻傳輸方式。在電子學理論中,電流流過導體,導體周圍會形成磁場;交變電流(發電機產生電動勢隨時間變化而做週期性變化,因而用電器中的電流電壓也做週期性變化,電路中產生的是交變電流(alternating current),簡稱交流(AC))通過導體,導體周圍會形成交變的電磁場,稱爲電磁波。在電磁波頻率低於100khz時,電磁波會被地表吸收,不能形成有效的傳輸,但電磁波頻率高於100khz時,電磁波可以在空氣中傳播,並經大氣層外緣的電離層反射,形成遠距離傳輸能力,我們把具有遠距離傳輸能力的高頻電磁波稱爲射頻,射頻技術在無線通信領域中被廣泛使用。

2.基帶:
Baseband。信源(信息源,也稱發終端)發出的沒有經過調製(進行頻譜搬移和變換)的原始電信號所固有的頻帶(頻率帶寬),稱爲基本頻帶,簡稱基帶。

3.頻帶:
frequency band。通俗的說,對信道而言,頻帶就是允許傳送的信號的最高頻率與允許傳送的信號的最低頻率這之間的頻率範圍(當然要考慮衰減必須在一定範圍內)。若兩者差別很大,可以認爲頻帶就等於允許傳送的信號的最高頻率。

TCXO:
TCXO(Temperature Compensate X'tal (crystal) Oscillator)TCXO是一種石英晶體振盪器,通過附加的溫度補償電路來削減由周圍溫度變化產生的振盪頻率變化量。
------------------------------------------------------------------------------------------------------
BCM4330芯片模塊介紹:

在手機中我們用到了BCM4330芯片中的這些模塊:PCM、UART、TCXO、analog FM receiver interface、FM digital interfaces、radio transceiver。

BCM4330用一個外部晶振(即TCXO)來產生射頻和時鐘。(TCXO可以進一步減小整個芯片的尺寸大小、電量消耗)

PCM:
PCM提供主/從/混合操作模式與單個或多個編碼解碼器相連。

UART:
UART接口有一個1040字節的接收和傳送FIFO,用來支持EDR(即Enhanced data rate,是藍牙技術中增強速率的縮寫,其特色是大大提高了藍牙技術的數據傳輸速率,達到了2.1Mbps ,是目前藍牙技術的三倍。因此除了可獲得更穩定的音頻流傳送的更低的耗電量之外,還可充分利用帶寬優勢同時連接多個藍牙設備)。CPU或DMA通過AHB接口與FIFO通信。

I2S:
FM數據接收是通過I2S接口。

FM子系統的控制通過BT的HCI接口。

Bluetooth Radio:BCM4330整合了一個radio transceiver。它用來提供低功耗以及與應用程序在ISM頻段以2.4GHz的穩定通信。
------------------------------------------------------------------------------------------------------
BT Application
packages/apps/Bluetooth/src/com/
packages/apps/Settings/src/com/broadcom/bt/app/settings/(APP UI - Settings App)
packages/apps/Settings/src/com/android/settings/bluetooth/(APP UI - Settings App)
packages/apps/Phone/src/com/android/phone/(APP UI - Phone App)

BT Framework
frameworks/base/core/java/com/broadcom/bt/service/
frameworks/base/core/java/android/bluetooth/
frameworks/base/services/java/com/android/server/(SystemServer)
frameworks/base/services/java/com/broadcom/bt/server/BrcmBtServiceLoader.java
frameworks/base/core/java/android/server/BluetoothService.java

BT JNI
frameworks/base/core/jni/

BT Hardware
hardware/broadcom/bt/

BT Driver
kernel/drivers/bluetooth/
external/bluetooth/bluez/
------------------------------------------------------------------------------------------------------
Client send data to Server:
packages/apps/Bluetooth/src/com/broadcom/bt/app/opp/client/OPPClientService.java

Server send data to Client:
packages/apps/Bluetooth/src/com/broadcom/bt/app/opp/server/OPPServerService.java

TimeoutWatchdog:
packages/apps/Bluetooth/src/com/broadcom/bt/app/opp/util/TimeoutWatchdog.java

BluetoothServiceManager:
frameworks/base/core/java/com/broadcom/bt/service/framework/BluetoothServiceManager.java

BluetoothEventLoop:
frameworks/base/core/jni/android_server_BluetoothEventLoop.cpp
frameworks/base/core/java/android/server/BluetoothEventLoop.java

BluetoothPBAPService:
frameworks/base/core/java/com/broadcom/bt/service/pbap/BluetoothPBAPService.java

Android Os:
frameworks/base/core/java/android/os/

IBtService
frameworks/base/core/java/com/broadcom/bt/service/framework/IBtService.java

狀態欄:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/
frameworks/base/core/java/android/app/StatusBarManager.java
frameworks/base/services/java/com/android/server/StatusBarManagerService.java

CachedBluetoothDevice:
packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java

BluetoothServiceConfig:
frameworks/base/core/java/com/broadcom/bt/service/framework/

PowerManagerService
frameworks/base/services/jni/com_android_server_PowerManagerService.h
frameworks/base/services/jni/com_android_server_PowerManagerService.cpp
frameworks/base/services/java/com/android/server/PowerManagerService.java

BtOppRfcommListener
packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppRfcommListener.java

BT HSHFP
packages/apps/Phone/src/com/android/phone/BluetoothHeadsetService.java
frameworks/base/core/jni/android_bluetooth_HeadsetBase.cpp

定義一些ACTION和BOND的狀態(比方log裏的 bond state 11 -> 12):
frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
------------------------------------------------------------------------------------------------------
./dalvik/libnativehelper/include/nativehelper/jni.h
/external/dbus/dbus/

Headset Profile (HSP):including the ability to ring, answer a call, hang up and adjust the volume.
Hands-Free Profile (HFP):last number redial, call waiting and voice dialing.

/* Finishing service bluetooth_dun -- call trace */

(frameworks/base/core/java/com/broadcom/bt/service/)
BluetoothServiceManager-->disableService-->_stopService-->svcWrapper.mSvc.stop()-->BluetoothDUNService{stop()-->disableNative()}<------------[Framework]
                            |
                            |                                    
                            |
                            V
    frameworks/base/core/jni/com_broadcom_bt_service_dun_BluetoothDUNService.cpp{disableNative()-->BTL_IFC_CtrlSend}    <------------[JNI]
                            |
                            |                                    
                            |
                            V
        hardware/broadcom/bt/adaptation/btl-if/client/btl_ifc.c{BTL_IFC_CtrlSend-->send()}                <------------[HAL]

/* reference list */
BtServiceWrapper svcWrapper = null;
private static class BtServiceWrapper {
    private IBtService mSvc;       

public abstract class BaseEventLoop implements IBtService
public abstract class BaseService implements IBtService

public class OppEventLoop extends BaseEventLoop implements OppConstants
public final class BluetoothDUNService extends BaseService
------------------------------------------------------------------------------------------------------
RfKill
內核使用 rfkill 模塊管理無線設備,rfkill 提供兩種類型的用戶態接口用於查詢和控制無線設備:
1. /dev/rfkill
這是一個標準的 I/O 設備,可以使用標準的 open(), close() ioctl() 等操作查詢和控制每個無線設備的狀態,相關的頭文件 /usr/include/linux/rfkill.h

2. /sys/class/rfkill/
每個 rfkill 設備會在 sysfs 中創建自己的一個節點,都有下面文件:

name : 接口或驅動名稱,註冊 rfkill 設備時指定。
type : 設備類型, wlan | bluethooth …
persistent : 從外存謀取的軟限制狀態
state : 當前的無線設備狀態
0 : RFKILL_STATE_SOFT_BLOCKED    被軟件關閉
1 : RFKILL_STATE_UNBLOCKED     開啓
2 : RFKILL_STATE_HARD_BLOCKED    被硬件驅動關閉
設備禁用類型

軟件禁用,由用戶態應用程序觸發,並通過 rfkill 接口關閉無線設備。
硬件驅動禁用,由內核硬件驅動程序觸發的關閉,硬件驅動程序(平臺驅動)調用 rfkill 接口通知硬件被關閉。

implementation:
./kernel/net/rfkill

rfkill mechanism is introduced in Linux kernel 2.6.29.
http://www.mjmwired.net/kernel/Documentation/rfkill.txt is an introduction about rfkill.
That is, while Google released kernel 2.6.29, you have to use rfkill to control BT power.
In android\system\bluetooth\bluedroid\bluetooth.c, it shows that it uses rfkill to turn on power not the previous version with "echo 1 > /sys/module/bluetooth_power/parameters/power"

android\kernel\drivers\bluetooth\bluetooth-power.c is the kernel driver to register rfkill mechanism.
Function bluetooth_power in android\kernel\arch\arm\mach-msm\board-xxxx.c is the entry point to control BT power related configuration.

Now, we removed the control over "/sys/module/bluetooth_power/parameters/power" and the only way to control BT power is to do it over rfkill.
For debugging purpose, here shows the same procedures in bluedroid\bluetooth.c to turn on BT power over adb shell
# cd /sys/class/rfkill
cd /sys/class/rfkill
# ls
ls
rfkill0
# cd rfkill0
cd rfkill0
# cat type
cat type
bluetooth
# cat state
cat state
0
# echo 1 > state
echo 1 > state
# cat state
cat state
1
------------------------------------------------------------------------------------------------------
hcid - Bluetooth Host Controller Interface Daemon
The hcid daemon manages all the Bluetooth devices. hcid itself does not accept many command-line options, as most of its configuration is done in the hcid.conf file, which has its own man page. hcid can also provide a number of services via the D-BUS message bus system.

hciattach - attach serial devices via UART HCI to BlueZ stack
Hciattach is used to attach a serial UART to the Bluetooth stack as HCI transport interface.

在當前項目中,bt的hciattach是這樣啓動的:
service hciattach /system/bin/brcm_patchram_plus  --enable_hci --enable_lpm --patchram /etc/firmware/bcm4330.hcd /dev/ttyHS0 -d
user root
group root
disabled

brcm_patchram_plus的實現位於目錄system/bluetooth/brcm_patchram_plus/brcm_patchram_plus.c。

**  Description:   This program downloads a patchram files in the HCD format
**                 to Broadcom Bluetooth based silicon and combo chips and
**                                 and other utility functions.
**
**                 It can be invoked from the command line in the form
**                                              <-d> to print a debug log
**                                              <--patchram patchram_file>
**                                              <--baudrate baud_rate>
**                                              <--bd_addr bd_address>
**                                              <--enable_lpm>
**                                              <--enable_hci>
**                                              uart_device_name
------------------------------------------------------------------------------------------------------
BT:
HCI提供一些通用控制接口和命令。在掃描設備階段,BT協議棧根據具體協議通過HCI發送命令來獲得設備的MAC地址。BluetoothEventLoop,開啓Event Loop線程,用來從/org/freedesktop/DBus接收信號。開啓BluetoothService、BluetoothServiceManager服務。OppEventLoop,Starting OPP Event Loop as Standalone。OppEventHandler.cpp接收來自/org/freedesktop/DBus的信號。Load OppApplication,調用ExchangeFolderManager檢查/mnt/sdcard/bluetooth/下面的文件夾,然後爲每一個子目錄Registering file observer。

SystemServer
BluetoothService
BluetoothA2dpService
BluetoothHIDService
一個Service對應一個profile,比如BluetoothHIDService對應HID profile。BluetoothService管理所有的profile。

zygote
dbus
btld
bluetoothd
SystemServer 是 Android Java 層的系統服務模塊,這個模塊主要功能就是管理供 Android 應用開發的 system service.
init.rc 文件一行service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server啓動SystemServer.zygote 進程是整個 Android 的孵化器進程,所有的 Activity 進程均是通過它來生成的。在 zygote 進程啓動過程中指定了這麼一個參數“– start-system-server” ,這個參數就是在 zygote 進程啓動的同時啓動 SystemServer 。
------------------------------------------------------------------------------------------------------
bluetooth profile
        Bluetooth的一個很重要特性,就是所有的Bluetooth產品都無須實現全部的Bluetooth規範。爲了更容易的保持Bluetooth設備之間的兼容,Bluetooth規範中定義了Profile。Profile定義了設備如何實現一種連接或者應用,你可以把Profile理解爲連接層或者應用層協議。

        比如,如果一家公司希望它們的Bluetooth芯片支援所有的Bluetooth耳機,那麼它只要支持HeadSet Profile即可,而無須考慮該芯片與其它Bluetooth設備的通訊與兼容性問題。如果你想購買Bluetooth產品,你應該瞭解你的應用需要哪些Profile來完成,並且確保你購買的Bluetooth產品支持這些Profile。

        在所有的Profile中,有四種是基本的Profile,這些Profile會被其它的Profile使用。它們是:
        GAP Profile: Generic Access Profile,該Profile保證不同的Bluetooth產品可以互相發現對方並建立連接。
        SDAP Profile: Service Discovery Application Profile,通過該Profile,一個Bluetooth設備可以找到其它Bluetooth設備提供的服務,以及查詢相關的信息。
        SPP Profile: Serial Port Profile,模擬串口通訊
        GOEP Profile: Generic Object Exchange Profile,通用對象交換。這個Profile的名字有些費解,它定義的是數據的傳輸,包括同步,文件傳輸,或者推送其它的數據。你可以把它理解爲內容無關的傳輸層協議,可以被任何應用用來傳輸自己定義的數據對象。

        另外,Bluetooth還定義了9種應用(usage)Profile。

        CTP Profile: Cordless Telephone Profile,無繩電話。
        IP Profile: Intercom Profile,這是在兩個設備之間建立語音連接,換句話說,把兩個昂貴的蘭牙設備變成廉價的對講機。
        HS Profile: HeadSet Profile,用於連接耳機。
        DNP Profile: Dial-up Networking Profile,用於爲PC提供撥號網絡功能。
        FP Profile: Fax Profile,傳真功能。
        LAP Profile: LAN Access Profile,使用PPP協議建立局域網。
        OPP Profile: Object Push Profile,用於設備之間傳輸數據對象。
        FTP Profile: File Transfer Profile,用於文件傳輸。
        SP Profile: Synchronization Profile,用於不同的Bluetooth設備同步,保持數據的一致性。

Bluetooth的Profile問題是相當複雜的,這些Profile規範在全部的Bluetooth規範中佔有了400頁的內容。
------------------------------------------------------------------------------------------------------
support bluetooth 步驟:
1.kernel/arch/arm/configs/msm7630-xxx-perf_defconfig(make kernelconfig)
CONFIG_BCM4330_POWER=y

2.kernel/arch/arm/mach-msm/Kconfig
config BCM4330_POWER
depends on (MACH_MSM7X30_xxx)
bool "BCM4330 Power Monitor Interface"
default n
---help---
BCM4330 power controle interface.

3.arch/arm/mach-msm/board-msm7x30-xxx.c
編寫上電相關的函數,例如bluetooth_power,這其中要涉及到GPIO引腳的配置;配置休眠相關的resources,比如gpio上的哪個引腳是bt_wake_msm,哪個是msm_wake_bt。


4.啓動hciattach服務
system/core/rootdir/etc/init.qcom.rc
service hciattach /system/bin/brcm_patchram_plus  --enable_hci --enable_lpm --patchram /etc/firmware/bcm4330.hcd /dev/ttyHS0 -d
user root
group root
disabled
對於init中參數的含義參考system/core/init/readme.txt文件。對於brcm_patchram_plus後面參數的含義參考system/bluetooth/brcm_patchram_plus/brcm_patchram_plus.c。

5.在BoardConfig.mk中添加相關信息:
device/qcom/msm7630_xxx/BoardConfig.mk
BOARD_HAVE_BLUETOOTH := true
BOARD_HAVE_BLUETOOTH_BCM := true
BT_ALT_STACK := true
BRCM_BT_USE_BTL_IF := true
BRCM_BTL_INCLUDE_A2DP := true

6.如果出問題,檢查以下文件:
kernel/driver/bluesleep/bluesleep.c
system/bluetooth/bluedroid/bluetooth.c
system/bluetooth/brcm_patchram_plus/brcm_patchram_plus.c
system/core/rootdir/etc/init.qcom.rc
------------------------------------------------------------------------------------------------------
Android上藍牙Profile的簡單實現流程:
Google的Android只實現了Headset/Handfree和A2DP/AVRCP等Profile,而其它常用的Profile如 HID/DUN/SPP/OPP/FTP/PAN等卻沒有實現,並且Google方面關於何時實現也沒有一個時間表。前段時間我實現了HID/DUN /SPP三個Profile,下一步實現OPP/FTP等Profile。具體的開發其實也簡單,我是參照A2DP的代碼進行的相關Profile的實現。Android的Handset/Handfree的實現方式和A2DP/AVRCP的方式有很大的不同,Handset/Handfree是直接在 bluez的RFCOMM Socket上開發的,沒有利用bluez的audio plugin,而A2DP/AVRCP是在bluez的audio plugin基礎上開發的,所以大大降低了實現的難度。其實bluez的audio plugin上也有Handset/Handfree的實現,但不知道爲什麼Google沒有用它,而要在RFCOMM Socket上自己實現一個,這使得Handset/Handfree的實現顯得比較複雜。

HID要用到bluez的input plugin,Android已經把它編譯進去了,在system/lib/bluez-plugin/input.so下,與input.so一起的還有audio.so庫,那是供A2DP/AVRCP用的。參照frameworks/base/core/jni/android_server_BluetoothA2dpService.cpp,自己寫一個HID用的的.cpp文件,其中跟A2DP一樣利用 DBUS調用input.so庫的CreateDevice/Connect/Disconnect等函數,具體源碼在external/bluez/utils/input/manager.c和external/bluez/utils/input/device.c中。然後參照 frameworks/base/core/java/android/server/BluetoothA2dpService.java和 frameworks/base/core/java/android/bluetooth/BluetoothA2dp.java及 frameworks/base/core/java/android/bluetooth/IBluetoothA2dp.aidl,自己分別寫兩個 JAVA類及AIDL接口,餘下的就是在packages/apps/Settings/src/com/android/settings/bluetooth目錄下的各個文件的修改了,比較省事的方法是搜一下A2DP,只要是A2DP要修改的地方照葫蘆畫瓢添加修改就是了。

DUN/SPP要用到bluez的serial plugin,因Android沒有編譯進去,所以要在external/bluez/utils/serial目錄下寫一個Android.mk,把它編譯進去,生成system/lib/bluez-plugin/serial.so庫,其它的跟HID類似。
------------------------------------------------------------------------------------------------------

藍牙各版本之間的區別:
1.1/1.2 可以支持 Stereo 音效的傳輸要求,但只能夠作(單工)方式工作。

2.0 傳輸率約在 1.8M/s~2.1M/s,可以有(雙工)的工作方式。即一面作語音通訊,同時亦可以傳輸檔案/高質素圖片。缺點是配置流程複雜和設備功耗較大。

2.1+EDR 主要是解決2.0的缺點。改進過後的連接方式則是會自動使用數字密碼來進行配對與連接,舉例來說,只要在手機選項中選擇連接特定裝置,在確定之後,手機會自動列出目前環境中可使用的設備,並且自動進行連結;   藍牙2.1版加入了Sniff Subrating的功能,透過設定在2個裝置之間互相確認訊號的發送間隔來達到節省功耗的目的。一般來說,當2個進行連結的藍牙裝置進入待機狀態之後,藍牙裝置之間仍需要透過相互的呼叫來確定彼此是否仍在聯機狀態,當然,也因爲這樣,藍牙芯片就必須隨時保持在工作狀態,即使手機的其它組件都已經進入休眠模式。爲了改善了這樣這樣的狀況,藍牙2.1將裝置之間相互確認的訊號發送時間間隔從舊版的0.1秒延長到0.5秒左右,如此可以讓藍牙芯片的工作負載大幅降低,也可讓藍牙可以有更多的時間可以徹底休眠。根據官方的報告,採用此技術之後,藍牙裝置在開啓藍牙聯機之後的待機時間可以有效延長5倍以上。

3.0 核心是"Generic Alternate MAC/PHY"(AMP),這是一種全新的交替射頻技術,允許藍牙協議棧針對任一任務動態地選擇正確射頻。通過集成"802.11 PAL"(協議適應層),藍牙3.0的數據傳輸率提高到了大約24Mbps,是2.0的8倍。功耗方面,通過藍牙3.0高速傳送大量數據自然會消耗更多能量,但由於引入了增強電源控制(EPC)機制,再輔以802.11,實際空閒功耗會明顯降低,藍牙設備的待機耗電問題有望得到初步解決。此外,新的規範還具備通用測試方法(GTM)和單向廣播無連接數據(UCD)兩項技術,並且包括了一組HCI指令以獲取密鑰長度。

4.0 實際是個三位一體的藍牙技術,它將三種規格合而爲一,分別是傳統藍牙、低功耗藍牙和高速藍牙技術,這三個規格可以組合或者單獨使用。改進之處主要體現在三個方面,電池續航時間、節能和設備種類上。擁有低成本,跨廠商互操作性,3毫秒低延遲、100米以上超長距離、AES-128加密等諸多特色。

容易混的profile:
FTP:
瀏覽其他設備上的文件或文件夾或目錄樹。這裏的設備不僅僅是手機,包括PC等。
在設備之間傳輸文件或文件夾。
修改另一個設備上的文件或文件夾,包括刪除或創建。
OPP:
Object Push
Business Card Pull
Business Card Exchange
pull/push名片(business card/vcard)或約會(appointment)。
交換名片或約會,交換的意思就是a push of a business card followed by a pull of a
business card.
PBAP:
It is based on a Client-Server interaction model where the Client device pulls phone book objects from the Server device.
注意這裏是基於C-S的,client從server上pull phone book,而且並未提到其他操作。
可以瀏覽另一個設備上的phone book,但不可以做修改。
與OPP結合可以實現pull phone book from a server device.
------------------------------------------------------------------------------------------------------
external/dbus/dbus/dbus-protocol.h
external/bluetooth/bluez/doc/
各個interface(比如org.bluez.device)中含有哪些方法。
/data/data/com.android.settings/shared_prefs/bluetooth_settings.xml
DBUS_ERROR_UNKNOWN_METHOD
------------------------------------------------------------------------------------------------------
OPP(transfer file)
OppEventHandler:
frameworks/base/core/jni/com_broadcom_bt_service_opp_OppEventHandler.cpp

BtOppTransfer
packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppTransfer.java

BluetoothService:
frameworks/base/core/jni/android_server_BluetoothService.cpp
frameworks/base/core/java/android/server/BluetoothService.java

BtOppObexServer
packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java

BtOpp ObexClient
packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java

BtOpp Service
packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppService.java

Obex ServerOperation
frameworks/base/obex/javax/obex/ServerOperation.java

ResponseCodes class contains the list of valid response codes a server may send to a client.
frameworks/base/obex/javax/obex/ResponseCodes.java
------------------------------------------------------------------------------------------------------


Bluez作爲當前最成熟的開源藍牙協議棧,在Linux的各大發行版中已經得到了廣泛的應用。在桌面環境下,使用Bluez應該已經沒有太大的問題,本文的主要目的是介紹在嵌入式平臺上,搭建和配置Bluez的各個Profile運行所需做的工作,討論可能遇到的問題,介紹一些工具的使用和工作原理。因爲本人的能力和測試時間有限,可能下文中有些理解、分析不一定準確,歡迎聯繫指正。


1 相關說明
1.1 網站資源
Bluez的官方網址:http://www.bluez.org/ 這裏提供最新的源碼下載,最近服務器崩潰了一次,有些東西沒了。。。。
Bluez的Wiki:http://wiki.bluez.org/wiki/ 這裏提供Bluez相關的Howto等文檔資源
相關郵件列表:
https://lists.sourceforge.net/lists/listinfo/bluez-users 關於如何使用和配置Bluez,多數是在討論PC環境下的問題。。。。
https://lists.sourceforge.net/lists/listinfo/bluez-devel Bluez開發者活動的地方,有什麼Bug之類的懷疑,還有編程接口之類的問題,就發到這裏吧。

1.2 工作環境
個人感覺,使用Bluez最大的問題就是文檔的欠缺,除了Wiki上的有限資料以外,很難找到其它有用的文檔。
由於Bluez的代碼實現更新變化得很快,網上的許多文檔介紹的都是早期版本的使用,再有的文章多數是基於成熟的Linux發行版,來討論藍牙設備的配置和使用,對於嵌入系統開發,自己編譯,搭建和配置相關環境的文章很少。此外和具體藍牙芯片相關的資料也很難找到。

這裏我不打算也沒有能力寫一個完整的指南,只能基於前段時間在自己的板子上所做的工作,總結一下相關的步驟和所遇到的各類問題以及這期間所掌握的各種相關知識。希望能給有類似開發需求的朋友一些有益的幫助,下面是這篇文章所基於的工作環境:

 硬件平臺:基於ARM的嵌入式板子
 藍牙芯片:CSR BC4 ROM 版本芯片,不帶eeprom
 軟件環境:Linux 2.6.21 ,自制文件系統
 Bluez版本:bluez-libs 3.22 bluez-utils 3.22

2 編譯
2.1 內核
相信多數人使用的都是2.6的內核了,在2.6的內核中要支持Bluez,只要你的內核版本不是太舊,無需打Patch,直接配置好就OK了,內核裏面的代碼相對比較穩定了。當然,Bluez對一些Bluetooth協議棧新特性的支持,還是需要更新kernel代碼的。你應該確認你使用的kernel版本是否以及包含了對應的支持。

內核的配置,基本上把 networking下 --- Bluetooth subsystem support 裏的以下幾項全部選上即可:

L2CAP protocol support
SCO links support
RFCOMM protocol support
RFCOMM TTY support
BNEP protocol support
HIDP protocol support

此外,在Bluetooth device drivers裏選上你所需要支持的Bluetooth設備。我使用的CSR的chip是我們直接build在板子上,通過串口和cpu通訊的,芯片默認使用BCSP作爲通訊協議,所以我選擇了:

HCI UART driver
BCSP protocol support

如果你是通過usb接口使用藍牙適配器,需要選擇
HCI USB driver

2.2 Bluez Lib / Utils

Bluez Lib的編譯比較簡單,而Bluez-Utils所依賴的庫就比較多了,大體包括 dbus alsa hal gstreamer openobex xml等等,仔細觀察./configure 的輸出,將所需要的包先安裝或者build好。
值得注意的一點是:
如果你需要打開所有的功能模塊的支持,需要在 ./configure 參數中添加 --enable-all --enable-audio --enable-input --enable-network –enable-serial 等,在3.22版本中 --enable-all 居然不包括 audio等相關模塊的service的編譯,不知道是否是因爲還保留了daemon和service等不同方案的緣故。不過,這至少與他的configure --help 對於 --enable-all 的描述是不符合的。

3 藍牙硬件初始化及基礎服務啓動

如果在PC環境下,使用Ubuntu,調用 /etc/init.d/bluetooth start 應該就能完成這一步的工作了。下面敘述一下在我的嵌入式環境下,如何手動完成這一步驟。

3.1 何謂硬件初始化
硬件初始化,指的是配置藍牙芯片,將其置於一個能夠正常通訊的狀態。 對於CSR的芯片來說,就是通過設置PSKEY,設置其晶振頻率,UART波特率等等一些關鍵參數。 如果使用的是USB形式的適配器,因爲其EEPROM存儲了相關的默認參數,這一步很可能不需要做,而我使用的是不帶EEPROM的ROM版本芯片,如何正確完成初始化工作着實讓我折騰了一陣。

對於其它芯片,沒有太多研究,不過,據我有限的瞭解,TI的芯片在hciattach時也需要完成一些額外的初始化工作,其它如ST的芯片則可能需要下載firmware。

3.2 硬件初始化步驟
通常藍牙芯片的初始化和協議綁定可以通過 hciattach 來完成(通過配置bluez的啓動腳本,可以不需要使用hciattach,標準發行版應該都是不用hciattach,如何配置,還沒有研究 。。。 8 )

Hciattach 需要的參數主要包括 TTY節點,設備類型,波特率等。多數類型的設備的初始化工作,在選擇了正確的設備類型參數後,都由hciattach在init_uart函數中調用具體的初始化函數所完成。

很遺憾的是,因爲要重新設置晶振頻率和波特率,並同步BCSP協議,這種方式好像處理不了我所使用的芯片(不排除我沒有找到正確的解決方案的可能性),我最終的解決辦法是在hciattach之前,使用Bluez-utils裏的BCCMD工具先完成這些PSKEY的設置工作。

具體命令是:
bccmd -t bcsp -d /dev/ttyS1 psload -r csr.psr

在這時,由於HCI接口還沒有啓動,所以只能使用BCSP協議來進行通訊,我的設備是暴露在ttyS1下,你的可能不一樣,-r參數指明在psload完成 PSKEY的批量加載操作之後,對芯片進行Warmreset,否則這些參數的修改不會起作用。

Csr.psr的內容取決與你的芯片,我的大致如下:

// PSKEY_ANA_FREQ
&01fe = 9C40 // 相當於40M的晶振
// PSKEY_UART_BAUD_RATE
&01be = 0EBF // 921600的波特率
// PSKEY_UART_SEQ_WINSIZE
&0407 = 0006
// BDADDR
&0001 = 1122 3344 5566 7788
。。。

這裏有個問題,你會發現,通過bccmd -t bcsp psset 命令理論上應該是可以單步設置每一個PSKEY的,但是從我實踐看來,單步的操作在兩次對bccmd的調用過程中,上一次對PSKEY的修改,都會在下一次調用之前被複位,從代碼上看估計和BCSP協議的同步過程有關。
3.2.1 關於PSKEY的獲取
如何獲得正確的完整的PSKEY參數,大概會有幾個途徑:
 通過CSR的網站下載boot_strap包,這是CSR自己的BCHS協議棧所使用的初始化代碼,在裏面找到你所需要的pskey值。
 下載CSR的bluesuite工具,裏面包含了一個叫pstool的工具,可以用它來讀寫CSR的Casira開發板或其它BT設備的PSKEY設置,試驗並找出你能用的參數。
 找CSR或模組廠商支持 8 )

不過,基本上來說,如果只是要讓芯片通過串口能夠和Bluez協議棧正常通訊上,只需要設置PSKEY_ANA_FREQ 和 PSKEY_UART_BAUD_RATE 這兩個PSKEY就可以了。

3.3 Daemon進程的啓動
早先的版本里,Bluez的Daemon很多,但是最近的版本,很多daemon都轉爲service的形式來做了,3.22 裏面包括了以下這幾個Service,其它profile貌似還保留着daemon的形式。
bluetoothd-service-serial
bluetoothd-service-network
bluetoothd-service-audio
bluetoothd-service-input
這幾個Service的啓動依賴於hcid的啓動以及相關的配置文件
主要配置文件位於:/etc/bluetooth/
此外,通常還需要啓動SDP來提供服務查詢,另外,Bluez本身還依賴於Dbus daemon的運行。

所以,整體上來說,我的手動啓動Bluez的全過程如下:(其中內核代碼是以模塊形式編譯的)

insmod bluetooth.ko
insmod hci_uart.ko
insmod l2cap.ko
insmod rfcomm.ko
insmod sco.ko
insmod hidp.ko

/etc/rc2.d/S20dbus start
bccmd -t bcsp -d /dev/ttyS1 psload -r csr.psr
hciattach -s 921600 /dev/ttyS1 bcsp 921600
hciconfig hci0 up
sdpd
hcid –d

4 Paring配對
4.1 Passkey_agent
在正常使用一個藍牙設備前,通常都需要對該設備進行配對綁定的操作。
Bluez的配對機制貌似也修改了幾次,2.x版本中通過pin_helper來處理pin code的應答,3.22版本里使用的配對機制,其API是基於Dbus來實現的,需要向dbus註冊一個agent,PC的發行版通常都會有一些基於各種圖形庫的passkey_agent,對於嵌入式系統,這部分代碼可以想象,應該是要按照相應的API自己實現一個,爲了測試,我直接使用了bluez-utils/daemon 目錄下的passkey-agent

這是一個命令行下的可以使用預先設定的pin code進行配對的程序

爲了使用它,我的文件系統裏 /etc/Bluetooth/hcid.conf 中 option一節類似如下 :

# HCId options
options {
# Automatically initialize new devices
autoinit yes;

# Security Manager mode
# none - Security manager disabled
# auto - Use local PIN for incoming connections
# user - Always ask user for a PIN
#
security user;

# Pairing mode
pairing multi;

# Do the same as "hciconfig hci0 down" when SetMode("off")
# is called.
offmode devdown;

# Default PIN code for incoming connections
passkey "1234";
}

4.2 關於自動配對和請求的發起

配對的發起,這裏主要是從請求的發起者是誰的角度來說。

通常可能不需要關心配對請求是由本地還是由遠端發起的,使用passkey_agent都能夠正確處理。

不過如果在hcid.conf中將 Security Manager mode 設置爲 auto,則Bluez會將passkey後面的字符串作爲默認的Pin code,自動答覆遠端發起的配對請求。這是在沒有使用passkey_agent的情況下的一種配對方式。

在這種情況下,Bluez可以處理遠端的配對請求,但是對於本地發起的配對請求,將無法正確處理,我沒有仔細的分析原因,或許是代碼特意設計成這種工作方式。所以在無法明確知道誰將會主動先發起配對請求的情況下,使用Atuo模式,可能就會出現有些時候設備能綁定有些時候不能綁定的現象。

通常如果是由本地設備搜索發現的新設備,配對綁定的操作應該也是由本地發起。

另外可以觀察到,對遠端一個非PC類的藍牙設備,如藍牙耳機,如果上次綁定過,在耳機啓動時會主動發起連接請求,如果本地的link key丟失了,也就會再走一次綁定的流程,這種情況下配對請求就是由遠端設備發起的。


5 A2DP
A2DP藍牙立體聲應該是藍牙最常見的Profile之一。
2.x版本的Bluez,對A2DP的支持是通過BTSCO來實現的,3.22的版本通過bluetoothd-service-audio來支持。
對Bluez A2DP profile的支持,還依賴於Alsa或Gstreamer。
5.1 配置
測試A2DP的時候,我使用的是aplay,同時在相關的配置文件裏面寫死了藍牙耳機的地址
主要的配置文件包括:

/etc/asound.conf :

pcm.bluetooth{
type bluetooth
device 00:02:5B:00:C1:A0
profile "hifi"
}

/etc/bluetooth/audio.conf :

[General]
# disable=Sink
SCORouting=PCM

[Headset]
DisableHFP=true

[A2DP]
SourceCount=2

配置好這些以後,使用 aplay -D bluetooth sample.wav 進行測試。

值得注意的是,使用Aplay打開藍牙設備進行播放,需要有如下兩個Alsa的plugin:

/usr/lib/alsa-lib/libasound_module_pcm_bluetooth.so
/usr/lib/alsa-lib/libasound_module_ctl_bluetooth.so

這兩個so文件可以在bluez-utils 裏面找到。需要注意他們和libasound 的版本匹配。

5.2 問題
在測試中發現,如果連接的耳機是由PC上的藍牙適配器提供的AV耳機服務,那麼配對可以完成,但是連接會失敗,真正的耳機則沒有這個問題,不知道是否是因爲以上的方法還存在缺陷?嘗試使用由DBUS發起命令的形式來連接PC的AV耳機服務,也是一樣的問題。是否連接PC模擬的AV耳機服務,首先要切換設備的role?

沒有測試Ctl接口

如何動態選擇不同的耳機,而不是寫死在腳本里?(這個想來估計是要自己基於Alsa的API編程處理,aplay無法直接完成測試)

播放大文件會出現under run錯誤,需要測試是由與波特率設置不夠高造成,還是SBC編碼效率不夠,還是這個版本里存在的bug。

6 DUN的使用
Dun profile運行於rfcomm之上,主要是通過藍牙接口暴露一個Modem的接口,用於提供撥號上網服務。 在這裏所討論的不是提供撥號上網服務本身,而是使用外部設備所提供的這個服務,進行網絡連接。
6.1 系統配置
通常爲了使用DUN,或者任何一個其它類型的Modem,我們會通過PPP協議來撥號和建立網絡連接。
首先需要內核的支持,可以簡單的把 device drivers -> Network device support 下面的PPP相關的內容全部選上。
其次,要編譯應用層的PPP包,我的測試是基於ppp-2.4.4

主要的兩個ppp配置文件:

/etc/ppp/peers/gprs:

/dev/rfcomm0
115200
defaultroute
usepeerdns
nodetach
noauth
local
debug
connect "/usr/sbin/chat -v -f /etc/ppp/chat-gprs"

/etc/ppp/chat-gprs:

TIMEOUT 10
ABORT 'BUSY'
ABORT 'NO ANSWER'
ABORT 'ERROR'
"" 'ATZ'
SAY 'Init....\n'
OK 'AT+CGDCONT=1,"IP","CMWAP"'
ABORT 'NO CARRIER'
SAY 'Dialing....\n'
OK 'ATD*99***1#'
CONNECT ''

前面一個配置文件基本就是那樣了,後面一個,這兩句要根據你的SIM卡的實際情況來處理:

OK 'AT+CGDCONT=1,"IP","CMWAP"'
OK 'ATD*99***1#'

這裏我設置的是使用中國移動的CMWAP。

此外,使用CMWAP還需要設置你的瀏覽器的代理服務器:10.0.0.172 端口9201

6.2 連接步驟
首先是要查找提供dun服務的設備,將服務提供在哪個channel通道上。這可以通過sdptool來查看,在我的設備上查詢的結果是在channel 1上:

~ # ./sdptool browse 00:08:C6:77:A0:6C

Browsing 00:08:C6:77:A0:6C ...
Service Name: Dial-upnetworking
Service RecHandle: 0x10000
Service Class ID List:
"Dialup Networking" (0x1103)
"Generic Networking" (0x1201)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Profile Descriptor List:
"Dialup Networking" (0x1103)
Version: 0x0100

其次,如果rfcomm所需設備節點不存在,將其創建:

mknod -m 666 /dev/rfcomm0 c 216 0

然後就是撥號了,如果該設備之前沒有綁定,這過程中會自動發起綁定操作:

pppd debug dump call gprs &

完成以後就可以看到 ppp0這樣一個網絡接口了。

~ # ifconfig
ppp0 Link encap:Point-to-Point Protocol
inet addr:10.154.76.82 P-t-P:192.200.1.21 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:64 (64.0 B) TX bytes:101 (101.0 B)

7 Bluez相關的各種tools的使用
在這一段折騰Bluez的時間裏,越來越發現Bluez相關的許多工具做得還是挺好用的,主要在Bluez-utils/tools 目錄下。只是有一點讓我很遺憾,除了man以外很難找到更多的幫助文檔,而man文檔本身對一些功能的描述也不是很詳細。
其中有些選項,如果你不瞭解藍牙協議棧,或者沒有查閱過相關藍牙芯片的一些文檔,很難搞明白是什麼意思,甚至有些選項的具體參數值的設定,如果不讀源碼你都無從得知有哪些備選值。。。。

能力有限,下面所寫的只是我所用過的有限的幾個工具的一些使用經驗,希望能有所幫助。
7.1 Bccmd
Bccmd是用來和CSR的芯片進行BCCMD(Bluecore command protocol)通訊的一個工具。BCCMD並非藍牙協議棧的標準,而是CSR芯片的專屬協議
Bccmd的調用格式爲:bccmd [-t <transport>] [-d <device>] <command> [<args>]
Tansport類型包括 HCI USB BCSP H4等,常用的估計就是HCI和BCSP兩種。需要注意一下他們的使用場合:
HCI是一個抽象的標準的藍牙通訊接口,在基於HCI協議調用BCCMD時,需要在Bluez已經建立好hci接口的基礎上使用。
BCSP(Bluecore Serial Protocol)是CSR自己制定的傳輸層協議,主要目的是用來加強在沒有使用CTS、RTS進行流量控制的情況下進行可靠的數據傳輸的能力。其概念是相對H3 , H4而言,( 具體分析,請參考下面雜項一章中相應的小節 )

BCCMD的主要用途就是用來讀寫pskey,這裏以 psset 這個command來介紹一下格式:
Psset 格式如下: psset [-r] [-s <stores>] <key> <value>
其它都好理解,關鍵是-s參數之後跟的store具體的含義。這個參數可以是數值也可以是字符串
查詢CSR的BCCMD相關的文檔,可以找到具體的含義如下:

0x0000 Default
0x0008 psram
0x0001 psi
0x0002 psf
0x0004 psrom
0x0003 psi then psf
0x0007 psi, psf then psrom
0x0009 psram then psi
0x000b psram, psi then psf
0x000f psram, psi, psf then psrom

CSR的藍牙芯片中,PSKEY可能存儲在 rom flash eeprom ram等介質裏,這裏的數值指明瞭psset/get命令操作PSKEY時所針對的存儲介質及其優先順序,通常我們會用 –s 0x0 或 –s “default” 來使用該命令,0x0的含義與0xf一樣。

值得注意的是,哪個參數是有效的,還取決於哪一類的存儲介質實際存在於藍牙芯片中,此外,只讀類的介質對寫操作類的命令也是無效的。

基本上來說,所修改的都是位於psram中的pskey,此外,pskey修改以後要起作用,還要一併使用 –r參數,或直接用warmreset命令將藍牙芯片進行warm reset。


7.2 Hciattach
Hciattach主要用來初始化藍牙設備,它的命令格式如下:

hciattach [-n] [-p] [-b] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]

其中最重要的參數就是 type和speed,type決定了要初始化的設備的型號,可以使用 hciattach –l 來列出所支持的設備型號。
並不是所有的參數對所有的設備都是適用的,有些設備會忽略一些參數設置,例如:查看hciattach的代碼就可以看到,多數設備都忽略bdaddr參數。

Hciattach命令內部的工作步驟是:首先打開制定的tty設備,然後做一些通用的設置,如flow等,然後設置波特率爲initial_speed,然後根據type調用各自的初始化代碼,最後將波特率重新設置爲speed。所以調用hciattach時,要根據你的實際情況,設置好initial_speed和speed。

對於type BCSP來說,它的初始化代碼只做了一件事,就是完成BCSP協議的同步操作,它並不對藍牙芯片做任何的pskey的設置。同步操作的具體流程和規範可以參考CSR的相關文檔: BCSP Link Establishment Protocol

7.3 其它
下面幾個,使用了,但是沒有太多研究
7.3.1 Hcidump
Hcidump不在bluez-utils包裏,而是在單獨的hcidump包裏。主要用來分析捕獲和分析HCI數據包,如果使用bluez過程中出了什麼問題,用hcidump往往可以發現一些出錯的線索,原因。 參數很多,基本上hcidump –X –V 就可以幫你獲得詳細的經過格式解析的數據包。
7.3.2 Hcitool
主要用hcitool來scan遠端的設備,顯示設備地址,名稱等。
例如:Hcitool scan, hcitool inq

7.3.3 Sdptool
主要用來瀏覽遠端設備SDP服務,或者管理本地的SDPD維護的數據庫。
常用的應該就是查找遠端設備的服務了
例如:
sdptool browse 00:02:72:B0:00:26 瀏覽地址爲00:02:72:B0:00:26的設備所提供的服務
sdptool search 0x1112 00:02:72:B0:00:26 查找地址爲00:02:72:B0:00:26的設備上的Headset Audio Gateway服務。

./sdptool search 0x1112 00:02:72:B0:00:26
Class 0x1112
Inquiring ...
Searching for 0x1112 on 00:02:72:B0:00:26 ...
Service Name: Headset Audio Gateway
Service RecHandle: 0x1001d
Service Class ID List:
"Headset Audio Gateway" (0x1112)

"Generic Audio" (0x1203)
。。。

7.3.4 Hciconfig
這個就不用多說了,格式上很類似於ifconfig,用來設置HCI設備的參數
例如
hciconfig hci0 up 啓動hci0接口
hciconfig hci0 iscan 使能位於hci0接口的藍牙芯片的inquery scan模式(使得設備能被其它藍牙設備發現)


8 雜項
8.1 使用Dbus-send進行測試
由於Bluez使用dbus進行進程間通訊,所以我們可以使用dbus-send命令直接發送命令進行一些查詢,試驗的工作。
Bluez每個Daemon或service所支持的Dbus接口API描述文本,可以在各自的目錄下找到,例如Audio的API寫在 audio/audio-api.txt中。
以Audio爲例,可以參考 http://wiki.bluez.org/wiki/HOWTO/AudioDevices 中的描述


8.2 HCI、H4、USB、BCSP 之間的關係
個人理解,嚴格的說HCI和其它幾種protocol並不是可以對比的同一層次的東西。
HCI protocol 並不考慮在實際傳輸載體以及其中的糾錯等問題,只是一個抽象的傳輸層或叫做接口。USB,H3,H4等纔是具體的transport layer(此外還有SD Transport layer)。HCI數據包需要附着在這些具體的Transport Layer的協議包中。
以BCSP爲例,4種類型的HCI數據包各自使用了一個BCSP通道,做爲這些通道的payload封裝在BCSP的協議包裏,需要通過TTY的lldsic層走一次,並由hci_uart模塊做相應的封裝工作。而BCSP還通過其它通道支持其它的一些自定的Protocol。BCSP作爲一個具體的傳輸層協議,還支持了校驗,同步等功能。
H4機制類似,SD和USB transport好像區別比較大一點。具體可以參考 Bluetooth Specification Volume 4.

8.3 BCSP數據包結構
HCI數據包的結構,在bluetooth的spec裏面有詳細定義,不過,CSR自己的BCSP,BCCMD等一系列協議,又添加了一堆的東西,其中,HCI數據包是作爲BCSP的payload,而BCCMD又是作爲HCI的payload,所以測試過程中,發覺要分析清楚bluez通過kernel最後到底往藍牙芯片的串口發送了什麼數據,特別是想要自己手工構建一串數據,着實要看上一堆spec,拼湊起來才能完成。
要具體學習分析一串命令,最好的辦法,我能想到的就是修改bccmd的代碼,將它傳給串口的每一個字符串都打印出來,這樣對照這spec看,事半功倍。

例如下面這條,是使用我修改後的bccmd指令。所做的操作是讀取串口波特率的pskey:

./bccmd.dbg -t bcsp -d /dev/ttyS1 psget -s 0x0 0x01be

cmd : 00 fc 13 c2 00 00 09 00 01 00 03 70 00 00 be 01 01 00 00 00 00 00
c0 d1 65 01 c8 00 fc 13 c2 00 00 09 00 01 00 03 70 00 00 be 01 01 00 00 00 00 69 a6 c0

在這裏 HCI的數據包是第一行,具體解釋一下:

頭4個字節是HCI Head,其中
00 fc :整體代表這是一個製造商自定義的命令。
13 :HCI命令長度爲0x13。
C2 :包的內容是唯一的一個BCCMD數據包。

後面是BCCMD的Head
00 00 :這是一個GetReq命令
09 00 :BCCMD的命令9個word長度,及18字節
01 00 :seqno, 包的順序標記 包1
03 70 :varid 7003, 表示這是對PSKEY的操作
00 00 :狀態標誌
再下來是BCCMD的payload
be 01 :0x01be 波特率PSKEY的index
01 00 :該PSKEY的長度爲1
00 00 :strore 爲 00
00 00 :該PSKEY的值,這裏是發送讀命令,所以填0

第二行的數據是將HCI包封裝在了BCSP數據包裏:
前面部分:c0 d1 65 01 c8 :
C0 :是BCSP數據包的分割符
D1 :類型爲可靠鏈接數據流,有CRC校驗
65 01 :channel 5 ( HCI CMD ), 長度爲0x16
C8 :包頭的校驗
後面部分:69 a6 c0:
69 a6 :整個BCSP包的CRC校驗
C0 :分隔符

其它命令類似的分析可得。

如果只是希望看到HCI命令本身,也可以用hcidump來看。這是上面的讀pskey操作通過HCI接口操作的dump:

< HCI Command: Vendor (0x3f|0x0000) plen 19
BCCMD: Get req: len 9 seqno 1 varid 0x7003 status 0
PSKEY: key 0x01be len 1 stores 0x0000

8.4 Hid / Serial / HF / OBEX
這幾個比較常用的profile,還沒測試哪。。。。。。誰給我買個藍牙鼠標玩玩?!

8.5 總的遺留問題
整體上,PC上實現的自動識別,自動啓動服務的一整套腳本,還沒有仔細研究。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章