- bounty将在2天后过期**。回答此问题可获得+50声望奖励。Hristo Kamenov希望引起更多人关注此问题。
我正在尝试实现一个BLE信标,它允许请求额外的信息。
我目前的理解是,在BLE中,设备可以广播广告数据包,广告数据包可以指示设备是可扫描的,这意味着客户端可以向信标发送扫描请求,然后信标可以发送包含附加信息的扫描响应。
因此,交换的数据包将如下所示:高级扫描指示-〉扫描请求-〉扫描响应。
我试图理解beacon实现应该如何工作。这是由适配器实现的吗(我必须预先指定要在扫描响应中发送回的数据)?或者beacon应该侦听SCAN_REQ包并在看到时广播SCAN_RSP吗?
我一直在寻找在Rust或Go中使用的库,但是在这些语言中使用bluez时似乎缺乏对开发BLE外设的支持。
任何编程语言/库中的答案我都能接受,只要它能在Linux上工作
到目前为止,我得到的关闭是使用蓝色的 rust 。
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let session = bluer::Session::new().await?;
let adapter = session.default_adapter().await?;
adapter.set_powered(true).await?;
println!(
"Advertising on Bluetooth adapter {} with address {}",
adapter.name(),
adapter.address().await?
);
let mut data = BTreeMap::new();
data.insert(0, vec![1, 2, 3]);
let le_advertisement = Advertisement {
advertisement_type: bluer::adv::Type::Broadcast,
local_name: Some("le_advertise".to_string()),
advertisting_data: data,
..Default::default()
};
println!("{:?}", &le_advertisement);
let handle = adapter.advertise(le_advertisement).await?;
std::thread::sleep(std::time::Duration::from_secs(30));
println!("Removing advertisement");
drop(handle);
Ok(())
}
这适用于广播广告。我可以使用nrf连接在手机上看到它。
然而,我找不到响应扫描请求的方法,也找不到指示信标可以被扫描的方法。
2条答案
按热度按时间sr4lhrrt1#
从理论部分开始,您对扫描响应的理解是正确的。蓝牙SIG的官方定义是(Bluetooth Core Specification v5.4,Vol 1,Part A,section4.2.2.2):-
广告设备可以从监听设备接收扫描请求,以便从广告设备获得附加用户数据。扫描响应由广告设备发送到作出扫描请求的设备。
这里也提到了这一点(蓝牙核心规范v5.4,第1卷,A部分,第3.3.2.2.2节):
由通告设备发送的一些通告事件允许监听设备(扫描器)在接收到通告分组的同一通告PHY信道上并发地发送扫描请求或连接请求分组。通告设备可以在同一通告事件内在同一通告PHY信道上再次发送扫描响应分组。
扫描响应通常在设备开始通告之前设置,然而,允许在设备已经开始通告时设置或更改扫描响应。这在蓝牙规范v5.4,第4卷,E部分,7.8.8 LES设置扫描响应数据命令中提到:-
如果广告目前已启用,管制员应在后续广告活动中使用新数据。如果发布此命令时广告活动正在进行中,管制员可使用旧数据或新数据。如果广告目前已禁用,则数据应由管制员保存,并在广告启用后使用。
默认扫描响应数据长度应为零,默认扫描响应数据应为31个零八位字节。
至于实用部分,您可以使用btmgmt工具和Linux上的以下命令轻松发送扫描报告:-
其中-d选项用于设置广告数据,-s选项用于设置扫描响应数据。btmgmt add-adv选项的完整列表包括:-
广告中的BLE数据解码如下(基于on the Assigned Numbers Document):-
所以我添加的广告数据的含义:-
扫描响应数据的含义是:
一些更有用的链接:-
mm9b1k5b2#
正如你所说,你可以接受任何编程语言/库的答案--我想向你介绍一下Qt框架,特别是Qt连接模块及其蓝牙组件。下面是一个示例摘录,其中广告数据和扫描响应数据都是配置好的。
上面的例子说明了蓝牙协议栈通常是如何实现扫描响应的(特别是注意例子中的第二行和最后一行)。这个例子的完整源代码在https://code.qt.io/cgit/qt/qtconnectivity.git/tree/examples/bluetooth/heartrate-server/main.cpp?h=6.4,并在BSD许可下提供(注意,上面的摘录被修改以突出如何设置扫描响应)。
我已经在RPi上验证了上面的代码,我可以看到生成的BTLE广告使用NRFConnect添加了mfr数据。
1.将这些例子复制到你可以使用它们的地方(例如mkdir test && cd test && cp-R/usr/lib/arm-linux-gnueabihf/qt5/examples.)[我使用了一个我已经准备好的旧的rpi--你的可能是新的,因此这些例子将在默认情况下保存在不同的目录中]
1.编辑示例代码(例如cd examples/bluetooth/heartrate-server && vim main.cpp)--进行我上面指出的3个编辑
1.制造
这个例子本身并没有实现信标,但是,无论设备是信标,ble设备的通告部分在很大程度上都是相同的(仅限广告)或如果它有一项服务(或服务)。如果您从未连接到示例中的玩具服务,则它在功能上是信标。在任何情况下,当实现严格意义上是信标的设备时,将采用上述方法。此外,您已经表示希望实现"信标",但没有提供关于信标类型的进一步信息。通常,您会实现iBeacon或EddyStone信标--当然BLE规范也足够开放,允许您发明自己的信标。
要回答有关信标实施应如何运行的问题,请执行以下操作:扫描响应数据包与广告数据包具有相同的结构,并且通常在配置广告数据的同时配置它。例如,Nordic堆栈就是这样工作的。显然,您可以在上面看到QT也是这样做的。
原始的linux HCI接口在这方面稍有不同,因为必须将扫描响应指定为一个单独的命令,但有效载荷的格式与广告数据设置相同。adv数据和扫描响应数据都是在启用广告的过程中设置的。
一般来说,你的蓝牙包应该能让你设置扫描响应,就像你设置广告数据一样--这两者是紧密联系的。(软设备)实现,并且在该特定平台上,确实可以选择发送SCAN_REQ事件。通常的做法是提前设置扫描响应数据。2在Linux上,我怀疑你还能做些什么:BTLE的实现需要在收到SCAN_REQ后快速发送扫描响应,这样就没有时间往返用户区。这些数据需要已经在内核端的缓冲区中。
如果您深入研究Qt实现,您可以(最终)了解一下QLeAdvertiserBluez的实现;感兴趣的方法是setScanResponseData,它又委托给setData。对setData的调用是在isScanResponseData设置为真的情况下进行的,导致OcfLeSetScanResponseData命令被发送到Linux HCI(连同作为扫描响应传递的对象中的数据)。https://code.qt.io/cgit/qt/qtconnectivity.git/tree/src/bluetooth/qleadvertiser_bluez.cpp?h=5.15第339行。OcfLeSetScanResponseData结果是操作码命令字段0x9,其被传递到Qt的HciManager,并由此(经由套接字)连接到Linux HCI驱动器。
ocf 0x9对应于
第1651行
所以--这些都是可行的。Qt显然做到了。我不明白的是为什么你的Rust包没有公开这个相当基本的功能。BlueZ的"文档"仍然是一个无法穿透的泥潭。每次我想使用用户空间BlueZ的东西时,我都会放弃,只使用hci. h中的结构定义
[Edit] While following up some dangling leads from the above research I found an alternate C API that may also be of interest. This one is direct from the bluez folks, but has a couple of major downsides. https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/shared That's bluez.git:src/shared -- apparently it is an unofficial API with no stability guarantees. Also, documentation for it appears to be thin to the point of non-existence (no worries, though -- code is self documenting, right?). There is an example at https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/tools/eddystone.c (bluez.git:tools/eddystone.c) which could probably be altered to make a beacon with a scan response. Look at adv_tx_power_callback in eddystone.c -- one could construct a bt_hci_cmd_le_set_scan_rsp_data struct, build the data array to contain a valid manufacturer info block (or a local name, or any other valid adv block), and then send the new struct with bt_hci_send(..., BT_HCI_CMD_LE_SET_SCAN_RSP_DATA,...)