實戰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了。

相關文章
相關標籤/搜索