实战LinuxBluetooth编程.docx

上传人:b****6 文档编号:7013708 上传时间:2023-01-16 格式:DOCX 页数:34 大小:34.60KB
下载 相关 举报
实战LinuxBluetooth编程.docx_第1页
第1页 / 共34页
实战LinuxBluetooth编程.docx_第2页
第2页 / 共34页
实战LinuxBluetooth编程.docx_第3页
第3页 / 共34页
实战LinuxBluetooth编程.docx_第4页
第4页 / 共34页
实战LinuxBluetooth编程.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

实战LinuxBluetooth编程.docx

《实战LinuxBluetooth编程.docx》由会员分享,可在线阅读,更多相关《实战LinuxBluetooth编程.docx(34页珍藏版)》请在冰豆网上搜索。

实战LinuxBluetooth编程.docx

实战LinuxBluetooth编程

实战Linux_Bluetooth编程

Sam一年前在Linux下写了一个类似Windows下BTW的库--BTX。

现在需要添加新功能时

发现很多知识点都忘记了。

所以决定在这次学习中,把一些bluezAPI记录下来。

这几天又想,这样还不够,不如把Linux下的Bluetooth编程基础给记录下来吧。

前言:

随着嵌入式系统的飞速发展,很多嵌入式平台上需要Bluetooth设备和应用。

但在Linux下如何对Bluetooth编程,一直没有一份很好的中文文档。

Sam结合自己的工作,一步一步

将一些有用的东西记录下来,希望对其它Linux下Bluetooth编程的朋友有点帮助。

一:

Bluetooth基本概念:

Bluetooth是爱立信、诺基亚、东芝、IBM和Intel5家公司在1998年联合推出的一项无线网

络技术。

其宗旨是提供一种短距离、低成本的无线传输应用技术。

在行业协会筹备阶段,需要一个极具有表现力的名字来命名这项高新技术。

行业组织人员,在经过一夜关于欧洲历史

和未来无限技术发展的讨论后,有些人认为用Blatand国王的名字命名再合适不过了。

Blatand国王将现在的挪威,瑞典和丹麦统一起来;就如同这项即将面世的技术,将标准不一的短距离无线传输技术统一起来。

Intel负责半导体芯片和传输软件的开发,爱立信负责无线射频和移动电话软件的开发,IBM和东芝负责笔记本电脑接口规格的开发。

蓝牙是无线数据和语音传输的开放式标准,它将各种通信设备、计算机及其终端设备、各种

数字数据系统、甚至家用电器采用无线方式联接起来。

它的传输距离为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频段的微波,实现数据位流的过滤和传输,本层协议主要定义了蓝牙收发器在此频带正

常工作所需要满足的条件。

基带负责跳频以及蓝牙数据和信息帧的传输。

链路管理负责连接、

建立和拆除链路并进行安全控制。

关于bluetooth协议栈,接下来再谈。

当前已经实现的Bluetooth栈有以下各种:

1.Widcomm:

第一个windows上的协议栈,由Widcomm公司开发,也就是现在的Broadcom.

2.MicrosoftWindowsstack:

WindowsXPSP2中包括了这个内建的协议栈,开发者也可以调

用其API开发第三方软件。

3.Toshibastack:

它也是基于Windows的,不支持第三方开发,但它把协议栈授权给一些

laptop商(sony,asus等,我的本本上就是Toshiba的)。

它支持的Profile有:

SPP,DUN,FAX,LAP,OPP,FTP,HID,HCRP,PAN,BIP,HSP,HFP,A2DP,AVRCP,GAVDP)

4.BlueSoleil:

著名的IVT公司的产品.该产品可以用于桌面和嵌入式,他也支持第三方开

发,DUN,FAX,HFP,HSP,LAP,OBEX,OPP,PANSPP,AV,BIP,FTP,GAP,HID,SDAP,and

SYNC。

5.Bluez:

Linux官方协议栈,该协议栈的上层用Socket封装,便于开发者使用,通过DBUS与其它应用程序通信。

6.Affix:

NOKIA公司的协议栈,在Symbian系统上运行.

7.BlueDragon:

东软公司产品,好像2002年6月就通过了蓝牙的认证,支持的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.

8.BlueMagic:

美国OpenInterface公司forportableembeddeddivce的协议栈,iphone(apple),nav-u(sony)等很多电子产品都用该商业的协议栈,BlueMagic3.0是第一个通过bluetooth协议栈1.1认证的协议栈,那么我现在就在用它,那么该栈用起来简单,API清晰明了。

