deviceplug / btleplug

Rust Cross-Platform Host-Side Bluetooth LE Access Library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

prevent re-use of dropped peripheral

jcaude opened this issue · comments

Hello,

I hesitate filling a feature request or a bug. But since it happens with erroneous code I prefer to see it as a FR.

On macOS (not tested on other platforms), the following sequence goes in an infinite waiting loop:

  • 1/ scan
  • 2/ connect to a peripheral
  • 3/ disconnect the peripheral
  • 4/ as if the peripheral is connected <== stuck in an await.

I am fully aware that step 4 is wrong, still it should not await indefinitely (at least panic)

The feature request is:

"could we add a timeout() on the connect(), disconnect() and is_connected() functions or use reference counting at some point."

I hope I make a clear statement.

jC

ps/ as code usually says more:

use std::error::Error;
use std::time::Duration;

use btleplug::api::{Central, Manager as _, Peripheral as _, ScanFilter};
use btleplug::platform::{Adapter, Manager, Peripheral};
use log::info;
use tokio::io::AsyncWriteExt as _;
use tokio::{io, time};

pub async fn bug_is_connected(adapter: &Adapter) -> Result<(), Box<dyn Error>> {
    info!("IS-CONNECTED TEST");
    let mut device: Option<Peripheral> = None;
    // scan
    info!(" 1) Scan");
    adapter
        .start_scan(ScanFilter::default())
        .await
        .expect("Can't scan BLE adapter for connected devices...");
    time::sleep(Duration::from_secs(10)).await;
    // list peripherals
    let peripherals = adapter.peripherals().await?;
    if peripherals.is_empty() {
        eprintln!("->>> BLE peripheral devices were not found, sorry. Exiting...");
    } else {
        // All peripheral devices in range
        for peripheral in peripherals.iter() {
            let properties = peripheral.properties().await?;
            let is_connected = peripheral.is_connected().await?;
            let local_name = properties
                .unwrap()
                .local_name
                .unwrap_or(String::from("(peripheral name unknown)"));
            println!(
                "Peripheral {:?} {:?} is connected: {:?}",
                local_name,
                peripheral.id(),
                is_connected
            );
            io::stdout().flush().await?;
            if local_name.contains("iPhone") {
                device = Some(peripheral.clone());
                break;
            }
        }
    } 
      // connect
    info!(" 2) Connect device");
    if let Some(iphone) = &device {
        iphone.connect().await?;
        let is_connected = iphone.is_connected().await?;
        println!("iPhone is connected: {:?}", is_connected);
    }
    //
    info!(" 3) Disconnect device");
    if let Some(iphone) = &device {
        iphone.disconnect().await?;
    }
    info!(" 4) Check connection status");
    if let Some(iphone) = &device {
        let is_connected = iphone.is_connected().await?; // infinite await here..
        println!("iPhone is connected: {:?}", is_connected);
    } 
    // eop
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    env_logger::init();
    info!("BtLEPlug Test Code");
    // init.
    let manager = Manager::new().await?;
    let adapter_list = manager.adapters().await?;
    if adapter_list.is_empty() {
        eprintln!("No Bluetooth adapters found");
    }
    let adapter = adapter_list.first().unwrap(); // we have at least one ..

    // TEST 1
    bug_is_connected(&adapter).await?;

    // eop
    Ok(())
}

Besides, I will give a look on how we can prevent this from happening and I will you about it.

commented

This is definitely a bug. is_connected() should return pretty much immediately, so there's something in our background executor that's having a problem.

I agree on the bug thing.. here some feedback on the possible issue:

INFO  btleplug_hunting]  3) Disconnect device
TRACE btleplug::corebluetooth::internal] Adapter message!
TRACE btleplug::corebluetooth::internal] Trying to disconnect peripheral!
TRACE btleplug::corebluetooth::internal] Disconnecting peripheral!
TRACE btleplug::corebluetooth::central_delegate::CentralDelegate] delegate_centralmanager_diddisconnectperipheral_error CBPeripheral(iPhone, XXXXX)
TRACE btleplug::corebluetooth::internal] Got disconnect event!
INFO  btleplug::corebluetooth::peripheral] Event receiver died, breaking out of corebluetooth device loop.
TRACE btleplug::common::adapter_manager] Lost central event, while nothing subscribed: SendError(DeviceDisconnected(PeripheralId(XXXXX)))
TRACE btleplug::common::adapter_manager] Lost central event, while nothing subscribed: SendError(DeviceDisconnected(PeripheralId(XXXXX)))
TRACE btleplug::corebluetooth::peripheral] Device disconnected!
INFO  btleplug_hunting]  4) Check connection status