BlueR - Official BlueZ Bindings for Rust

Overview

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 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
    • querying of address, name, class, signal strength (RSSI), etc.
    • Bluetooth Low Energy advertisements
    • change events stream
    • connecting and pairing
  • 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
    • stream oriented
    • sequential packet oriented
    • datagram oriented
    • async IO interface with AsyncRead and AsyncWrite support
  • database of assigned numbers
    • manufacturer ids
    • GATT services, characteristics and descriptors

Currently, classic Bluetooth functionality is mostly unimplemented except for device discovery. However, pull requests and contributions are welcome!

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.

Crate features

All crate features are enabled by default.

  • 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.

Requirements

This library has been tested with BlueZ version 5.59 with additional patches from the master branch applied. 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.

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.

  • list_adapters: List installed Bluetooth adapters and their properties.

Use cargo run --example to run a particular example application.

Tools

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

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

    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?

    bug 
    opened by potto216 14
  • Gatt Server not offering Services

    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.

    opened by Severon96 9
  • ConnectDevice results in `org.freedesktop.DBus.Error.UnknownMethod`

    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: https://github.com/deviceplug/btleplug/issues/244

    bug 
    opened by ryankurte 9
  • Modified the advertisting_data dbus message to fix a bug preventing bluez from parsing message

    Modified the advertisting_data dbus message to fix a bug preventing bluez from parsing message

    Modified the advertisting_data dbus message to fix a bug preventing bluez from parsing the message. Also added comments on using advertising_data. This should close #49 .

    opened by potto216 5
  • BlueR does not report RSSI correctly

    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?

    external 
    opened by MaxG87 5
  • Discovery example =

    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 }
    
    opened by bobgates 5
  • Multi-central Nordic UART Service implementation

    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 https://github.com/bluez/bluer/issues/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

    enhancement 
    opened by alexandrefresnais 4
  • failed build

    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 %```
    opened by ChrisFetterly 4
  • Support for adding desired capability when registering agent

    Support for adding desired capability when registering agent

    This pull request adds support to specify desired capability when registering agent through session.register_agent(agent, "KeyboardOnly");

    Similar to how it is done here: https://github.com/bluez/bluez/blob/3f03ea4aebcee5166cd057047b5eb511eda90f42/test/simple-agent#L161 manager.RegisterAgent(path, capability);

    opened by hvardhanx 4
  • Cannot build on musl targets

    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.

    bug 
    opened by lu-zero 3
  • 'Invalid argument

    '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

    opened by BroderickCarlin 3
  • Implement bluetooth mesh support

    Implement bluetooth mesh support

    This is an initial implementation of the support for Bluetooth mesh API as discussed in issue #37

    It supports at the moment:

    • Joining and provisioning mesh networks
    • Sending and receiving messages

    Some functionalities that are not implemented yet:

    • Scanning
    • Importing/Exporting
    • Managing keys

    Currently implemented features are quite stable and we used them to implement the gateway for the EclipseCon Hackathon. They should be a good base for the further development.

    The implementation depends on the btmesh crate for representing Bluetooth mesh models. We'll release this crate shortly, so that git dependency can be removed.

    Please let me know if you have any further questions about this. Any feedback is more than welcomed.

    enhancement 
    opened by dejanb 1
  • Example for one central, multiple peripherals wanted

    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.

    documentation enhancement good first issue help wanted 
    opened by tomazbracic 1
  • Bluer causes bluetoothd to crash on armv7

    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
    external 
    opened by alexmoon 6
  • Second discovery attempt fails with InProgress error

    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.

    external 
    opened by jmagnuson 1
  • Add support for passive BLE scanning

    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.

    enhancement 
    opened by Redrield 9
Releases(v0.15.4)
Owner
BlueZ
Official Linux Bluetooth protocol stack
BlueZ
Arkworks bindings to Circom's R1CS, for Groth16 Proof and Witness generation in Rust.

ark-circom Arkworks bindings to Circom's R1CS, for Groth16 Proof and Witness generation in Rust.

Georgios Konstantopoulos 138 Dec 25, 2022
Rust language bindings for Bitcoin secp256k1 library.

Full documentation rust-secp256k1 rust-secp256k1 is a wrapper around libsecp256k1, a C library by Pieter Wuille for producing ECDSA signatures using t

Rust Bitcoin Community 250 Dec 18, 2022
Generate bindings to use Rust code in Qt and QML

Rust Qt Binding Generator This code generator gets you started quickly to use Rust code from Qt and QML. In other words, it helps to create a Qt based

KDE GitHub Mirror 768 Dec 24, 2022
Stream-based FSEvents API bindings.

fsevent-stream Stream-based FSEvents API bindings. Features Support directory-granular and file-granular events. Retrieve related file inode with kFSE

LightQuantum 7 Dec 28, 2022
Bindings to the Tauri API for projects using wasm-bindgen

tauri-sys Raw bindings to the Tauri API for projects using wasm-bindgen Installation This crate is not yet published to crates.io, so you need to use

Jonas Kruckenberg 25 Jan 9, 2023
Node.js bindings for feed_rs

Description Node.js bindings for feed_rs. Installation npm install @nooptoday/feed-rs Usage import { parse } from '@nooptoday/feed-rs' const response

null 5 Nov 17, 2023
k-mer counter in Rust using the rust-bio and rayon crates

krust is a k-mer counter written in Rust and run from the command line that will output canonical k-mers and their frequency across the records in a f

null 14 Jan 7, 2023
Experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code

Diplomat is an experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code. With Diplomat, you can simply define Rust APIs to be exposed over FFI and get high-level C, C++, and JavaScript bindings automatically!

null 255 Dec 30, 2022
Aws-sdk-rust - AWS SDK for the Rust Programming Language

The AWS SDK for Rust This repo contains the new AWS SDK for Rust (the SDK) and its public roadmap. Please Note: The SDK is currently released as a dev

Amazon Web Services - Labs 2k Jan 3, 2023
Rust + Yew + Axum + Tauri, full-stack Rust development for Desktop apps.

rust-yew-axum-tauri-desktop template Rust + Yew + Axum + Tauri, full-stack Rust development for Desktop apps. Crates frontend: Yew frontend app for de

Jet Li 54 Dec 23, 2022
A lightning fast version of tmux-fingers written in Rust, copy/pasting tmux like vimium/vimperator

tmux-thumbs A lightning fast version of tmux-fingers written in Rust for copy pasting with vimium/vimperator like hints. Usage Press ( prefix + Space

Ferran Basora 598 Jan 2, 2023
A command-line tool collection to assist development written in RUST

dtool dtool is a command-line tool collection to assist development Table of Contents Description Usage Tips Installation Description Now dtool suppor

GB 314 Dec 18, 2022
Rust mid-level IR Abstract Interpreter

MIRAI MIRAI is an abstract interpreter for the Rust compiler's mid-level intermediate representation (MIR). It is intended to become a widely used sta

Facebook Experimental 793 Jan 2, 2023
Migrate C code to Rust

C2Rust helps you migrate C99-compliant code to Rust. The translator (or transpiler) produces unsafe Rust code that closely mirrors the input C code. T

Immunant 3k Jan 8, 2023
C to Rust translator

Corrode: Automatic semantics-preserving translation from C to Rust This program reads a C source file and prints an equivalent module in Rust syntax.

Jamey Sharp 2.1k Dec 14, 2022
Astronomical algorithms in Rust

astro-rust Contents API Docs About Usage Contributing References About astro-rust is a library of advanced astronomical algorithms for the Rust progra

Saurav Sachidanand 213 Jan 7, 2023
A Rust library for calculating sun positions

sun A rust port of the JS library suncalc. Install Add the following to your Cargo.toml [dependencies] sun = "0.2" Usage pub fn main() { let unixti

Markus Kohlhase 36 Dec 28, 2022
Macro for Python-esque comprehensions in Rust

Cute Macro for Python-esque list comprehensions in Rust. The c! macro implements list and hashmap comprehensions similar to those found in Python, all

Matt Gathu 306 Jan 6, 2023
Language Integrated Query in Rust.

Linq in Rust Language Integrated Query in Rust (created by declarative macros). Inspired by LINQ in .NET. What's LINQ This project is under developmen

StardustDL 91 Dec 8, 2022