use bluer::gatt::remote::Characteristic; use bluer::{Adapter, AdapterEvent, Address, Device, Result, Uuid}; use futures::{pin_mut, StreamExt}; use std::collections::HashSet; use std::time::Duration; use tokio::sync::mpsc; // const CONNECT_RETRIES: u8 = 3; // const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8); // const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8); pub(crate) async fn create_session() -> Result { let session = bluer::Session::new().await?; let adapter_names = session.adapter_names().await?; let adapter_name = adapter_names.first().expect("no Bluetooth adapter found"); let adapter = session.adapter(adapter_name)?; adapter.set_powered(true).await?; Ok(adapter) } async fn has_service(device: &Device, uuid: &Uuid) -> Result { let uuids = device.uuids().await?.unwrap_or_default(); if uuids.contains(uuid) { return Ok(true); } Ok(false) } async fn bluetooth_scan(tx: mpsc::Sender, adapter: Adapter, uuid: Uuid) -> Result<()> { println!("start bluetooth scan"); let discover = adapter.discover_devices().await?; let mut already_scanned: HashSet
= HashSet::new(); pin_mut!(discover); while let Some(evt) = discover.next().await { match evt { AdapterEvent::DeviceAdded(addr) => { if already_scanned.contains(&addr) { continue; } already_scanned.insert(addr); let device = adapter.device(addr)?; match has_service(&device, &uuid).await { Ok(service_found) => { if service_found { tx.send(device).await.unwrap(); println!("found service in device {}", addr); } } Err(_) => continue, } } _ => {} } } Ok(()) } pub(crate) async fn scan_devices(adapter: Adapter, uuid: Uuid) -> Vec { let (tx, mut rx) = mpsc::channel(4); let timeout = tokio::time::timeout(Duration::from_secs(30), bluetooth_scan(tx, adapter, uuid)); let scan = tokio::spawn(timeout); let mut devices: Vec = Vec::new(); while let Some(device) = rx.recv().await { devices.push(device); if devices.len() >= 2 { drop(scan); break; } } devices } pub async fn connect(device: &Device, retries: u8) -> bluer::Result<()> { if device.is_connected().await? { return Ok(()); } for i in 0..retries { match device.connect().await { Ok(()) => return Ok(()), Err(_) => { println!("connection error ({}), retry…", i); } } } Err(bluer::Error { kind: bluer::ErrorKind::ConnectionAttemptFailed, message: "all attempts fail".parse().unwrap(), }) } pub async fn get_char( device: &Device, service_uuid: Uuid, char_uuid: Uuid, ) -> Result> { for service in device.services().await? { if service_uuid == service.uuid().await? { for char in service.characteristics().await? { if char_uuid == char.uuid().await? { return Ok(Some(char)); } } } } Ok(None) }