126 lines
3.8 KiB
Rust
126 lines
3.8 KiB
Rust
use bluer::{AdapterEvent, Device};
|
|
use bluer::gatt::remote::Characteristic;
|
|
use futures::{pin_mut, StreamExt};
|
|
use std::time::Duration;
|
|
use tokio::time::sleep;
|
|
|
|
const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8);
|
|
const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8);
|
|
|
|
|
|
#[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 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);
|
|
}
|
|
_ => (),
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn send_seq(char: &Characteristic) -> bluer::Result<()> {
|
|
println!(" Characteristic flags : {:?}, ", char.flags().await?);
|
|
|
|
let mut base_data: Vec<u8> = vec![0x00, 0x00, 0x01];
|
|
let mut off_data: Vec<u8> = vec![0x00, 0x00, 0x01];
|
|
for _ in 0..10 {
|
|
base_data.append(&mut vec![0xff, 0x00, 0x00]);
|
|
off_data.append(&mut vec![0x00, 0x00, 0x00]);
|
|
}
|
|
|
|
loop {
|
|
char.write(&*base_data).await?;
|
|
sleep(Duration::from_secs(1)).await;
|
|
char.write(&*off_data).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? {
|
|
if PIXEL_DATA_UUID == char.uuid().await? {
|
|
return Ok(Some(char));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Ok(None)
|
|
} |