调试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上实现的自动识别,自动启动服务的一整套脚本,还没有仔细研究。



发布了1 篇原创文章 · 获赞 1 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/likeping/article/details/42646235