实战Linux Bluetooth编程(四) L2CAP层编程

(L2CAP协议简介,L2CAP在BlueZ中的实现以及L2CAP编程接口) git

 

一:L2CAP协议简介: 编程

Logical Link Control and Adaptation Protocol(L2CAP) dom

 

逻辑链接控制和适配协议 (L2CAP) 为上层协议提供面向链接和无链接的数据服务,并提供多协议功能和分割重组操做。L2CAP 充许上层协议和应用软件传输和接收最大长度为 64K  L2CAP 数据包。 socket

  L2CAP 基于 通道(channel) 的概念。 通道 (Channel) 是位于基带 (baseband) 链接之上的逻辑链接。每一个通道以多对一的方式绑定一个单一协议 (single protocol)。多个通道能够绑定同一个协议,但一个通道不能够绑定多个协议。 每一个在通道里接收到的 L2CAP 数据包被传到相应的上层协议。 多个通道可共享同一个基带链接。 ide

 

L2CAP处于Bluetooth协议栈的位置以下: ui

也就是说,全部L2CAP数据均经过HCI传输到Remote Device。且上层协议的数据,大都也经过L2CAP来传送。 spa

 

 

L2CAP能够发送Command。例如链接,断连等等。 rest

 

下面看Command例子:Connection Request: orm

 

其中PSM比较须要注意,L2CAP 使用L2CAP链接请求(Connection Request )命令中的PSM字段实现协议复用。L2CAP能够复用发给上层协议的链接请求,这些上层协议包括服务发现协议SDP(PSM = 0x0001)、RFCOMM(PSM = 0x0003)和电话控制(PSM = 0x0005)等。 htm

 

 

Protocol PSM Reference
SDP 0x0001 See Bluetooth Service Discovery Protocol (SDP), Bluetooth SIG.
RFCOMM 0x0003 See RFCOMM with TS 07.10, Bluetooth SIG.
TCS-BIN 0x0005 See Bluetooth Telephony Control Specification / TCS Binary, Bluetooth SIG.
TCS-BIN-CORDLESS 0x0007 See Bluetooth Telephony Control Specification / TCS Binary, Bluetooth SIG.
BNEP 0x000F See Bluetooth Network Encapsulation Protocal, Bluetooth SIG.
HID_Control 0x0011 See Human Interface Device , Bluetooth SIG.
HID_Interrupt 0x0013 See Human Interface Device, Bluetooth SIG.
UPnP 0x0015 See [ESDP] , Bluetooth SIG.
AVCTP 0x0017 See Audio/Video Control Transport Protocol , Bluetooth SIG.
AVDTP 0x0019 See Audio/Video Distribution Transport Protocol , Bluetooth SIG.
AVCTP_Browsing 0x001B See Audio/Video Remote Control Profile, Bluetooth SIG
UDI_C-Plane 0x001D See the Unrestricted Digital Information Profile [UDI], Bluetooth SIG

 

 

 

 

二: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这些状态:

Sam在刚开始本身作L2CAP层链接时,使用另外一台Linux机器插USB Bluetooth Dongle做Remote Device。怎么也无法使用inquiry扫描到remote设备,也无法链接remote设备,甚至没法使用l2ping ping到remote设备。以为很是奇怪,后来才发现Remote Device状态设置有问题。没有设置PSCAN和ISCAN。

Inquiry Scan状态表示设备可被inquiry. Page Scan状态表示设备可被链接。

#hciconfig hci0 iscan

#hciconfig hci0 pscan

或者:#hciconfig hci0 piscan

就能够设置为PSCAN或者iSCAN状态了。

编程则可使用ioctl(HCISETSCAN) . dev_opt = SCAN_INQUIRY;dr.dev_opt = SCAN_PAGE;dr.dev_opt = SCAN_PAGE | SCAN_INQUIRY;

则能够inquiry或者connect了。

相关文章
相关标签/搜索