Coder Social home page Coder Social logo

bluez / bluer Goto Github PK

View Code? Open in Web Editor NEW
260.0 8.0 45.0 682 KB

BlueR — Official BlueZ Bindings for Rust

Home Page: https://crates.io/crates/bluer

License: Other

Rust 99.81% C++ 0.13% Shell 0.07%
bluetooth bluetooth-low-energy bluez l2cap gatt-client gatt-services rfcomm bluetooth-mesh

bluer's Introduction

BlueR — Official BlueZ Bindings for Rust

crates.io page docs.rs page BSD-2-Clause license

This library provides the official Rust interface to the Linux Bluetooth protocol stack (BlueZ). Both publishing local and consuming remote GATT services using idiomatic Rust code is supported. L2CAP and RFCOMM sockets are presented using an API similar to Tokio networking.

The following functionality is provided:

  • Bluetooth adapters
    • enumeration
    • configuration of power, discoverability, name, etc.
    • hot-plug support through change events stream
  • Bluetooth devices
    • discovery with custom filters
    • querying of address, name, class, signal strength (RSSI), etc.
    • Bluetooth Low Energy advertisements
    • change events stream
    • connecting and pairing
    • passive LE advertisement monitoring
  • consumption of remote GATT services
    • GATT service discovery
    • read, write and notify operations on characteristics
    • read and write operations on characteristic descriptors
    • optional use of low-overhead AsyncRead and AsyncWrite streams for notify and write operations
  • publishing local GATT services
    • read, write and notify operations on characteristics
    • read and write operations on characteristic descriptors
    • two programming models supported
      • callback-based interface
      • low-overhead AsyncRead and AsyncWrite streams
  • sending Bluetooth Low Energy advertisements
  • Bluetooth authorization agent
  • efficient event dispatching
    • not affected by D-Bus match rule count
    • O(1) in number of subscriptions
  • L2CAP sockets
    • support for both classic Bluetooth (BR/EDR) and Bluetooth LE
    • stream oriented
    • sequential packet oriented
    • datagram oriented
    • async IO interface with AsyncRead and AsyncWrite support
  • RFCOMM sockets
    • support for classic Bluetooth (BR/EDR)
    • stream oriented
    • async IO interface with AsyncRead and AsyncWrite support
  • Bluetooth Mesh
    • provision and join networks
    • send and receive messages
  • database of assigned numbers
    • manufacturer ids
    • service classes, GATT services, characteristics and descriptors

Currently, some classic Bluetooth (BR/EDR) functionality is missing. However, pull requests and contributions are welcome!

Usage

To use BlueR as a library, run the following command in your project directory:

cargo add -F full bluer

This will add the latest version of BlueR with all features enabled as a dependency to your Cargo.toml.

Crate features

The following crate features are available.

  • bluetoothd: Enables all functions requiring a running Bluetooth daemon. For building, D-Bus library headers, provided by libdbus-1-dev on Debian, must be installed.
  • id: Enables database of assigned numbers.
  • l2cap: Enables L2CAP sockets.
  • rfcomm: Enables RFCOMM sockets.
  • mesh: Enables Bluetooth mesh functionality.
  • serde: Enables serialization and deserialization of some data types.

To enable all crate features specify the full crate feature.

Requirements

The minimum support Rust version (MSRV) is 1.75.

This library has been tested with BlueZ 5.60. Older versions might work, but be aware that many bugs related to GATT handling exist. Refer to the official changelog for details.

If any bluetoothd feature is used the Bluetooth daemon must be running and configured for access over D-Bus. On most distributions this should work out of the box.

For mesh feature Bluetooth mesh daemon must be running and configured for access over D-Bus.

Configuration

The following options in /etc/bluetooth/main.conf are helpful when working with GATT services.

[GATT]
Cache = no
Channels = 1

This disables the GATT cache to avoid stale data during device discovery.

By only allowing one channel the extended attribute protocol (EATT) is disabled. If EATT is enabled, all GATT commands and notifications are sent over multiple L2CAP channels and can be reordered arbitrarily by lower layers of the protocol stack. This makes sequential data transmission over GATT characteristics more difficult.

Building

When cloning this repository make sure to use the following command. Otherwise the build will fail with file not found errors.

git clone --recursive https://github.com/bluez/bluer.git

D-Bus development headers are required for building.

Troubleshooting

The library returns detailed errors received from BlueZ.

Set the Rust log level to trace to see all D-Bus communications with BlueZ.

In some cases checking the Bluetooth system log might provide further insights. On Debian-based systems it can be displayed by executing journalctl -u bluetooth. Check the bluetoothd man page for increasing the log level.

Sometimes deleting the system Bluetooth cache at /var/lib/bluetooth and restarting bluetoothd fixes persistent issues with device connectivity.

Examples

Refer to the API documentation and examples folder for examples.

The following example applications are provided.

  • discover_devices: Discover Bluetooth devices and print their properties.

  • gatt_client: Simple GATT client that calls read, write and notify on a characteristic.

  • gatt_server_cb: Corresponding GATT server implemented using callback programming model.

  • gatt_server_io: Corresponding GATT server implemented using IO programming model.

  • gatt_echo_client: Simple GATT client that connects to a server and sends and receives test data.

  • gatt_echo_server: Corresponding GATT server that echos received data.

  • l2cap_client: Simple L2CAP socket client that connects to a socket and sends and receives test data.

  • l2cap_server: Corresponding L2CAP socket server that echos received data.

  • le_advertise: Register Bluetooth LE advertisement.

  • le_passive_scan: LE passive scan & subscribe to updates for discovered peripheral(s).

  • list_adapters: List installed Bluetooth adapters and their properties.

  • mesh_sensor_client: Simple Bluetooth mesh client sending sensor model messages

  • mesh_sensor_server: Simple Bluetooth mesh server receiving sensor model messages

  • mesh_provisioner: Simple Bluetooth mesh provisioner

  • rfcomm_client: Simple RFCOMM socket client that connects to a socket and sends and receives test data.

  • rfcomm_server: Corresponding RFCOMM socket server that echos received data.

Use cargo run --all-features --example <name> to run a particular example application.

Tools

See the BlueR tools crate for tools that build on this library.

History

This project started as a fork of blurz but has since then become a full rewrite. It was published under the name blez before it was designated the official Rust interface to BlueZ and renamed to BlueR. Documentation has been mostly copied from the BlueZ API specification, but also adapted where it makes sense.

bluer's People

Contributors

bsphere avatar dati91 avatar eijebong avatar gh2o avatar hugmanrique avatar jaqchen avatar jmagnuson avatar jpumc avatar kjetijor avatar lu-zero avatar m1cha avatar manio avatar mattarsamer avatar mxk avatar ngoquang2708 avatar ngotchac avatar nicolaskagami avatar nithinmuthukumar avatar otaviojr avatar oxc avatar pflakus avatar potto216 avatar pythops avatar riomus avatar rtzoeller avatar sameer avatar simonsapin avatar sireliah avatar surban avatar taha-firoz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bluer's Issues

all_properties() device method not found

Hello I'm trying to use bluer in my project, but i'm facing a problem regarding the all_properties device method.
It's seems missing.
My cargo.lock show the following ;
[[package]]
name = "bluer"
version = "0.13.3"

I use rust into buildroot for rpi3 target

Problem importing bluer

UPDATE: When I import bluer = { version = "0.15", features = ["full"] } it seems to work. Where in the docs can I read about how to set up the most minimum import?

Hi, I'm having some problems using bluer. I assume there is a problem with my Cargo.toml file but I don't see my error.

Error:

   Compiling bluer v0.15.5
   Compiling ble v0.1.0 (/home/xxx/playground/mossmoss/ble)
error[E0432]: unresolved imports `bluer::AdapterEvent`, `bluer::DeviceEvent`
 --> src/main.rs:1:13
  |
1 | use bluer::{AdapterEvent, DeviceEvent};
  |             ^^^^^^^^^^^^  ^^^^^^^^^^^ no `DeviceEvent` in the root
  |             |
  |             no `AdapterEvent` in the root
error[E0433]: failed to resolve: could not find `Session` in `bluer`
 --> src/main.rs:6:26
  |
6 |     let session = bluer::Session::new().await?;
  |                          ^^^^^^^ could not find `Session` in `bluer`

Cargo:

[package]
name = "ble"
version = "0.1.0"
edition = "2021"

[dependencies]
bluer = "0.15"
tokio = { version = "1.24", features = ["full"] }
futures = "0.3"

Code:
Similar to the discover device example.

Thanks!

Add support for passive BLE scanning