实现了的profile有:

HCI,L2CAP,RFCOMM,A/V,Remote,Control,A/V,Streaming,BIP,BPP,DUN,FAX,FTP,GAP,Ha

nds-Free,and,Headset,HCRP,HID,OBEX,OPP,PAN,BNEP,PBAP,SAP,SPP,Synchronization,Sync

ML,Telephony,XML.

9.BCHS-BluecoreHostSoftware:

蓝牙芯片CSR的协议栈,同时他也提供了一些上层应用的

Profile的库,当然了它也是为嵌入式产品了,支持的Profile有:

A2DP,AVRCP,PBAP,BIP,BPP,CTP,DUN,FAX,FMAPI,FTP

GAP,GAVDP,GOEP,HCRP,Headset,HF1.5,HID,ICP,JSR82,LAPMessageAccess

Profile,OPP,PAN,SAP,SDAP,SPP,SYNC,SYNCML。

10.WindowsCE:

微软给WindowsCE开发的协议栈,但是windowsce本身也支持其它的协议栈

11.BlueLet:

IVT公司forembeddedproduct的清量级协议栈。

BlueZ

Linux下Bluetooth协议栈的实现.Linux下开放的蓝牙协议栈主要包括IBM公司的BlueDrekar,Nokia公司的Affix,Axis公司的OpenBT和官方协议栈BlueZ。

我们主要面对Bluez来探讨。

BlueZ基础代码均是由MaximKrasnyansky完成的。

包括:

HCI,L2CAP,RFCOMM和基本socket的实现。

他就职于Qualcomm(高通)。

MarcelHoltmann开发层的协议和应用,包括:

BNEP,CMTP等。

当然,这些中也有MaximKrasnyansky的参预。

有部分代码由Nokia提供的。

Bluez是如何实现Bluetooth协议栈的呢?

它分2部分实现:

1.Kernel层实现:

正如上一篇所谈到的,bluetooth协议栈有多层结构,最底层的硬件协议在硬件中就已经实现

了。

(例如broadcom的芯片中,底层硬件协议已经包含于芯片之中了)。

软件级别的协议实

现,从HCI这一层起就可以了。

BlueZ对各层协议的实现是依托于Socket的。

BlueZ首先创建了一个新的Socket中的协议--PF_BLUETOOTH(AF_BLUETOOTH=31).(也就是说,Socket()的第一个参数:

domain必须是:

PF_BLUETOOTH)。

这也意味着,地址类型需

要使用Bluetooth所定义的。

其实很简单,就是在net_families(网络协议列表)中添加了PF_BLUETOOTH这一项。

如果对LinuxKernel有了解的话,就知道这个注册动作一定在Bluetoothinit部分作的。

同样,各个协议层(如:

HCI,L2CAP,HID等)都将自己的行为规范添加到PF_BLUETOOTH协议中。

2.应用程序层实现:

虽然Kernel层已经将Bluetooth协议栈完全实现了,但如果要使用起来,还是非常不方便的。

毕竟应用程序与kernel最方便的交流通道就是ioctl().这非常不直观。

于是,BlueZ又提供了一套API,这个API帮助开发者方便的与Kernel层协议打交道。

当然,这些API底层的实现其就是是ioctl.

BlueZ的时间,基本就是这样了。

下面咱们具体研究如何使用BlueZ所提供的这套API。

HCI

1.HCI层协议概述:

HCI提供一套统一的方法来访问Bluetooth底层。

如图所示:

从图上可以看出,HostControllerInterface(HCI)就是用来沟通Host和Module。

Host通常就是PC,Module则是以各种物理连接形式(USB,serial,pc-card等)连接到PC上的bluetoothDongle。

在Host这一端:

application,SDP,L2cap等协议都是软件形式提出的(Bluez中是以kernel层程序)。

在Module这一端:

LinkManager,BB,等协议都是硬件中firmware提供的。

而HCI则比较特殊,它一部分在软件中实现,用来给上层协议和程序提供访问接口(Bluez

中,hci.chci_usb.c,hci_sock.c等).另一部分也是在Firmware中实现,用来将软件部分的指

令等用底层协议明白的方式传递给底层。

居于PC的上层程序与协议和居于Modules的下层协议之间通过HCI沟通,有4种不同形式的传输:

Commands,Event,ACLData,SCO/eSCOData。

1.1.HCICommand:

