set asynchrone scan
This commit is contained in:
86
src/bluetooth.rs
Normal file
86
src/bluetooth.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::mpsc::{channel, Sender};
|
||||
use std::time::Duration;
|
||||
use bluer::{Adapter, AdapterEvent, Address, Device, Result, Uuid};
|
||||
use futures::{pin_mut, StreamExt};
|
||||
use tokio::task::spawn_blocking;
|
||||
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<Adapter>
|
||||
{
|
||||
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<bool> {
|
||||
|
||||
let uuids = device.uuids().await?.unwrap_or_default();
|
||||
if uuids.contains(uuid) {
|
||||
return Ok(true)
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn bluetooth_scan(tx: mpsc::Sender<Device>, adapter: Adapter, uuid: Uuid) -> Result<()> {
|
||||
println!("start bluetooth scan");
|
||||
let discover = adapter.discover_devices().await?;
|
||||
let mut already_scanned: HashSet<Address> = HashSet::new();
|
||||
pin_mut!(discover);
|
||||
while let Some(evt) = discover.next().await {
|
||||
match evt {
|
||||
AdapterEvent::DeviceAdded(addr) => {
|
||||
println!("device adress {}", 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;
|
||||
println!("found service in device {}", addr);
|
||||
}
|
||||
}
|
||||
Err(_) => { continue }
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
println!("ended");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub(crate) async fn scan_devices(adapter: Adapter, uuid: Uuid) -> Vec<Device> {
|
||||
println!("start scanning devices");
|
||||
let (tx, mut rx) = mpsc::channel(4);
|
||||
;
|
||||
let timeout = tokio::time::timeout(Duration::from_secs(30), bluetooth_scan(tx, adapter, uuid)).await;
|
||||
let scan = tokio::spawn(timeout);
|
||||
println!("good");
|
||||
let mut devices: Vec<Device> = Vec::new();
|
||||
while let Some(device)= rx.recv().await {
|
||||
println!("new device received {}", device.address());
|
||||
devices.push(device);
|
||||
println!("len {}", devices.len());
|
||||
if devices.len() >= 2 {
|
||||
println!("drop");
|
||||
drop(scan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
devices
|
||||
}
|
||||
190
src/main.rs
190
src/main.rs
@@ -1,129 +1,111 @@
|
||||
mod patterns;
|
||||
mod bluetooth;
|
||||
|
||||
use patterns::{PixelColor, Strip};
|
||||
use bluer::{AdapterEvent, Device};
|
||||
use bluer::Device;
|
||||
use bluer::gatt::remote::Characteristic;
|
||||
use futures::{pin_mut, StreamExt};
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
use crate::patterns::RainbowPattern;
|
||||
|
||||
const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8);
|
||||
const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8);
|
||||
const STRIP_SIZE: usize = 25;
|
||||
const BASE_STRIP_DATA : [u8; 3] = [0x00, 0x00, 0x01];
|
||||
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> bluer::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?;
|
||||
let adapter = bluetooth::create_session().await?;
|
||||
|
||||
let discover = adapter.discover_devices().await?;
|
||||
pin_mut!(discover);
|
||||
|
||||
while let Some(evt) = discover.next().await {
|
||||
match evt {
|
||||
AdapterEvent::DeviceAdded(addr) => {
|
||||
let device = adapter.device(addr)?;
|
||||
match find_neopixel_service(&device).await {
|
||||
Ok(Some(char)) => {
|
||||
println!("found characteristic");
|
||||
match send_seq(&char).await {
|
||||
// this loop should never stop
|
||||
_ => ()
|
||||
}
|
||||
|
||||
}
|
||||
Ok(None) => {
|
||||
println!("characteristic not found")
|
||||
}
|
||||
Err(err) => {
|
||||
println!("device error : {}", &err);
|
||||
let _ = adapter.remove_device(device.address()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
AdapterEvent::DeviceRemoved(addr) => {
|
||||
println!("Device removed {}", addr);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let devices = bluetooth::scan_devices(adapter, SERVICE_UUID).await;
|
||||
|
||||
for device in devices {
|
||||
println!("{:?}", device);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_seq(char: &Characteristic) -> bluer::Result<()> {
|
||||
println!(" Characteristic flags : {:?}, ", char.flags().await?);
|
||||
// async fn send_seq(char: &Characteristic) -> bluer::Result<()> {
|
||||
// println!(" Characteristic flags : {:?}, ", char.flags().await?);
|
||||
//
|
||||
// let mut strip_red : Strip<10> = Strip::default();
|
||||
// strip_red.strip.fill(PixelColor { red: 255, green: 0, blue: 0});
|
||||
//
|
||||
// let mut strip_green: Strip<10> = Strip::default();
|
||||
// strip_green.strip.fill(PixelColor { red: 0, green: 255, blue: 0});
|
||||
//
|
||||
// let pattern = RainbowPattern::<STRIP_SIZE> { current_iteration: 0,};
|
||||
//
|
||||
//
|
||||
// for strip in pattern {
|
||||
// write_strip(strip, char).await?;
|
||||
// sleep(Duration::from_millis(50)).await;
|
||||
// }
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
let mut strip_red : Strip<10>;
|
||||
strip_red.strip.fill(PixelColor { red: 255, green: 0, blue: 0});
|
||||
// pub async fn write_strip<const N: usize>(data: Strip<N>, char: &Characteristic) -> bluer::Result<()> {
|
||||
// let frame = [BASE_STRIP_DATA.to_vec(), data.to_array()].concat();
|
||||
// print!("{:?}",frame);
|
||||
// char.write(&*frame).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
let mut strip_green: Strip<10>;
|
||||
strip_green.strip.fill(PixelColor { red: 0, green: 255, blue: 0});
|
||||
// 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(),
|
||||
// })
|
||||
// }
|
||||
|
||||
loop {
|
||||
char.write(&*strip_green.to_array()).await?;
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
char.write(&*strip_red.to_array()).await?;
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn find_neopixel_service(device: &Device) -> bluer::Result<Option<Characteristic>> {
|
||||
let addr = device.address();
|
||||
let uuids = device.uuids().await?.unwrap_or_default();
|
||||
|
||||
if uuids.contains(&SERVICE_UUID) {
|
||||
println!("service neopixel found for device {}", &addr);
|
||||
match connect(device, 3).await {
|
||||
Ok(()) => {
|
||||
println!("successefully connected");
|
||||
}
|
||||
Err(err) => {
|
||||
println!("unable to connect, trying new device, {}", err);
|
||||
return Err(err)
|
||||
}
|
||||
}
|
||||
for service in device.services().await? {
|
||||
if SERVICE_UUID == service.uuid().await? {
|
||||
for char in service.characteristics().await? {
|
||||
println!("uuid : {}", &char.uuid().await?);
|
||||
if PIXEL_DATA_UUID == char.uuid().await? {
|
||||
|
||||
return Ok(Some(char));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
// async fn find_neopixel_service(device: &Device) -> bluer::Result<Option<Characteristic>> {
|
||||
// let addr = device.address();
|
||||
// let uuids = device.uuids().await?.unwrap_or_default();
|
||||
//
|
||||
// if uuids.contains(&SERVICE_UUID) {
|
||||
// println!("service neopixel found for device {}", &addr);
|
||||
// match connect(device, 3).await {
|
||||
// Ok(()) => {
|
||||
// println!("successefully connected");
|
||||
// }
|
||||
// Err(err) => {
|
||||
// println!("unable to connect, trying new device, {}", err);
|
||||
// return Err(err)
|
||||
// }
|
||||
// }
|
||||
// for service in device.services().await? {
|
||||
// if SERVICE_UUID == service.uuid().await? {
|
||||
// for char in service.characteristics().await? {
|
||||
// println!("uuid : {}", &char.uuid().await?);
|
||||
// if PIXEL_DATA_UUID == char.uuid().await? {
|
||||
//
|
||||
// return Ok(Some(char));
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// Ok(None)
|
||||
// }
|
||||
Reference in New Issue
Block a user