I'm trying to use bluer on a raspberry pi to scan for advertising BLE devices. In doing some research, I'm fairly certain that bluer only supports active (ie. scan request) discovery, and that there is code in BlueZ to support passive scanning (used in hcitool lescan, for example), but there isn't anything in bluer to give access to passive scanning.

Gatt echo example, no services found

Hey, I'm currently tring out the gatt echo server/client example, but somehow the services()call returns an empty vec and therefore never retrieves the provided characteristics. I have no clue how to debug this.

I'm on latest main branch and bluez is version 5.66-1

failed build

Hi, sorry am quite new to rust. I keep getting build errors and am unsure how to resolve. This is a result of using the git clone --recursive https://github.com/bluez/bluer.git command then cd into the cloned repo and cargo build.

(base) chrisfetterly@computer % cargo build
    Updating crates.io index
  Downloaded proc-macro2 v1.0.36
  Downloaded 1 crate (41.4 KB) in 0.55s
   Compiling proc-macro2 v1.0.36
   Compiling libc v0.2.112
   Compiling unicode-xid v0.2.2
   Compiling syn v1.0.84
   Compiling cfg-if v1.0.0
   Compiling memchr v2.4.1
   Compiling log v0.4.14
   Compiling futures-core v0.3.19
   Compiling autocfg v1.0.1
   Compiling slab v0.4.5
   Compiling pin-project-lite v0.2.7
   Compiling version_check v0.9.3
   Compiling futures-channel v0.3.19
   Compiling futures-task v0.3.19
   Compiling futures-sink v0.3.19
   Compiling futures-util v0.3.19
   Compiling pin-utils v0.1.0
   Compiling futures-io v0.3.19
   Compiling serde_derive v1.0.132
   Compiling pkg-config v0.3.24
   Compiling serde v1.0.132
   Compiling cfg-if v0.1.10
   Compiling unicode-segmentation v1.8.0
   Compiling bytes v1.1.0
   Compiling once_cell v1.9.0
   Compiling serde_json v1.0.73
   Compiling lazy_static v1.4.0
   Compiling signal-hook v0.3.13
   Compiling itoa v1.0.1
   Compiling bitflags v1.3.2
   Compiling parking_lot_core v0.8.5
   Compiling ryu v1.0.9
   Compiling scopeguard v1.1.0
   Compiling smallvec v1.7.0
   Compiling bytes v0.5.6
   Compiling pin-project-lite v0.1.12
   Compiling async-trait v0.1.52
   Compiling hashbrown v0.11.2
   Compiling byteorder v1.4.3
   Compiling ppv-lite86 v0.2.15
   Compiling termcolor v1.1.2
   Compiling regex-syntax v0.6.25
   Compiling unicode-width v0.1.9
   Compiling humantime v2.1.0
   Compiling hex v0.4.3
   Compiling strsim v0.10.0
   Compiling pretty-hex v0.2.1
   Compiling instant v0.1.12
   Compiling lock_api v0.4.5
   Compiling proc-macro-error-attr v1.0.4
   Compiling proc-macro-error v1.0.4
   Compiling unicase v2.6.0
   Compiling memoffset v0.6.5
   Compiling indexmap v1.7.0
   Compiling num-traits v0.2.14
   Compiling textwrap v0.14.2
   Compiling heck v0.3.3
   Compiling libdbus-sys v0.2.2
   Compiling aho-corasick v0.7.18
   Compiling os_str_bytes v4.2.0
   Compiling quote v1.0.10
   Compiling regex v1.5.4
   Compiling signal-hook-registry v1.4.0
   Compiling num_cpus v1.13.1
   Compiling mio v0.7.14
   Compiling getrandom v0.2.3
   Compiling iovec v0.1.4
   Compiling net2 v0.2.37
   Compiling atty v0.2.14
   Compiling nix v0.23.1
   Compiling bytes v0.4.12
   Compiling uuid v0.8.2
   Compiling rand_core v0.6.3
   Compiling parking_lot v0.11.2
   Compiling mio v0.6.23
   Compiling rand_chacha v0.3.1
   Compiling signal-hook-mio v0.2.1
   Compiling rand v0.8.4
   Compiling crossterm v0.22.1
   Compiling mio-uds v0.6.8
   Compiling env_logger v0.9.0
   Compiling tokio v0.2.25
   Compiling synstructure v0.12.6
   Compiling futures-macro v0.3.19
   Compiling tokio-macros v1.7.0
   Compiling pin-project-internal v1.0.9
   Compiling custom_debug_derive v0.5.0
   Compiling strum_macros v0.22.0
   Compiling displaydoc v0.2.3
   Compiling num-derive v0.3.3
   Compiling clap_derive v3.0.0-beta.5
   Compiling tokio v1.15.0
   Compiling custom_debug v0.5.0
   Compiling pin-project v1.0.9
   Compiling strum v0.22.0
   Compiling clap v3.0.0-beta.5
   Compiling dbus v0.9.5
   Compiling futures-executor v0.3.19
   Compiling futures v0.3.19
   Compiling tab-pty-process v0.2.0
   Compiling tokio-stream v0.1.8
   Compiling tokio-compat-02 v0.2.0
   Compiling dbus-tokio v0.7.5
   Compiling dbus-crossroads v0.5.0
   Compiling bluer v0.13.1 (/Users/chrisfetterly/Projects/RustProjects/bluer/bluer)
error[E0432]: unresolved imports `libc::SOCK_CLOEXEC`, `libc::SOCK_NONBLOCK`
 --> bluer/src/sock.rs:3:49
  |
3 | use libc::{c_int, c_ulong, sockaddr, socklen_t, SOCK_CLOEXEC, SOCK_NONBLOCK};
  |                                                 ^^^^^^^^^^^^  ^^^^^^^^^^^^^ no `SOCK_NONBLOCK` in the root
  |                                                 |
  |                                                 no `SOCK_CLOEXEC` in the root
  |
help: a similar name exists in the module
  |
3 | use libc::{c_int, c_ulong, sockaddr, socklen_t, O_CLOEXEC, SOCK_NONBLOCK};
  |                                                 ~~~~~~~~~
help: a similar name exists in the module
  |
3 | use libc::{c_int, c_ulong, sockaddr, socklen_t, SOCK_CLOEXEC, O_NONBLOCK};
  |                                                               ~~~~~~~~~~

error[E0432]: unresolved imports `libc::SOCK_CLOEXEC`, `libc::SOCK_NONBLOCK`
 --> bluer/src/gatt/mod.rs:5:22
  |
5 | use libc::{AF_LOCAL, SOCK_CLOEXEC, SOCK_NONBLOCK, SOCK_SEQPACKET};
  |                      ^^^^^^^^^^^^  ^^^^^^^^^^^^^ no `SOCK_NONBLOCK` in the root
  |                      |
  |                      no `SOCK_CLOEXEC` in the root
  |
help: a similar name exists in the module
  |
5 | use libc::{AF_LOCAL, O_CLOEXEC, SOCK_NONBLOCK, SOCK_SEQPACKET};
  |                      ~~~~~~~~~
help: a similar name exists in the module
  |
5 | use libc::{AF_LOCAL, SOCK_CLOEXEC, O_NONBLOCK, SOCK_SEQPACKET};
  |                                    ~~~~~~~~~~

error[E0432]: unresolved imports `libc::AF_BLUETOOTH`, `libc::SOL_BLUETOOTH`, `libc::TIOCINQ`
  --> bluer/src/l2cap.rs:21:5
   |
21 |     AF_BLUETOOTH, EAGAIN, EINPROGRESS, MSG_PEEK, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_SEQPACKET,
   |     ^^^^^^^^^^^^ no `AF_BLUETOOTH` in the root
22 |     SOCK_STREAM, SOL_BLUETOOTH, SOL_SOCKET, SO_ERROR, SO_RCVBUF, TIOCINQ, TIOCOUTQ,
   |                  ^^^^^^^^^^^^^ no `SOL_BLUETOOTH` in the root    ^^^^^^^ no `TIOCINQ` in the root

error[E0432]: unresolved imports `libc::AF_BLUETOOTH`, `libc::SOL_BLUETOOTH`, `libc::TIOCINQ`
  --> bluer/src/rfcomm/mod.rs:16:12
   |
16 |     c_int, AF_BLUETOOTH, EAGAIN, EINPROGRESS, MSG_PEEK, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_RAW, SOCK_STREAM,
   |            ^^^^^^^^^^^^ no `AF_BLUETOOTH` in the root