HCICommand是Host向Modules发送命令的一种方式。

HCICommandPacket结构如下:

OpCode用来唯一标识HCICommand.它由2部分组成,10bit的OpcodeCommand.6bit的OpcodeGroup。

1.1.1:

OpCodeGroup:

LinuxKernel(BlueZ)中,~/include/net/bluetooth/hci.h中定义了OpCodeGroup。

#defineOGF_LINK_CTL0x01

#defineOGF_LINK_POLICY0x02

#defineOGF_HOST_CTL0x03

#defineOGF_INFO_PARAM0x04

#defineOGF_STATUS_PARAM0x05

它们代表了不同的CommandGroup:

OGF_LINK_CTL:

Linkcontrol,这个CommandGroup中的Command允许Host控制与其它bluetoothdevice的连接。

OGF_LINK_POLICY:

LinkPolicy。

这个CommandGroup中的Command允许调整LinkManagercontrol.

OGF_HOST_CTL:

ControlandBaseband.

1.1.2:

OpcodeCommand:

用来在同一个Group内唯一识别Command。

~/include/net/bluetooth/hci.h中定义。

1.2:

HCIEvent:

Modules向Host发送一些信息,使用HCIEvent。

EventPacket结构如下:

HCIEvent分3种:

CommandcompleteEvent,CommandStatesEvent,CommandSubsequentlyCompletend.

CommandcompleteEvent:

如果Host发送的Command可以立刻有结果,则会发送此类Event。

也就是说,如果发送的Command只与本地Modules有关,不与remote设备打交道,则使用CommandcompleteEvent。

例如:

HCI_Read_Buffer_Size.

CommandStatesEvent:

如果Host发送的Command不能立刻得知结果,则发送此类Event。

Host发送的Command执行要与Remote设备打交道,则必然无法立刻得知结果,所以会发

送CommandStatesEvent.例如:

HCIConnect。

CommandSubsequentlyCompletend:

Command延后完成Event。

例如:

连接已建立。

下图是一个Command-Event例子:

从这里可以看出,如果Host发送的Command是与Remotedevice有关的,则会先发送CommandStatesEvent。

等动作真正完成了,再发送CommandSubsequentlyCompletend。

HCIACL与SCO数据,这里就不多讲了。

只需要明白,l2cap数据是通过ACL数据传输给remotedevice的。

下图很明白的展示了l2cap数据如何一步一步转化为USB数据并传递给底层协议的。

很明显,一个l2cap包会按照规则先切割为多个HCI数据包。

HCI数据包再通过HCI-usb这一层传递给USB设备。

每个包又通过USBdriver发送到底层。

2.HCIprotocol的实现:

(稍后添加)

3.HCI层的编程:

正如上一节所说,HCI是沟通上层协议以及程序与底层硬件协议的通道。

所以,通过HCI发送的Command都是上层协议或者应用程序发送给BluetoothDongle的。

它命令BluetoothDongle(或其中的硬件协议)去做什么何种动作。

3.0:

得到Host上插入Dongle数目以及Dongle信息:

我们先复习一下socket的概念:

使用函数socket()建立一个Socket,就如同你有一部电话.bind()则是把这个电话和某个电话号码(网络地址)对应起来。

类似的,我们可以把Host理解为一个房间,这个房间有多部电话(Dongle)。

当使用socket()打开一个HCIprotocol的socket,表明得到这个房间的句柄。

HOST可能会

有多个Dongle。

换句话说,这个房间可以有多个电话号码。

所以HCI会提供一套指令去得到这些Dongle。

//0.分配一个空间给hci_dev_list_req。

这里面将放所有Dongle信息。

structhci_dev_list_req*dl;

structhci_dev_req*dr;

structhci_dev_infodi;

inti;

if(!

(dl=malloc(HCI_MAX_DEV*sizeof(structhci_dev_req)+sizeof(uint16_t)))){

perror("Can'tallocatememory");

exit

(1);

}

dl->dev_num=HCI_MAX_DEV;

dr=dl->dev_req;

//1.打开一个HCIsocket.此socket相当于一个房间。

if((ctl=socket(AF_BLUETOOTH,SOCK_RAW,BTPROTO_HCI))<0){

perror("Can'topenHCIsocket.");

exit

(1);

}

//2.使用HCIGETDEVLIST,得到所有dongle的DeviceID。

存放在dl中。

if(ioctl(ctl,HCIGETDEVLIST,(void*)dl)<0){

perror("Can'tgetdevicelist");

exit

(1);

}

