diff --git a/spectacle.yml b/spectacle.yml index 8e955c9..098af97 100644 --- a/spectacle.yml +++ b/spectacle.yml @@ -1,8 +1,25 @@ - name : toto mac_addresses : - C9:81:9C:BA:53:BC - - D8:D3:AF:87:70:FA sequence: + - pattern: + type: Blink + fade: + current_iteration: 10 + nbr_iterations: 20 + begin_color: + red: 0 + green: 0 + blue: 0 + end_color: + red: 255 + green: 0 + blue: 255 + current_iteration: 0 + max_iteration: 10 + period: + secs: 0 + nanos: 50000000 - pattern: type: Fade current_iteration: 0 @@ -42,25 +59,28 @@ stability: 40 period: secs: 0 - nanos: 100000000 + nanos: 800000000 - name: titi sequence: - pattern: - type: Fade + type: Blink + fade : + current_iteration: 0 + nbr_iterations: 20 + begin_color: + red: 0 + green: 0 + blue: 0 + end_color: + red: 0 + green: 255 + blue: 255 current_iteration: 0 - nbr_iterations: 20 - begin_color: - red: 255 - green: 0 - blue: 0 - end_color: - red: 0 - green: 0 - blue: 255 + max_iteration : 10 period: secs: 0 - nanos: 200000000 + nanos: 100000000 - pattern: type: Rainbow current_iteration: 0 diff --git a/src/main.rs b/src/main.rs index d8758d9..984f4b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,12 +11,15 @@ 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 std::time::Duration; use tokio::sync::mpsc; -use tokio::sync::watch::Receiver; +use tokio::sync::watch; +use tokio::sync::Notify; const SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8); const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8); @@ -36,7 +39,7 @@ async fn main() -> bluer::Result<()> { let musique = tokio::task::spawn_blocking(move || play_sound(Path::new(&musique_file))); let adapter = bluetooth::create_session().await?; - let (tx_scan, mut rx_scan) = mpsc::channel(3); + let (tx_scan, rx_scan) = mpsc::channel(3); tokio::spawn(bluetooth::bluetooth_scan( tx_scan, @@ -44,34 +47,9 @@ async fn main() -> bluer::Result<()> { SERVICE_UUID, )); - let spectacle_channels = spectacle.clone(); - tokio::spawn(async move { - 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_channels = spectacle_channels.lock().unwrap(); - rx = spectacle_channels.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(()) - }); + tokio::spawn(connect_device(spectacle.clone(), rx_scan)); + + tokio::time::sleep(Duration::from_secs(5)).await; println!("starting"); let futures; @@ -90,6 +68,37 @@ async fn main() -> bluer::Result<()> { 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, diff --git a/src/patterns.rs b/src/patterns.rs index 41eeaa7..13814d7 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -11,7 +11,8 @@ pub(crate) enum Patterns { ColorWipe(ColorWipe), Scanner(Scanner), FillRandom(FillRandom), - FillUnstable(FillUnstable) + FillUnstable(FillUnstable), + Blink(Blink), } impl Iterator for Patterns { @@ -25,6 +26,7 @@ impl Iterator for Patterns { Patterns::Scanner(p) => p.next(), Patterns::FillRandom(p) => p.next(), Patterns::FillUnstable(p) => p.next(), + Patterns::Blink(p) => p.next(), } } } @@ -101,6 +103,10 @@ impl Strip { data } + pub fn new(color: PixelColor) -> Strip { + Strip { 0: [color; N] } + } + pub fn fill(&mut self, color: PixelColor) { self.0.fill(color); } @@ -118,6 +124,7 @@ impl Strip { /// #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct Rainbow { + #[serde(default)] pub(crate) current_iteration: usize, pub(crate) max_iteration: Option, pub(crate) step: Option, @@ -189,6 +196,7 @@ fn wheel(index: u8) -> PixelColor { /// #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct ColorWipe { + #[serde(default)] pub(crate) current_iteration: usize, pub(crate) max_iteration: Option, pub(crate) color: PixelColor, @@ -222,6 +230,7 @@ impl Iterator for ColorWipe { /// fade from one color to an other #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct Fade { + #[serde(default)] pub(crate) current_iteration: usize, pub(crate) nbr_iterations: usize, pub(crate) begin_color: PixelColor, @@ -278,6 +287,7 @@ impl Iterator for Fade { /// background_color work only for color not set by scanner pattern #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] pub struct Scanner { + #[serde(default)] pub(crate) current_iteration: usize, pub(crate) color: PixelColor, pub(crate) background_color: Option, @@ -403,3 +413,50 @@ impl Iterator for FillUnstable { Some(strip) } } + +#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] +enum Direction { + there, + back, +} + +impl Default for Direction { + fn default() -> Self { + Direction::there + } +} + +/// # Blink +/// +/// fade from one color to an other then go back several times +#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] +pub struct Blink { + #[serde(default)] + pub(crate) current_iteration: usize, + pub(crate) max_iteration: Option, + fade: Fade, + #[serde(default)] + direction: Direction, +} + +impl Iterator for Blink { + type Item = Strip; + + fn next(&mut self) -> Option { + let value = self.fade.next(); + match value { + None => { + if let Some(iter_max) = self.max_iteration { + if self.current_iteration >= iter_max { + return None; + } + self.current_iteration += 1; + } + self.fade.current_iteration = 0; + std::mem::swap(&mut self.fade.begin_color, &mut self.fade.end_color); + self.fade.next() + } + Some(value) => Some(value), + } + } +} diff --git a/src/runner.rs b/src/runner.rs index 57fd036..2b6fcfd 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1,5 +1,5 @@ use crate::config::Config; -use crate::patterns::Patterns; +use crate::patterns::{Patterns, PixelColor}; use crate::Strip; use bluer::Address; use serde_derive::{Deserialize, Serialize}; @@ -45,19 +45,36 @@ impl Spectacle { if let Some((_, rx)) = self.runners.get(&runner as &DeviceSequence) { self.channels.insert(mac_address, rx.clone()); } else { - let (tx, rx) = tokio::sync::watch::channel(Strip::::default()); + let (tx, rx) = tokio::sync::watch::channel(Strip::::new(PixelColor { + red: 0, + green: 255, + blue: 0, + })); self.runners.insert(runner.clone(), (tx, rx.clone())); self.channels.insert(mac_address, rx); } } pub fn add_default(&mut self, runner: DeviceSequence) { - let (tx, rx) = tokio::sync::watch::channel(Strip::::default()); + let (tx, rx) = tokio::sync::watch::channel(Strip::::new(PixelColor { + red: 0, + green: 0, + blue: 255, + })); // self.tasks.push(runner.runner_loop(tx)); self.default_runner = Some((runner, tx)); self.default_receiver = Some(rx); } + pub fn nbr_tasks(&self) -> usize { + let mut nbr = 0; + if self.default_receiver.is_some() { + nbr += 1; + } + nbr += self.runners.len(); + nbr + } + pub fn get_channel(&self, mac_address: &Address) -> Option>> { let channel = self.channels.get(mac_address); match channel {