一、蓝牙协议架构
蓝牙是无线数据和语音传输的开放式标准,它将各种通信设备、计算机及其终端设备、各种数字数据系统、甚至家用电器采用无线方式联接起来。它的传输距离为10cm~10m,如果增加功率或是加上某些外设便可达到100m的传输距离。它采用2.4GHzISM频段和调频、跳频技术,使用权向纠错编码、ARQ、TDD和基带协议。TDMA每时隙为0.625μs,基带符合速率为1Mb/s。蓝牙支持64kb/s实时语音传输和数据传输,语音编码为CVSD,发射功率分别为1mW、2.5mW和100mW,并使用全球统一的48比特的设备识别码。由于蓝牙采用无线接口来代替有线电缆连接,具有很强的移植性,并且适用于多种场合,加上该技术功耗低、对人体危害小,而且应用简单、容易实现,所以易于推广。
蓝牙技术的系统结构分为三大部分:底层硬件模块、中间协议层和高层应用。底层硬件部分包括无线跳频(RF)、基带(BB)和链路管理(LM)。无线跳频层通过2.4GHz无需授权的ISM频段的微波,实现数据位流的过滤和传输,本层协议主要定义了蓝牙收发器在此频带正常工作所需要满足的条件。基带负责跳频以及蓝牙数据和信息帧的传输。链路管理负责连接、建立和拆除链路并进行安全控制。
Linux蓝牙协议栈又称BlueZ,是一个开放性的协议。
蓝牙协议栈体系结构
BlueZ采用模块化设计,其组织结构如图2.13所示。它包含内核和用户态两大模块。其中内核模块是由设备驱动层、蓝牙 核心及主机控制接口HCI(Host Control Interface)层、Bluetooth协议核心、逻辑链路控 制和适配协议L2CAP(Logical Link Control and Adaptation Protocol)、SCO音频层、其他Bluetooth服务组成。而用户态模块则包括BlueZ工具集和蓝牙应用程序。
二、蓝牙协议的HCI传输层
蓝牙系统的HCI层是位于蓝牙系统的L2CAP(逻辑链路控制与适配协议)层和LMP(链路管理协议)层之间的一层协议。HCI为上层协议提供了进入LM的统一接口和进入基带的统一方式。在HCI的主机(Host)和HCI主机控制器(HostController)之间会存在若干传输层,这些传输层是透明的,只需完成传输数据的任务,不必清楚数据的具体格式。目前,蓝牙的SIG规定了四种与硬件连接的物理总线方式:USB、RS232、UART和PC卡。其中通过RS232串口线方式进行连接具有差错校验。协议模型如图2.14所示。
蓝牙模型结构
HCI是通过包的方式来传送数据、命令和事件的,所有在主机和主机控制器之间的通信都以包的形式进行。包括每个命令的返回参数都通过特定的事件包来传输。HCI有数据、命令和事件三种包,其中数据包是双向的,命令包只能从主机发往主机控制器,而事件包始终是主机控制器发向主机的。主机发出的大多数命令包都会触发主机控制器产生相应的事件包作为响应。
三、编程框架
这里以rtk的usb蓝牙驱动为例。
首先将设备注册为一个usb设备,这个设备首选是一个usb设备。
static int __init btusb_init(void)
{
RTKBT_DBG("Realtek Bluetooth USB driver ver %s", VERSION);
#ifdef BTCOEX
rtk_btcoex_init();
#endif
return usb_register(&btusb_driver);
}
btusb_driver结构中,提供了蓝牙设备的probe方法,在usb协议初始完备后,调用probe将设备设定为蓝牙设备。
static struct usb_driver btusb_driver = {
.name = "rtk_btusb",
.probe = btusb_probe,
.disconnect = btusb_disconnect,
#ifdef CONFIG_PM
.suspend = btusb_suspend,
.resume = btusb_resume,
#ifdef RTKBT_SWITCH_PATCH
.reset_resume = btusb_resume,
#endif
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1)
.disable_hub_initiated_lpm = 1,
#endif
};
probe函数的完成的功能主要是对描述蓝牙设备的数据结构btusb_data进行幅值,然后创建hci层设备(hci_alloc_dev)、向hci层注册(hci_register_dev)。
在Linux内核中实现了蓝牙协议栈,最简单的方式就是将设备注册到内核协议栈中,设备就可以收发数据了。有实现的特殊的功能的,可以在各个操作方法的hook函数中实现。
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct btusb_data *data
...
data = rtk_alloc(intf);
...
data->cmdreq_type = USB_TYPE_CLASS;
data->udev = interface_to_usbdev(intf);
data->intf = intf;
init_usb_anchor(&data->tx_anchor);
init_usb_anchor(&data->intr_anchor);
init_usb_anchor(&data->bulk_anchor);
init_usb_anchor(&data->isoc_anchor);
init_usb_anchor(&data->deferred);
...
hdev = hci_alloc_dev();
data->hdev = hdev;
SET_HCIDEV_DEV(hdev, &intf->dev);
hdev->open = btusb_open;
hdev->close = btusb_close;
hdev->flush = btusb_flush;
hdev->send = btusb_send_frame;
hdev->notify = btusb_notify;
hci_set_drvdata(hdev, data);
...
hci_register_dev(hdev);
...
#ifdef BTCOEX
rtk_btcoex_probe(hdev);
#endif