add blink pattern
This commit is contained in:
		
							parent
							
								
									4451917154
								
							
						
					
					
						commit
						c2b2517661
					
				@ -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: 255
 | 
			
		||||
                red: 0
 | 
			
		||||
                green: 0
 | 
			
		||||
                blue: 0
 | 
			
		||||
            end_color:
 | 
			
		||||
                red: 0
 | 
			
		||||
            green: 0
 | 
			
		||||
                green: 255
 | 
			
		||||
                blue: 255
 | 
			
		||||
          current_iteration: 0
 | 
			
		||||
          max_iteration : 10
 | 
			
		||||
        period:
 | 
			
		||||
          secs: 0
 | 
			
		||||
          nanos: 200000000
 | 
			
		||||
          nanos: 100000000
 | 
			
		||||
      - pattern:
 | 
			
		||||
          type: Rainbow
 | 
			
		||||
          current_iteration: 0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										69
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								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<Receiver<Strip<STRIP_SIZE>>>;
 | 
			
		||||
                {
 | 
			
		||||
                    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<Mutex<Spectacle<STRIP_SIZE>>>,
 | 
			
		||||
    mut rx_scan: mpsc::Receiver<Device>,
 | 
			
		||||
) -> 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<watch::Receiver<Strip<STRIP_SIZE>>>;
 | 
			
		||||
            {
 | 
			
		||||
                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<const N: usize>(
 | 
			
		||||
    data: &Strip<N>,
 | 
			
		||||
    char: &Characteristic,
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,8 @@ pub(crate) enum Patterns<const N: usize> {
 | 
			
		||||
    ColorWipe(ColorWipe<N>),
 | 
			
		||||
    Scanner(Scanner<N>),
 | 
			
		||||
    FillRandom(FillRandom<N>),
 | 
			
		||||
    FillUnstable(FillUnstable<N>)
 | 
			
		||||
    FillUnstable(FillUnstable<N>),
 | 
			
		||||
    Blink(Blink<N>),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<const N: usize> Iterator for Patterns<N> {
 | 
			
		||||
@ -25,6 +26,7 @@ impl<const N: usize> Iterator for Patterns<N> {
 | 
			
		||||
            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<const N: usize> Strip<N> {
 | 
			
		||||
        data
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new(color: PixelColor) -> Strip<N> {
 | 
			
		||||
        Strip { 0: [color; N] }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn fill(&mut self, color: PixelColor) {
 | 
			
		||||
        self.0.fill(color);
 | 
			
		||||
    }
 | 
			
		||||
@ -118,6 +124,7 @@ impl<const N: usize> Strip<N> {
 | 
			
		||||
///
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
 | 
			
		||||
pub struct Rainbow<const N: usize> {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub(crate) current_iteration: usize,
 | 
			
		||||
    pub(crate) max_iteration: Option<usize>,
 | 
			
		||||
    pub(crate) step: Option<usize>,
 | 
			
		||||
@ -189,6 +196,7 @@ fn wheel(index: u8) -> PixelColor {
 | 
			
		||||
///
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
 | 
			
		||||
pub struct ColorWipe<const N: usize> {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub(crate) current_iteration: usize,
 | 
			
		||||
    pub(crate) max_iteration: Option<usize>,
 | 
			
		||||
    pub(crate) color: PixelColor,
 | 
			
		||||
@ -222,6 +230,7 @@ impl<const N: usize> Iterator for ColorWipe<N> {
 | 
			
		||||
/// fade from one color to an other
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
 | 
			
		||||
pub struct Fade<const N: usize> {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub(crate) current_iteration: usize,
 | 
			
		||||
    pub(crate) nbr_iterations: usize,
 | 
			
		||||
    pub(crate) begin_color: PixelColor,
 | 
			
		||||
@ -278,6 +287,7 @@ impl<const N: usize> Iterator for Fade<N> {
 | 
			
		||||
/// background_color work only for color not set by scanner pattern
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
 | 
			
		||||
pub struct Scanner<const N: usize> {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub(crate) current_iteration: usize,
 | 
			
		||||
    pub(crate) color: PixelColor,
 | 
			
		||||
    pub(crate) background_color: Option<PixelColor>,
 | 
			
		||||
@ -403,3 +413,50 @@ impl<const N: usize> Iterator for FillUnstable<N> {
 | 
			
		||||
        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<const N: usize> {
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    pub(crate) current_iteration: usize,
 | 
			
		||||
    pub(crate) max_iteration: Option<usize>,
 | 
			
		||||
    fade: Fade<N>,
 | 
			
		||||
    #[serde(default)]
 | 
			
		||||
    direction: Direction,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<const N: usize> Iterator for Blink<N> {
 | 
			
		||||
    type Item = Strip<N>;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        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),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<const N: usize> Spectacle<N> {
 | 
			
		||||
        if let Some((_, rx)) = self.runners.get(&runner as &DeviceSequence<N>) {
 | 
			
		||||
            self.channels.insert(mac_address, rx.clone());
 | 
			
		||||
        } else {
 | 
			
		||||
            let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::default());
 | 
			
		||||
            let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::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<N>) {
 | 
			
		||||
        let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::default());
 | 
			
		||||
        let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::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<Receiver<Strip<N>>> {
 | 
			
		||||
        let channel = self.channels.get(mac_address);
 | 
			
		||||
        match channel {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user