添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

蓝牙的各个协议栈的简介

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 里面提供的信号触发机制。

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

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.

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.

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

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.

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_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_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 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 the Sony 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 的数据传输的步骤

用于初始化一个 obex instance handle

arg1:OBEX_TRANS_BLUETOOTH 用于声明传输协议为 bluetooth

arg2:callback function

arg3:flag=OBEX_FL_KEEPSERVER, 接收到请求后,服务器可以继续接收其他客户端的请求;

函数用于读取并处理接收到的数据,如果没有数据到达,该函数将会阻塞;该函数内部调用了 selet ()函数,向系统登记了参数 handle 的客户端 sockt 与服务端 sockt ,让系

统监听 socket 上的事件 , 如果是服务端 socket 上有数据到达,则调用 accept ()函数为客户端创建一个新的 sockt ,如果 OBEX_Init() flag 不是设置为 OBEX_FL_KEEPSERVER ,则关掉服务端 socket ,禁止其他客户端的连接请求;

该函数返回上述客户端的 socket

函数内部重新创建了一个 obex instance handle ,并将上述服务器 handle 的参数复制到该 handle ,获得服务器 handle fd accept 为客户端创建的 socket )后,清除服务器本身的 fd

该函数同时也为新创建的 obex instance handle 设置 callback function Userdata ;至此,已经为客户端创建了一个与服务端完全独立的 obex instance handle ,此后该服务端的操作都由该 handle 标识,而服务器的 socket 则继续监听其他客户端的连接请求。

OBEX_CMD_PUT

OBEX_ObjectSetRsp(object,OBEX_RSP_CONTINUE,OBEX_RSP_SUCCESS) 设置响应操作码;此时,客户端文件传输完毕,需进行处理 :

OBEX_ObjectGetNextHeader() 分别取得文件的名称与内容;

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/