17 |     SOL_BLUETOOTH, SOL_SOCKET, SO_ERROR, SO_RCVBUF, TIOCINQ, TIOCOUTQ,
   |     ^^^^^^^^^^^^^ no `SOL_BLUETOOTH` in the root    ^^^^^^^ no `TIOCINQ` in the root

error[E0425]: cannot find function `accept4` in crate `libc`
   --> bluer/src/sock.rs:147:15
    |
147 |         libc::accept4(socket.as_raw_fd(), saddr.as_mut_ptr() as *mut _, &mut length, SOCK_CLOEXEC | SOCK_NONBLOCK)
    |               ^^^^^^^ help: a function with a similar name exists: `accept`
    |
   ::: /Users/chrisfetterly/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.112/src/unix/mod.rs:610:5
    |
610 |     pub fn accept(socket: ::c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> ::c_int;
    |     ----------------------------------------------------------------------------------------------- similarly named function `accept` defined here

Some errors have detailed explanations: E0425, E0432.
For more information about an error, try `rustc --explain E0425`.
error: could not compile `bluer` due to 5 previous errors
(base) chrisfetterly@computer bluer %```

Bluetoothd crash caused by call to adapter.discover_devices

On armv7, kernel 5.4.70, with bluez 5.55, 5.60 or 5.63, the following program always causes bluetoothd to crash with SIGABRT due to corrupted memory. This seems to be due to the cleanup for the device stream: if you uncomment the loop, the crash will not occur until you press ctrl-c to terminate the program.

#[tokio::main(flavor = "current_thread")]
async fn main() -> bluer::Result<()> {
    let session = bluer::Session::new().await?;
    let adapter = session.default_adapter().await?;
    println!("Discovering devices using Bluetooth adapter {}", adapter.name());
    adapter.set_powered(true).await?;

    let device_events = adapter.discover_devices().await?;
    futures::pin_mut!(device_events);
    // loop {}
    Ok(())
}

I'm posting this issue here because the equivalent commands in bluetoothctl cause no issue.

power on
scan on
scan off
exit

Cant build examples

Hi there,

I am quite new to rust and want to test this library but I cant import bluer correctly. I get the following error:

error[E0432]: unresolved imports `bluer::Adapter`, `bluer::AdapterEvent`, `bluer::DeviceEvent`

My Cargo manifest looks as follows

[package]
name = "discover"
version = "0.1.0"
edition = "2021"

[dependencies]
bluer = "0.15.0"

and as a source file I am using the discover example.

Is there something else I am missing when building the application?

Advertisement min_interval and max_interval are ignored

When modifying le_advertise.rs example to set custom min_interval / max_interval these seem to be just ignored. No matter what values I set, interval remains at default ~1280 ms.

OS: Debian 11
bluer: 0.13.1
bluez: 5.55-3.1 (Debian package)

Example for one central, multiple peripherals wanted

Hi,

would it be possible to add some more examples to the documentation? Implementing one central with multiple peripherals and notify from them for instance. What would be an idiomatic approach to do this.

Thanks in advance.

Multiple architectures in CI

Bug #2 has shown that we need to test the build on more architectures than amd64.

We should set up the CI process to build on i386, amd64, armhf and arm64 at least.

How do I avoid os: error 111 (connection refused).

Hello, I am attempting to make a lightweight device driver for the LG Magic Remote. However, when I try to connect to it through l2cap it errors out with an os error 111. This is my code so far. It just tries to connect to the Magic Remote and it begins to receive packets.

use bluer::{
    l2cap::{SocketAddr, Stream, PSM_LE_DYN_START},
    Address,
};
use tokio::io::AsyncReadExt;

#[tokio::main]
async fn main() -> bluer::Result<()> {
    let addr: Address = "7C:02:BC:C5:14:3B".parse().unwrap();
    let socket_addr = SocketAddr::new(addr, bluer::AddressType::LePublic, PSM_LE_DYN_START + 5);
    println!("Connecting to magic remote");
    let mut stream = Stream::connect(socket_addr).await?;
    println!("Local address: {:?}", stream.as_ref().local_addr()?);
    println!("Remote address: {:?}", stream.peer_addr()?);
    println!("Recv MTU: {}", stream.as_ref().recv_mtu()?);
    println!("Security: {:?}", stream.as_ref().security()?);

    loop {
        let mut hello_buf = [0u8; 30];
        stream
            .read_exact(&mut hello_buf)
            .await
            .expect("read failed");
        println!("Received: {:?}", hello_buf);
    }
}

This is what it prints out

Connecting to magic remote
Local address: SocketAddr { addr: E0:D4:E8:38:4D:65, addr_type: LePublic, psm: 133, cid: 64 }
Remote address: SocketAddr { addr: 7C:02:BC:C5:14:3B, addr_type: LePublic, psm: 133, cid: 0 }
Recv MTU: 672
Security: Security { level: Medium, key_size: 0 }
thread 'main' panicked at 'read failed: Os { code: 111, kind: ConnectionRefused, message: "Connection refused" }', src/main.rs:23:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Any ideas? Thanks!

Give access to DiscoveryFilter

Is there any particular reason why access to the discovery filter is restricted. I'm facing quite a few issues with the dbus api scans just not performing as well. This time I'm testing everything on a dedicated linux machine with Bluez 5.66. I had assumed the poor performance of the bluetooth scans were because of my adapter or bluez being buggy but now since I tried hci-tools le scan the performance on that is almost instantaneous and I don't face any weird problems where all devices suddenly disappear and the scan just stops working entirely showing no results(this happens in bluetoothctl).

When I looked into it setting the duplicate_data parameter in bluetoothctl with transport le dramatically improved the scanning results. Is there any reason why access to the filter is restricted, I mean we have keep the api as it is right now but have an additional option to set a custom DeviceFilter in the adapter object. I'd give the PR a try but of course I don't know why it's been restricted, it may cause other problems.

Setting the advertisting_data field of the Advertisement struct generates a parse error in BlueZ

I cannot set the advertisting_data field of the Advertisement struct to a valid value.
Every value I have tried for advertisting_data: BTreeMap<u8, Vec<u8>> results in a BlueR error of

Advertising on Bluetooth adapter hci0 with address 00:E0:42:AB:3D:03
Advertisement { advertisement_type: Peripheral, service_uuids: {}, manufacturer_data: {}, solicit_uuids: {}, service_data: {}, advertisting_data: {1: [6]}, discoverable: Some(true), discoverable_timeout: None, system_includes: {}, local_name: Some("le_advertise"), appearance: None, duration: None, timeout: None, secondary_channel: None, min_interval: None, max_interval: None, tx_power: None, _non_exhaustive: () }
Error: Error { kind: Failed, message: "Failed to parse advertisement." }

which results from the BlueZ bluetoothd which has the following debug information indicating an error parsing the Data property

Sep 25 12:37:17 debian rsyslogd: [origin software="rsyslogd" swVersion="8.2102.0" x-pid="551" x-info="https://www.rsyslog.com"] rsyslogd was HUPed
Sep 25 12:38:54 debian bluetoothd[541]: src/advertising.c:register_advertisement() RegisterAdvertisement
Sep 25 12:38:54 debian bluetoothd[541]: src/advertising.c:client_create() Adding proxy for /org/bluez/bluer/advertising/2fdf9eaa36a544799667bac89cbaec17
Sep 25 12:38:54 debian bluetoothd[541]: src/advertising.c:register_advertisement() Registered advertisement at path /org/bluez/bluer/advertising/2fdf9eaa36a544799667bac89cbaec17
Sep 25 12:38:54 debian bluetoothd[541]: src/advertising.c:parse_advertisement() Error parsing Data property

I have looked in BlueZ's advertising.c, but it is unclear why it isn't happy with what BlueR is sending to it over D-Bus.

I have followed Silicon Lab's recommendation for sending advertising data.

For the advertising data type (the u8) I am following Bluetooth Document Generic Access Profile Revision Date: 2021-07-13 Assigned numbers and GAP.

I am assuming the advertising data is the data being placed in the AdvData field of ADV_IND, ADV_NONCONN_IND, ADV_SCAN_IND, AUX_ADV_IND, and AUX_CHAIN_IND PDUs as defined in
Bluetooth Core Specification 5.3:Vol. 3, Part C section 11

For the below examples test_data is defined as let mut test_data = BTreeMap::<u8, Vec<u8>>::new(); is being passed to the advertisement:

    let le_advertisement = Advertisement {
        advertisement_type: bluer::adv::Type::Peripheral,
        advertisting_data: test_data,
        discoverable: Some(true),
        local_name: Some("le_advertise".to_string()),
        ..Default::default()
    };

The following all generate the same parse error.
I set flag data type, 0x01, and I send data 0x06 test_data.insert(0x01, vec![0x06]);

I set the Complete List of 16-bit Service Class UUIDs data type, 0x03, with test_data.insert(0x01, vec![0x09, 0x18]); which is Health Thermometer service 0x1809

I set the Complete Local Name data type, 0x09, with test_data.insert(0x09, vec![0x54, 0x68, 0x65, 0x72, 0x6D, 0x6F, 0x6d, 0x65, 074, 0x65, 0x72, 0x20, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65]); which is "Thermometer Example"

Any thoughts on what the problem is?

Bluer causes bluetoothd to crash on armv7

On a Raspberry Pi 4 running 32-bit Pi OS, the following program will cause bluetoothd to crash when the program exits:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    {
        let session = bluer::Session::new().await?;
        let adapter = session.default_adapter().await?;
        let _scan = adapter.discover_devices().await?;
    }

    // This delay is just to demonstrate that the crash occurs on program exit, not dropping of bluer objects
    // The crash still occurs with no delay
    tokio::time::sleep(std::time::Duration::from_secs(5)).await;
    Ok(())
}

Running this program causes bluetoothd to crash with an error similar to the following:

Sep 17 17:54:53 raspberrypi bluetoothd[2535]: realloc(): invalid next size

I believe this is the same issue that was previously reported in #9. However, the bluetoothctl program does not cause bluetoothd when performing scans, so there must be something different with bluer's interactions. It is also interesting to note that the crash does not occur until the program exits, even though the bluer objects are already dropped. Also, unlike #9, this crash is occurring on normal program exit, not Ctrl+C.

One thing I note in the DBus logs is that on initialization, a number of DBus matches are added:

method call time=1663451688.404791 sender=:1.206 -> destination=org.freedesktop.DBus serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'"
method return time=1663451688.404874 sender=org.freedesktop.DBus -> destination=:1.206 serial=3 reply_serial=2
method call time=1663451688.406506 sender=:1.206 -> destination=org.freedesktop.DBus serial=3 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesRemoved'"
method return time=1663451688.406605 sender=org.freedesktop.DBus -> destination=:1.206 serial=4 reply_serial=3
method call time=1663451688.408146 sender=:1.206 -> destination=org.freedesktop.DBus serial=4 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'"
method return time=1663451688.408211 sender=org.freedesktop.DBus -> destination=:1.206 serial=5 reply_serial=4
method call time=1663451688.409329 sender=:1.206 -> destination=org.freedesktop.DBus serial=5 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
   string "type='method_call'"
method return time=1663451688.409430 sender=org.freedesktop.DBus -> destination=:1.206 serial=6 reply_serial=5

However, when the objects are dropped, only one of those matches is removed:

method call time=1663451688.577775 sender=:1.206 -> destination=org.freedesktop.DBus serial=11 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=RemoveMatch
   string "type='signal',sender='org.bluez',interface='org.freedesktop.DBus.ObjectManager',member='InterfacesAdded'"
method return time=1663451688.577808 sender=org.freedesktop.DBus -> destination=:1.206 serial=7 reply_serial=11

I don't know enough about DBus or bluez to know if that could cause the problem or if it's just a red herring, but it's the only unusual thing in the DBus logs that jumped out to me.

Versions:

  • bluer: 0.15.0
  • bluez: 5.55-3.1+rpt1
  • bluez-firmware: 1.2-4+rpt8

Gatt Server not offering Services

Hey guys,

can someone help me please, because i'm a little confused why i'm not seeing any services when using a BTLE Scanner?

I used the GATT-Server implementation that is documented here:
https://docs.rs/bluer/latest/src/gatt_server_io/gatt_server_io.rs.html

I changed nothing, also i'm using the UUIDs from the gatt.inc.
Maybe someone can help me here? Because I don't know what the problem is.

I fixed the initial issue, that I had, by using the UUIDs from the examples. But I'm certain that that's not the right way to work with the crate.

PSM should be u16

I discover bluer for a personal project which uses an l2cap device.
After searching for pieces of information about the PSM, I don't understand why the PSM is encoded using an 8-bit unsigned integer while bluez and the Bluetooth references use a 16bit unsigned integer instead.

Is this supposed to be private?

I can't use the AsyncRead or AsyncWrite traits for Stream, defined in src/rfcomm/mod.rs. The compiler says they're private. But how else am I supposed to write to a stream?

Cannot build on musl targets

While building for aarch64-unknown-linux-musl:

   Compiling bluer v0.15.1 (/tmp/bluer/bluer)
error[E0308]: mismatched types
   --> bluer/src/sys.rs:188:38
    |
188 | pub const RFCOMMCREATEDEV: c_ulong = request_code_write!('R', 200, size_of::<c_int>());
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `i32`
    |
    = note: this error originates in the macro `ioc` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
   --> bluer/src/sys.rs:189:39
    |
189 | pub const RFCOMMRELEASEDEV: c_ulong = request_code_write!('R', 201, size_of::<c_int>());
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `i32`
    |
    = note: this error originates in the macro `ioc` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0061]: this function takes at least 2 arguments but 3 arguments were supplied
   --> bluer/src/sock.rs:303:24
    |
303 |     let ret = unsafe { libc::ioctl(socket.as_raw_fd(), request, value.as_mut_ptr()) };
    |                        ^^^^^^^^^^^                     -------  ------------------ argument unexpected
    |                                                        |
    |                                                        expected `i32`, found `u64`
    |
note: function defined here
   --> /home/lu_zero/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.135/src/unix/linux_like/linux/musl/mod.rs:727:12
    |
727 |     pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int;
    |            ^^^^^
help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit
    |
303 |     let ret = unsafe { libc::ioctl(socket.as_raw_fd(), request.try_into().unwrap(), value.as_mut_ptr()) };
    |                                                               ++++++++++++++++++++
help: remove the extra argument
    |
303 |     let ret = unsafe { libc::ioctl(socket.as_raw_fd(), /* i32 */) };
    |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0061]: this function takes at least 2 arguments but 3 arguments were supplied
   --> bluer/src/sock.rs:314:24
    |
314 |     let ret = unsafe { libc::ioctl(socket.as_raw_fd(), request, value as *const _) };
    |                        ^^^^^^^^^^^                     -------  ----------------- argument unexpected
    |                                                        |
    |                                                        expected `i32`, found `u64`
    |
note: function defined here
   --> /home/lu_zero/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.135/src/unix/linux_like/linux/musl/mod.rs:727:12
    |
727 |     pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int;
    |            ^^^^^
help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit
    |
314 |     let ret = unsafe { libc::ioctl(socket.as_raw_fd(), request.try_into().unwrap(), value as *const _) };
    |                                                               ++++++++++++++++++++
help: remove the extra argument
    |
314 |     let ret = unsafe { libc::ioctl(socket.as_raw_fd(), /* i32 */) };
    |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
   --> bluer/src/l2cap.rs:404:64
    |
404 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCINQ)?;
    |                            ----------------                    ^^^^^^^ expected `u64`, found `i32`
    |                            |
    |                            arguments to this function are incorrect
    |
note: function defined here
   --> bluer/src/sock.rs:301:8
    |
301 | pub fn ioctl_read<T>(socket: &OwnedFd, request: c_ulong) -> Result<T> {
    |        ^^^^^^^^^^    ----------------  ----------------
help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
404 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCINQ.try_into().unwrap())?;
    |                                                                       ++++++++++++++++++++

error[E0308]: mismatched types
   --> bluer/src/l2cap.rs:412:64
    |
412 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCOUTQ)?;
    |                            ----------------                    ^^^^^^^^ expected `u64`, found `i32`
    |                            |
    |                            arguments to this function are incorrect
    |
note: function defined here
   --> bluer/src/sock.rs:301:8
    |
301 | pub fn ioctl_read<T>(socket: &OwnedFd, request: c_ulong) -> Result<T> {
    |        ^^^^^^^^^^    ----------------  ----------------
help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
412 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCOUTQ.try_into().unwrap())?;
    |                                                                        ++++++++++++++++++++

error[E0308]: mismatched types
   --> bluer/src/rfcomm/mod.rs:254:64
    |
254 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCINQ)?;
    |                            ----------------                    ^^^^^^^ expected `u64`, found `i32`
    |                            |
    |                            arguments to this function are incorrect
    |
note: function defined here
   --> bluer/src/sock.rs:301:8
    |
301 | pub fn ioctl_read<T>(socket: &OwnedFd, request: c_ulong) -> Result<T> {
    |        ^^^^^^^^^^    ----------------  ----------------
help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
254 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCINQ.try_into().unwrap())?;
    |                                                                       ++++++++++++++++++++

error[E0308]: mismatched types
   --> bluer/src/rfcomm/mod.rs:262:64
    |
262 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCOUTQ)?;
    |                            ----------------                    ^^^^^^^^ expected `u64`, found `i32`
    |                            |
    |                            arguments to this function are incorrect
    |
note: function defined here
   --> bluer/src/sock.rs:301:8
    |
301 | pub fn ioctl_read<T>(socket: &OwnedFd, request: c_ulong) -> Result<T> {
    |        ^^^^^^^^^^    ----------------  ----------------
help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
262 |         let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCOUTQ.try_into().unwrap())?;
    |

I wonder if the socket abstraction couldn't now go away since std has its own OwnedFd now.

contributing

I'd like to possibly contribute to this project - is it still actively maintained?

org.freedesktop.DBus.Error.InvalidArgs: No such property 'AdvertisingData'

i am trying to get access to the "raw" manufaturer data from a device (contrary to the parsed manufacturer data, as the device i am trying to interact with doesnt follow the key/value structure described in the standard).

Unfortunately when i am trying to retrieve the advertising data like this:
println!(" Advertising data: {:?}", device.advertising_data().await?);

i am getting the following error:
Error: internal error: D-Bus error org.freedesktop.DBus.Error.InvalidArgs: No such property 'AdvertisingData'

Does anyone has an idea why this would happen?

Remove dependency on libbluetooth

BlueZ plans to deprecate libbluetooth in the future.

We should remove our dependency on it and import the required C definitions directly.

GATT per-client notifications are currently unsupported

Hello here!

Coming back on #62
I was preparing a Nordic UART Service example following your addition to the library but I cannot make it working.
When writing to the notifier of a client, both my phones get notified.

A few months ago, I took a look at BlueZ DBuS API and saw nothing to notify a specific client.
We asked if it was possible in an issue but no one answered (bluez/bluez#409)

So, following the previous issue, do you think this service is really possible with BlueR ?
I have serious belief that it is not currently possible in anyway with BlueZ.

examples/discover_devices.rs – struct `DiscoveryFilter` is private

I'm attempting to run examples/discover_devices.rs in my own project. The steps were

  1. cargo new [project-name]
  2. As per #43 added the dependencies
    2.1 cargo add -F full bluer
    2.2 cargo add tokio
    2.3 cargo add env_logger
    2.4 cargo add futures
  3. Copy code from examples/discover_devices.rs into src/main.rs
  4. cargo run

However then I get:

error[E0603]: struct `DiscoveryFilter` is private

The full error log is blow:

error[E0603]: struct `DiscoveryFilter` is private
   --> src/main.rs:3:58
    |
3   | use bluer::{Adapter, AdapterEvent, Address, DeviceEvent, DiscoveryFilter, DiscoveryTransport};
    |                                                          ^^^^^^^^^^^^^^^ private struct
    |
note: the struct `DiscoveryFilter` is defined here
   --> /home/rbeattie/.cargo/registry/src/index.crates.io-1cd66030c949c28d/bluer-0.15.7/src/lib.rs:536:17
    |
536 | pub use crate::{adapter::*, device::*, session::*};
    |                 ^^^^^^^^^^

error[E0603]: enum `DiscoveryTransport` is private
   --> src/main.rs:3:75
    |
3   | use bluer::{Adapter, AdapterEvent, Address, DeviceEvent, DiscoveryFilter, DiscoveryTransport};
    |                                                                           ^^^^^^^^^^^^^^^^^^ private enum
    |
note: the enum `DiscoveryTransport` is defined here
   --> /home/rbeattie/.cargo/registry/src/index.crates.io-1cd66030c949c28d/bluer-0.15.7/src/lib.rs:536:17
    |
536 | pub use crate::{adapter::*, device::*, session::*};
    |                 ^^^^^^^^^^

error[E0599]: no method named `set_discovery_filter` found for struct `Adapter` in the current scope
  --> src/main.rs:58:13
   |
58 |     adapter.set_discovery_filter(filter).await?;
   |             ^^^^^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `set_discoverable`

error[E0599]: no method named `discovery_filter` found for struct `Adapter` in the current scope
  --> src/main.rs:59:60
   |
59 |     println!("Using discovery filter:\n{:#?}\n\n", adapter.discovery_filter().await);
   |                                                            ^^^^^^^^^^^^^^^^ method not found in `Adapter`

Some errors have detailed explanations: E0599, E0603.
For more information about an error, try `rustc --explain E0599`.
error: could not compile `discover` (bin "discover") due to 5 previous errors

I wonder is this related to #90?

Discovery example = "Invalid arguments in method call"

I'm not able to run the discover_devices example:

Platform:
5.10.17-v7+ #1421 SMP Thu May 27 13:59:01 BST 2021 armv7l GNU/Linux
Using bluez 5.50.

I get this error:

Error: Error { kind: InvalidArguments, message: "Invalid arguments in method call" }

The code fails on this line in adapter.rs, in the function discovery_session, around about line 140 (I've been messing with code, line number is vague):

                    self.call_method("SetDiscoveryFilter", (filter.to_dict(),)).await?;

The filter it is called with contains:

DiscoveryFilter { uuids: {}, rssi: None, pathloss: None, transport: Auto, duplicate_data: false, discoverable: false, pattern: None }

BlueR does not report RSSI correctly

For a little toy project I need to obtain the strength of a signal from a Bluetooth device. I do not think this is relevant, but for the record, the devices are

  • Google Pixel 4a with latest Android
  • ASUSTek Computer, Inc. Broadcom BCM20702A0 Bluetooth (as reported by lsusb)

I am running Kernel 5.9.11, self compiled. I am using BlueR 0.13.3, because Debian's Cargo only provides Rust 1.54.

I am able to get the information I want using hcitool rssi <addr>. It seems as if my phone needs to be connected via Bluetooth, but once it is I get reliable connection strengths.

When I try to run the example discover_devices.rs, the connection strength is always reported as None. If I try to run discover_devices with --changes, sometimes I get a change RSSI event, but only once in a while, while I would need it regularly.

I even tried to write my own loop, but to no avail.

use bluer::Address;
use std::{collections::HashSet, env};

#[tokio::main(flavor = "current_thread")]
async fn main() -> bluer::Result<()> {
    // let with_changes = env::args().any(|arg| arg == "--changes");
    let filter_addr: HashSet<_> = env::args()
        .filter_map(|arg| arg.parse::<Address>().ok())
        .collect();

    env_logger::init();
    let session = bluer::Session::new().await?;
    let adapter = session.default_adapter().await?;
    loop {
        for cur_addr in &filter_addr {
            let device = adapter.device(*cur_addr)?;
            let rssi = device.rssi().await?;
            println!("{cur_addr}: {rssi:?}");
        }
    }
}

Is there something I do miss? How would I get the RSSI of a connection reliably, without relying on ChangeEvents?

Need tests

Currently there are no tests. This is bad!

However, testing is not so easy in our case. At least two systems with Bluetooth adapters are required to exercise the functionality of this crate.

Ideally, we will have a test lab with two machines (Raspberry Pi(e)s would do!) that hook into the CI process and run a test suite after each commit. The machines need to be synchronized, since one must provide a GATT server while the other is the client and vice versa, etc.

We should check if BlueZ already has some testing infrastructure in place that we could use.

ConnectDevice results in `org.freedesktop.DBus.Error.UnknownMethod`

hi there,

attempting to use Adapter::connect_device results in:

Error { kind: Internal(DBus("org.freedesktop.DBus.Error.UnknownMethod")), message: "Method \"ConnectDevice\" with signature \"a{ss}\" on interface \"org.bluez.Adapter1\" doesn't exist\n" }

i have enabled experimental features in bluetoothd, and d-feet shows this method does exist:

image

it appears that bluez is expecting an a{sv} signature (a string:variant dictionary) while bluer is calling with a{ss} (a string:string dictionary). i had a go at patching this, but it also seems that bluer won't compile when included via a path ¯\(ツ)

error: failed to run custom build command for `bluer v0.13.2 (/home/ryan/projects/forks/bluer/bluer)`

Caused by:
  process didn't exit successfully: `/home/ryan/projects/spo2/target/debug/build/bluer-55d669f39f7d50ee/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-changed=service_class_uuids.json
  cargo:rerun-if-changed=bluetooth-numbers-database/v1/service_uuids.json

  --- stderr
  thread 'main' panicked at 'services: Os { code: 2, kind: NotFound, message: "No such file or directory" }', /home/ryan/projects/forks/bluer/bluer/build.rs:227:6

relates to: deviceplug/btleplug#244

Resuming server notification sessions

I'm implementing battery and HID peripheral services, which require caching of CCCD state across client connections. As far as I can tell, the current behavior for both StartNotify and AcquireNotify is that the notification session persists across client re-connections, but as soon as either the rust process or bluetoothd itself are restarted, there is no way to resume notifications. These services specify that the client is not required to re-enable notifications on each subsequent connection after bonding, so the client assumes that notifications will just work from there on.

I thought this would be controlled by the Cache option in main.conf, but that doesn't seem to be the case, at least not across bluetoothd restarts.

Is this a fundamental issue with the bluez API or is there some functionality that would enable this use case that isn't exposed in bluer?

bluetoothd crashes when discover_devices is terminated

Which leads to a crash of bluetoothd at least on ARMv7 with versions 5.55 and 5.60:
free(): invalid next size (fast)

Limited testing on x86_64 shows no crash with 5.48, though the stop_fn never get's called as well.

Reason:
discover_devices() holds a SingleSessionToken while single_session() spawns a task waiting to receive something on the other end of the channel. AFAICT it won't ever receive something, so the stop_fn is never called which would stop the discovery and clean up.

How to reproduce:
run RUST_LOG=trace ./discover_devices and hit CTRL+C, notice a log missing "StopDiscovery" like:

'''
[2021-08-11T12:47:23Z TRACE bluer::session] Connected to D-Bus with unique name :1.4321
[2021-08-11T12:47:23Z TRACE mio::poll] registering event source with poller: token=Token(0), interests=READABLE
[2021-08-11T12:47:23Z TRACE bluer::session] Starting event loop for :1.4321
Discovering devices using Bluetooth adapater hci0

[2021-08-11T12:47:23Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.Powered := true
[2021-08-11T12:47:23Z TRACE bluer::session] Starting new single session for /org/bluez/hci0
[2021-08-11T12:47:23Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.SetDiscoveryFilter ({"UUIDs": Variant([]), "Transport": Variant("auto"), "DuplicateData": Variant(false), "Discoverable": Variant(false)},)
[2021-08-11T12:47:23Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.SetDiscoveryFilter (...) -> Ok(())
[2021-08-11T12:47:23Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.StartDiscovery ()
[2021-08-11T12:47:23Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.StartDiscovery (...) -> Ok(())
[2021-08-11T12:47:23Z TRACE bluer::session] Adding event subscription for /org/bluez/hci0 with child_objects=true
[2021-08-11T12:47:23Z TRACE bluer::session] Event: PropertiesChanged { object: Path("/org/bluez/hci0\u{0}"), interface: "org.bluez.Adapter1", changed: {"Discovering": Variant(true)} }
...
^C
'''

If you modify the discover_devices example to drop the adapter earlier, then there's still no "StopDiscovery" in the log as expected

Sleeping on main thread prevents dispatching of events

Hi,

i'm currently running a debian 11 install with bluez 5.55 on it (the default package version from debian repo) and want to implement a small geofencing application.

Currently i'm stuck in bluer not getting any pairing requests from bluez.

This is the rust code:

use bluer::{id, agent::{Agent, RequestAuthorization, ReqResult, RequestConfirmation, AuthorizeService, DisplayPinCode, DisplayPasskey}, Uuid, UuidExt};
use core::time;
use std::{thread, str::FromStr, fmt};
use log::{info};

#[derive(Clone, Copy)]
struct UuidOrShort(pub Uuid);

impl FromStr for UuidOrShort {
    type Err = String;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        match s.parse::<Uuid>() {
            Ok(uuid) => Ok(Self(uuid)),
            Err(_) => match u16::from_str_radix(s, 16) {
                Ok(short) => Ok(Self(Uuid::from_u16(short))),
                Err(_) => Err(s.to_string()),
            },
        }
    }
}

