(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了。