mod args; mod audio; mod bluetooth; mod config; mod patterns; mod runner; mod spectacle; use crate::args::Cli; use crate::audio::play_sound; use crate::config::{load_from_file, Config}; use crate::runner::Spectacle; use bluer::gatt::remote::Characteristic; use bluer::{Device, Error}; use clap::Parser; use patterns::Strip; use std::path::Path; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc; use tokio::sync::watch; 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 command_line = Cli::parse(); let file = Path::new(&command_line.spectacle_file); let config: Config<25> = load_from_file(file); let spectacle = Spectacle::from(config); let spectacle = Arc::new(Mutex::new(spectacle)); let adapter = bluetooth::create_session().await?; let (tx_scan, rx_scan) = mpsc::channel(3); tokio::spawn(bluetooth::bluetooth_scan( tx_scan, adapter.clone(), SERVICE_UUID, )); tokio::spawn(connect_device(spectacle.clone(), rx_scan)); println!("starting"); let musique_file = command_line.musique_file; let musique = tokio::task::spawn_blocking(move || play_sound(Path::new(&musique_file))); let futures; { let mut spectacle = spectacle.lock().unwrap(); futures = spectacle.run(); } let mut joinhandles = vec![]; for future in futures { joinhandles.push(tokio::spawn(future)); } for joinhandle in joinhandles { joinhandle.await.unwrap(); } musique.await.unwrap(); Ok(()) } async fn connect_device( spectacle: Arc>>, mut rx_scan: mpsc::Receiver, ) -> Result<(), Error> { while let Some(device) = rx_scan.recv().await { bluetooth::connect(&device, 3).await?; let char = bluetooth::get_char(&device, SERVICE_UUID, PIXEL_DATA_UUID).await?; if let Some(char) = char { let rx: Option>>; { let spectacle = spectacle.lock().unwrap(); rx = spectacle.get_channel(&device.address()); } if let Some(mut rx) = rx { tokio::spawn(async move { println!("device connected : {}", &device.address()); while rx.changed().await.is_ok() { let strip = *rx.borrow(); if write_strip(&strip, &char).await.is_err() { break; }; } println!("device {} disconnected", &device.address()); // drop(rx_device); }); } } } bluer::Result::Ok(()) } pub async fn write_strip( data: &Strip, char: &Characteristic, ) -> bluer::Result<()> { let frame = [BASE_STRIP_DATA.to_vec(), data.to_array()].concat(); // print!("{:?}", frame); char.write(&*frame).await?; Ok(()) }