impl From<UuidOrShort> for Uuid {
    fn from(u: UuidOrShort) -> Self {
        u.0
    }
}

impl From<Uuid> for UuidOrShort {
    fn from(u: Uuid) -> Self {
        Self(u)
    }
}

impl fmt::Display for UuidOrShort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(s) = self.0.as_u16() {
            write!(f, "{:04x}", s)
        } else {
            write!(f, "{}", self.0)
        }
    }
}

async fn request_authorization(req: RequestAuthorization) -> ReqResult<()> {
    info!("Is device {} on {} allowed to pair? (y/n)", &req.device, &req.adapter);
    Ok(())
}

async fn request_confirmation(req: RequestConfirmation) -> ReqResult<()> {
    info!("Is device {} on {} allowed to pair? (y/n)", &req.device, &req.adapter);
    Ok(())
}

async fn authorize_service(req: AuthorizeService) -> ReqResult<()> {
    let service_id = match id::Service::try_from(req.service) {
        Ok(name) => format!("{} ({})", name, UuidOrShort(req.service)),
        Err(_) => format!("{}", UuidOrShort(req.service)),
    };
    info!("Is device {} on {} allowed to use service {}? (y/n)", &req.device, &req.adapter, service_id);
    Ok(())
}

async fn display_pin_code(req: DisplayPinCode) -> ReqResult<()> {
    info!("PIN code for device {} on {} is \"{}\"", &req.device, &req.adapter, req.pincode);
    Ok(())
}