//3使用HCIGETDEVINFO,得到对应DeviceID的Dongle信息。

di.dev_id=(dr+i)->dev_id;

ioctl(ctl,HCIGETDEVINFO,(void*)&di);

这样就能得到所有Dongle信息。

structhci_dev_info{

uint16_tdev_id;//dongleDeviceID

charname[8];//Donglename

bdaddr_tbdaddr;//Donglebdaddr

uint32_tflags;//DongleFlags:

如:

UP,RUNING,Down等。

uint8_ttype;//Dongle连接方式:

如USB,PCCard,UART,RS232等。

uint8_tfeatures[8];

uint32_tpkt_type;

uint32_tlink_policy;

uint32_tlink_mode;

uint16_tacl_mtu;

uint16_tacl_pkts;

uint16_tsco_mtu;

uint16_tsco_pkts;

structhci_dev_statsstat;//此Dongle的数据信息,如发送多少个ACLPacket,正确多少,错误多少,等等。

};

3.0.1:

UP和DownBluetoothDongle:

ioctl(ctl,HCIDEVUP,hdev)

ioctl(ctl,HCIDEVDOWN,hdev)

ctl:

为使用socket(AF_BLUETOOTH,SOCK_RAW,BTPROTO_HCI)打开的Socket.

hdev:

DongleDeviceID.(所以上面的Socket不需要bind,因为这边指定了)

3.1BlueZ提供的HCI编程接口一(针对本地Dongle的API系列):

3.1。

1打开一个HCISocket---inthci_open_dev(intdev_id):

这个function用来打开一个HCISocket。

它首先打开一个HCIprotocol的Socket(房间),

并将此Socket与deviceID=参数dev_id的Dongle绑定起来。

只有bind后,它才将Socket句柄与Dongle对应起来。

注意,所有的HCICommand发送之前,都需要使用hci_open_dev打开并绑定。

3.1.2:

关闭一个HCISocket:

inthci_close_dev(intdd)//简单的关闭使用hci_open_dev打开的Socket。

3.1.3:

向HCISocket(对应一个Dongle)发送request:

inthci_send_req(intdd,structhci_request*r,intto)

BlueZ提供这个function非常有用,它可以实现一切Host向Modules发送Command的功能。

参数1:

HCISocket。

参数2:

Command内容。

参数3:

以milliseconds为单位的timeout.

下面详细解释此function和用法:

当应用程序需要向Dongle(对应为一个bind后的Socket)发送Command时,调用此function.

其中,参数一dd对应一个使用hci_open_dev()打开的Socket(Dongle)。

参数三to则为等待Dongle执行并回复命令结果的timeout.以毫秒为单位。

参数二hci_request*r最为重要,首先看它的结构:

structhci_request{

uint16_togf;//OpcodeGroup

uint16_tocf;//OpcodeCommand

intevent;//此Command产生的Event类型。

void*cparam;//Command参数

intclen;//Command参数长度

void*rparam;//Response参数

intrlen;//Response参数长度

};

ogf,ocf不用多说,对应前面的图就明白这是GroupCode和CommandCode。

这两项先确定下来,然后可以查HCISpec。

察看输入参数(cparam)以及输出参数(rparam)含义。

至于他们的结构以及参数长度,则在~/include/net/bluetooth/hci.h中有定义。

至于event.如果设置,它会被setsockopt设置于Socket。

例1:

得到某个连接的PolicySetting.

HCISpec以及~/include/net/bluetooth/hci.h中均可看到,OGF=OGF_LINK_POLICY(0x02).OCF=OCF_READ_LINK_POLICY(0x0C).

因为这个Command用来读取某个ACL连接的PolicySetting。

所以输入参数即为此连接Handle.

返回参数则包含3部分,status(Command是否顺利执行),handle(连接Handle)。

policy

(得到的policy值)

这就又引入了一个新问题,如何得到某个ACL连接的Handle。

可以使用ioctlHCIGETCONNINFO得到ACL连接Handle。

ioctl(dd,HCIGETCONNINFO,(unsignedlong)cr);

Connect_handle=htobs(cr->conn_info->handle);

所以完整的过程如下:

structhci_requestHCI_Request;

read_link_policy_cpCommand_Param;

read_link_policy_rpResponse_Param;

//1.得到ACLConnectHandle

if(ioctl(dd,HCIGETCONNINFO,(unsignedlong)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;//C

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1