async fn display_passkey(req: DisplayPasskey) -> ReqResult<()> {
    info!("Passkey for device {} on {} is \"{:06}\"", &req.device, &req.adapter, req.passkey);
    Ok(())
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> bluer::Result<()> {
    env_logger::init();
    let session = bluer::Session::new().await?;
    let adapter = session.default_adapter().await?;
    info!("Free pairing devices for {}", adapter.name());
    adapter.set_powered(true).await?;

    let agent = Agent {
        request_default: true,
        display_pin_code: Some(Box::new(|req| Box::pin(display_pin_code(req)))),
        display_passkey: Some(Box::new(|req| Box::pin(display_passkey(req)))),
        request_confirmation: Some(Box::new(move |req| {
            Box::pin(request_confirmation(req))
        })),
        request_authorization: Some(Box::new(move |req| {
            Box::pin(request_authorization(req))
        })),
        authorize_service: Some(Box::new(|req| Box::pin(authorize_service(req)))),
        ..Default::default()
    };
    let _agent_handle = session.register_agent(agent).await?;

    adapter.set_pairable_timeout(0).await?;
    adapter.set_pairable(true).await?;
    adapter.set_discoverable_timeout(0).await?;
    adapter.set_discoverable(true).await?;

    thread::sleep(time::Duration::from_secs(600));

    Ok(())
}

BlueZ returns a src/agent.c:simple_agent_reply() Timed out waiting for reply from agent when not in debug mode.

BlueR trace logs:

[2022-04-08T22:44:43Z TRACE bluer::session] Connected to D-Bus with unique name :1.1911
[2022-04-08T22:44:43Z TRACE mio::poll] registering event source with poller: token=Token(1), interests=READABLE
[2022-04-08T22:44:43Z TRACE bluer::session] Starting event loop for :1.1911
[2022-04-08T22:44:43Z INFO  ble_fencer] Free pairing devices for hci0
[2022-04-08T22:44:43Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.Powered := true
[2022-04-08T22:44:43Z TRACE bluer::agent] Publishing agent at /org/bluez/bluer/agent/af0e3da48d3b4568a49ccc8b8a9bb289 with capability DisplayYesNo
[2022-04-08T22:44:43Z TRACE bluer::agent] Registering agent at /org/bluez/bluer/agent/af0e3da48d3b4568a49ccc8b8a9bb289
[2022-04-08T22:44:43Z TRACE bluer::agent] Requesting default agent for /org/bluez/bluer/agent/af0e3da48d3b4568a49ccc8b8a9bb289
[2022-04-08T22:44:43Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.PairableTimeout := 0
[2022-04-08T22:44:43Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.Pairable := true
[2022-04-08T22:44:43Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.DiscoverableTimeout := 0
[2022-04-08T22:44:43Z TRACE bluer::adapter] /org/bluez/hci0: org.bluez.Adapter1.Discoverable := true

BlueZ journalctl with debug on:

Apr 09 00:44:39 kube bluetoothd[259103]: src/adapter.c:new_settings_callback() Settings: 0x00000acb
Apr 09 00:44:39 kube bluetoothd[259103]: src/adapter.c:settings_changed() Changed settings: 0x00000010
Apr 09 00:44:39 kube bluetoothd[259103]: src/adapter.c:settings_changed() Pending settings: 0x00000000
Apr 09 00:44:43 kube bluetoothd[259103]: src/agent.c:add_default_agent() Default agent set to :1.1911 /org/bluez/bluer/agent/af0e3da48d3b4568a49ccc8b8a9bb289
Apr 09 00:44:43 kube bluetoothd[259103]: src/adapter.c:set_mode() sending set mode command for index 0
Apr 09 00:44:43 kube bluetoothd[259103]: src/agent.c:agent_ref() 0x560e0db50750: ref=1
Apr 09 00:44:43 kube bluetoothd[259103]: src/agent.c:register_agent() agent :1.1911
Apr 09 00:44:43 kube bluetoothd[259103]: src/adapter.c:new_settings_callback() Settings: 0x00000adb
Apr 09 00:44:43 kube bluetoothd[259103]: src/adapter.c:settings_changed() Changed settings: 0x00000010
Apr 09 00:44:43 kube bluetoothd[259103]: src/adapter.c:settings_changed() Pending settings: 0x00000000
Apr 09 00:44:43 kube bluetoothd[259103]: src/adapter.c:set_discoverable() sending set mode command for index 0
Apr 09 00:44:43 kube bluetoothd[259103]: src/adapter.c:set_mode() sending set mode command for index 0
Apr 09 00:44:56 kube bluetoothd[259103]: src/adapter.c:connected_callback() hci0 device A0:4F:85:01:A7:08 connected eir_len 12
Apr 09 00:44:56 kube bluetoothd[259103]: src/device.c:device_create() dst A0:4F:85:01:A7:08
Apr 09 00:44:56 kube bluetoothd[259103]: src/device.c:device_new() address A0:4F:85:01:A7:08
Apr 09 00:44:56 kube bluetoothd[259103]: src/device.c:device_new() Creating device /org/bluez/hci0/dev_A0_4F_85_01_A7_08
Apr 09 00:44:56 kube bluetoothd[259103]: src/device.c:device_set_class() /org/bluez/hci0/dev_A0_4F_85_01_A7_08 0x5A020C
Apr 09 00:44:57 kube bluetoothd[259103]: src/adapter.c:user_confirm_request_callback() hci0 A0:4F:85:01:A7:08 confirm_hint 0
Apr 09 00:44:57 kube bluetoothd[259103]: src/device.c:new_auth() Requesting agent authentication for A0:4F:85:01:A7:08
Apr 09 00:44:57 kube bluetoothd[259103]: src/agent.c:agent_ref() 0x560e0db50750: ref=2
Apr 09 00:44:57 kube bluetoothd[259103]: src/agent.c:agent_request_confirmation() Calling Agent.RequestConfirmation: name=:1.1911, path=/org/bluez/bluer/agent/af0e3da48d3b4568a49ccc8b8a9bb289, passkey=827801
Apr 09 00:45:16 kube bluetoothd[259103]: src/adapter.c:bonding_attempt_complete() hci0 bdaddr A0:4F:85:01:A7:08 type 0 status 0x5
Apr 09 00:45:16 kube bluetoothd[259103]: src/device.c:device_bonding_complete() bonding (nil) status 0x05
Apr 09 00:45:16 kube bluetoothd[259103]: src/agent.c:send_cancel_request() Sending Cancel request to :1.1911, /org/bluez/bluer/agent/af0e3da48d3b4568a49ccc8b8a9bb289
Apr 09 00:45:16 kube bluetoothd[259103]: src/device.c:device_cancel_authentication() Canceling authentication request for A0:4F:85:01:A7:08
Apr 09 00:45:16 kube bluetoothd[259103]: src/agent.c:agent_unref() 0x560e0db50750: ref=1
Apr 09 00:45:16 kube bluetoothd[259103]: src/device.c:device_bonding_failed() status 5
Apr 09 00:45:16 kube bluetoothd[259103]: src/adapter.c:resume_discovery()
Apr 09 00:45:16 kube bluetoothd[259103]: src/adapter.c:dev_disconnected() Device A0:4F:85:01:A7:08 disconnected, reason 3
Apr 09 00:45:16 kube bluetoothd[259103]: src/adapter.c:adapter_remove_connection()
Apr 09 00:45:16 kube bluetoothd[259103]: plugins/policy.c:disconnect_cb() reason 3
Apr 09 00:45:16 kube bluetoothd[259103]: src/adapter.c:bonding_attempt_complete() hci0 bdaddr A0:4F:85:01:A7:08 type 0 status 0xe
Apr 09 00:45:16 kube bluetoothd[259103]: src/device.c:device_bonding_complete() bonding (nil) status 0x0e
Apr 09 00:45:16 kube bluetoothd[259103]: src/device.c:device_bonding_failed() status 14
Apr 09 00:45:16 kube bluetoothd[259103]: src/adapter.c:resume_discovery()
Apr 09 00:45:46 kube bluetoothd[259103]: src/device.c:device_remove() Removing device /org/bluez/hci0/dev_A0_4F_85_01_A7_08
Apr 09 00:45:46 kube bluetoothd[259103]: src/device.c:btd_device_unref() Freeing device /org/bluez/hci0/dev_A0_4F_85_01_A7_08
Apr 09 00:45:46 kube bluetoothd[259103]: src/device.c:device_free() 0x560e0db5a1e0

Is this because i don't run blueZ 5.60? If so would it be possible, maybe with a PR, to get compability with the default debian version?

Thanks :)

Can't build code depending on bluer = "0.10.2"

Gentlemen!

I'm seeing "no method named try_read_buf found" issues when building my code, having included a dependency to bluer 0.10.2 (please find my config and build output with exact error message below).

I'm not trying to manually build the bluer library, but rather consume it from crates.io (i guess).

I do have a bit aged version of Bluez on my system (5.53 I believe), but I'm not convinced this is the real issue at this stage as I'm experiencing build issues rather than runtime issues.


Development environment:

  • Ubuntu 20.04
  • bluez 5.53-0ubuntu3.3
  • libdbus-1-dev 1.12.16-2ubuntu2.1
  • cargo 1.53.0 (4369396ce 2021-04-27)
  • rustc 1.53.0 (53cb7b09b 2021-06-17)

Cargo.toml:

[package]
name = "hello"
version = "0.0.1-snapshot"
edition = "2018"

[dependencies]
bluer = "0.10.2"

The critical part of cargo build output:

   Compiling bluer v0.10.2
error[E0599]: no method named `try_read_buf` found for struct `tokio::net::UnixStream` in the current scope
   --> /home/monster/.cargo/registry/src/github.com-1ecc6299db9ec823/bluer-0.10.2/src/gatt/mod.rs:134:29
    |
134 |         let n = self.stream.try_read_buf(&mut buf)?;
    |                             ^^^^^^^^^^^^ help: there is an associated function with a similar name: `try_read`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: could not compile `bluer`

[Question] How to send the report update from a server to connected client?

Hi,

This might be a stupid question as I'm not very familiar with Bluetooth in general. I'm so sorry.

I'm trying to emulate a Bluetooth mouse using the library and a Raspberry Pi. I have implement all the required service and characteristic for HID over GATT. The end device, an iPhone, can see and connect to the Pi running the server. It stays connected and read these characteristic:

ManufacturerNameString - Read request CharacteristicReadRequest { offset: 0, mtu: 517, link: Some(Le) }
ReportMap - Read request CharacteristicReadRequest { offset: 0, mtu: 517, link: Some(Le) }
HidInformation - Read request CharacteristicReadRequest { offset: 0, mtu: 517, link: Some(Le) }
BatteryLevel - Read request CharacteristicReadRequest { offset: 0, mtu: 517, link: Some(Le) }

However, I'm not sure how I can start sending the update to the iOS device, for example new X/Y coordinate. I have a Characteristic::Report that has read and notify implement, but it never gets called for some reason. I also have another Characteristic::BootMouseInputReport with read and write, but that is not called either. After connecting to the iOS device, it just stays there.

I looked around a bit and found the example for writing notification using IO, but that still require the iOS device to initiate the notification session first, I think.

So my question is how can I send the update to iOS device after connected? Seems like no way to get the writer without receiving the notification request first.

The services and characteristic I have are:

HID Service
    Report
    Protocol Mode
    Report Map
    Boot Mouse Input Report
    Hid Information
    Hid Control Point

Battery Service
    Battery Level

Device Information Service
    Manufacturer Name String
    PnP ID

Please let me know if this is not the appropriate place for this. I will try and remove it asap.

Thank you so much for your time and help.

Can't compile libbluetooth

Lots of errors like:

pub const RFCOMMGETDEVINFO: u64 = request_code_read!('R', 211, std::mem::size_of::<c_int>());
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found `u32` 

when building on Raspberry Pi running:
Linux raspberrypi 5.10.17-v7+ #1421 SMP Thu May 27 13:59:01 BST 2021 armv7l GNU/Linux

Using bluez 5.50. Let me try to install 5.59.

The errors occur when trying to build libbluetooth. I guess that's why there is a an existing issue to remove the dependency?

Multi-central Nordic UART Service implementation

Hello,

First, thanks for the amazing work!

I would like to know if it should be possible to implement the Nordic UART Service specification with this API ?

I know this question looks related to #58 but I cannot precisely see how it could be done in this specific case.

The Nordic documentation specifies that a central client may write on a RX Characteristic, and get answered with a notification.
As an example, I took a look at the gatt_echo_server and I could not see how I could echo the specific client which wrote me.

I understand that I can have multiple Write and Notify events, but I cannot see how I could link a writer and a notifier to answer the good client.

Is it possible ?

Thanks!

Regards,

Alexandre

failed to resolve

Hey,
I'm new to Rust and maybe there is something that I don't understand.
I want to write a little test-app to play around. When I try to use bluer in the current version (0.15.1) like let session = bluer::Session::new(); I always get the message: error[E0433]: failed to resolve: could not find `Session` in `bluer` . But if I downgrade the version to 0.13.3 everything works as expected.
Is there a bug or is it just me, don't getting it?

internal error: D-Bus error org.freedesktop.DBus.Error.InvalidArgs: No such property 'Notifying'

Running a modified gatt_client example,

$ uname -a
Linux klh-desktop 6.1.10-artix1-1 #1 SMP PREEMPT_DYNAMIC Mon, 06 Feb 2023 18:16:02 +0000 x86_64 GNU/Linux
$ rustup show
[...]
active toolchain
----------------
stable-x86_64-unknown-linux-gnu (default)
rustc 1.68.2 (9eb3afe9e 2023-03-27)
$ bluetoothctl --version
bluetoothctl: 5.66

The device I'm connecting to is some no-brand smart watch, it uses two characteristics to implement serial communication, one of them is write_without_response only, which means there is no Notify property on the DBus object. That results in an error:

Characteristic UUID: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
    Device failed: internal error: D-Bus error org.freedesktop.DBus.Error.InvalidArgs: No such property 'Notifying'

As a quick fix I changed src/gatt/remote.rs:506 to make this property OPTIONAL instead of MANDATORY and now it works (and to be fair the BlueZ docs indicate this property is optional: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt)

I have zero knowledge about this project though, so I'm not sure if that change even makes sense. It's also possible that my BT adapter (TP-Link UB500) or BlueZ has issues, because the advertisements sometimes contain no or wrong services (at least for this device). Same behavior on a known good OnePlus 5T BT adapter (and BlueZ 5.64), works fine with the quick fix.

For some reason I can't enable tracing, RUST_LOG=trace doesn't work on cargo run or running the executable directly, but I don't think it's needed here?

Discover and auto pair with password

Hi,
I don't know if this is possible but I made a small program to connect to a solar inverter and right now I'm using bluetoothctl with the help of a script to auto discover the device and pair it. ¿Is there any way to do this from directly from rust code? So I can avoid using cron, hacky scripts, etc just to pair a device?

Thank you in advance.

'Invalid argument "mtu"' when attempting to write local characteristic

Attempting to setup a GATT peripheral with a basic writeable characteristic but attempts to actually perform a write (or write without response) consistently result in the following error:

[2022-04-27T22:13:26Z TRACE bluer] /org/bluez/bluer/gatt/app/4bef7b60a5124fc0b5de51b736b207a8/service0/char1: org.bluez.GattCharacteristic1.WriteValue ([1], {"link": Variant("LE"), "device": Variant(Path("/org/bluez/hci0/dev_7C_3E_56_10_96_8E\u{0}"))})
[2022-04-27T22:13:26Z TRACE bluer] /org/bluez/bluer/gatt/app/4bef7b60a5124fc0b5de51b736b207a8/service0/char1: org.bluez.GattCharacteristic1.WriteValue (...) -> Err(MethodErr(ErrorName("org.freedesktop.DBus.Error.InvalidArgs\u{0}"), "Invalid argument \"mtu\""))

This same error occurs when running the example GATT servers provided as well as the GATT server(s) hosted by bluer-tools.

Bluer version: 0.14.0
Bluez version: 5.58
D-Bus Message Bus Daemon: 1.12.2
libdbus-1-dev: 1.12.2-1ubuntu1.2

Property events

Hello,

i'm using the latest version of bluer to get information from a ble device with sends periodic information by advertising.

The property manufacture data is changing periodic, but the example "discover devices" with option --changes is getting only RSSI events, not others.

Same using the function discover_devices_with_changes()...Only RSSI events...

This is an expected behavior?

Second discovery attempt fails with InProgress error

Device: Raspberry Pi zero 2w
OS: Yocto Linux
BlueZ: 5.64

Running the gatt_client example the first time succeeds as expected:

root@yocto:/tmp# ./gatt_client
Discovering on Bluetooth adapter hci0 with address B8:27:EB...

...

Discovered device B8:27:EB... with service UUIDs {00000002-e900-4e66-854c-cde416ae1332, 00000000-0000-0000-0000-0000feedc0de}
    Manufacturer data: Some(...)
    Device provides our service!
    Connecting...
    Connect error: Bluetooth operation failed: le-connection-abort-by-local
    Connected
    Enumerating services...
    Service UUID: 00001801-0000-1000-8000-00805f9b34fb
    Service data: [Primary(true), Uuid(00001801-0000-1000-8000-00805f9b34fb), Includes([])]
    Service UUID: 00001800-0000-1000-8000-00805f9b34fb

...

    Stopping notification IO
    Characteristic exercise completed
    Device disconnected

Stopping discovery

And I can see both StartDiscovery and StopDiscovery going over DBus:

method call time=1662105582.357526 sender=:1.71 -> destination=org.bluez serial=12 path=/org/bluez/hci0; interface=org.bluez.Adapter1; member=StartDiscovery
method return time=1662105582.361596 sender=:1.61 -> destination=:1.71 serial=189 reply_serial=12
signal time=1662105582.367611 sender=:1.61 -> destination=(null destination) serial=190 path=/org/bluez/hci0; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.bluez.Adapter1"
   array [
      dict entry(
         string "Discovering"
         variant             boolean true
      )
   ]
   array [
   ]

...

method call time=1662105596.823707 sender=:1.71 -> destination=org.bluez serial=16 path=/org/bluez/hci0; interface=org.bluez.Adapter1; member=StopDiscovery
method return time=1662105596.828165 sender=:1.61 -> destination=:1.71 serial=222 reply_serial=16

However, subsequent attempts fail with org.bluez.Error.InProgress:

root@yocto:/tmp# ./gatt_client
Discovering on Bluetooth adapter hci0 with address B8:27:EB...

Error: Error { kind: InProgress, message: "Operation already in progress" }

root@yocto:/tmp# bluetoothctl show | grep Discovering
        Discovering: no
method call time=1662107942.325967 sender=:1.80 -> destination=org.bluez serial=10 path=/org/bluez/hci0; interface=org.bluez.Adapter1; member=StartDiscovery
error time=1662107942.330377 sender=:1.61 -> destination=:1.80 error_name=org.bluez.Error.InProgress reply_serial=10
   string "Operation already in progress"

I have been able to correct this by power cycling with bluetoothctl power on/off, but ideally there's something that can be done in bluer to avoid this.

I'm not an expert on the BlueZ DBus API, but it seems like it may have to do with the device connection being made after discovery, since I do not see this issue with the discover_devices example, which only does device discovery and no connection attempts.

Put windows deps in (default-included) feature

Due to idiosyncrasies of how cargo resolves dependencies, all the Windows dependencies show up in Cargo.lock files even on Linux -- and in Yocto builds, which is making our build process more difficult. Features do not have the same issue.

There should be a "windows" feature, included by default to avoid breaking existing clients, that can be explicitly disabled if the windows dependencies are not going to be used. This will make building easier on Yocto and other build systems.

I am willing to (and going to) write a PR for this; I'm just adding an issue first for discussion in principle.

Implement Mesh API

Is an implementation the BlueZ D-Bus Mesh API within the scope of this project? Anyone currently working on it or have a desire to?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.