add blink pattern

This commit is contained in:
Tobias Ollive 2022-03-10 09:54:02 +01:00
parent 4451917154
commit c2b2517661
4 changed files with 150 additions and 47 deletions

View File

@ -1,8 +1,25 @@
- name : toto - name : toto
mac_addresses : mac_addresses :
- C9:81:9C:BA:53:BC - C9:81:9C:BA:53:BC
- D8:D3:AF:87:70:FA
sequence: 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: - pattern:
type: Fade type: Fade
current_iteration: 0 current_iteration: 0
@ -42,25 +59,28 @@
stability: 40 stability: 40
period: period:
secs: 0 secs: 0
nanos: 100000000 nanos: 800000000
- name: titi - name: titi
sequence: sequence:
- pattern: - pattern:
type: Fade type: Blink
fade :
current_iteration: 0 current_iteration: 0
nbr_iterations: 20 nbr_iterations: 20
begin_color: begin_color:
red: 255 red: 0
green: 0 green: 0
blue: 0 blue: 0
end_color: end_color:
red: 0 red: 0
green: 0 green: 255
blue: 255 blue: 255
current_iteration: 0
max_iteration : 10
period: period:
secs: 0 secs: 0
nanos: 200000000 nanos: 100000000
- pattern: - pattern:
type: Rainbow type: Rainbow
current_iteration: 0 current_iteration: 0

View File

@ -11,12 +11,15 @@ use crate::audio::play_sound;
use crate::config::{load_from_file, Config}; use crate::config::{load_from_file, Config};
use crate::runner::Spectacle; use crate::runner::Spectacle;
use bluer::gatt::remote::Characteristic; use bluer::gatt::remote::Characteristic;
use bluer::{Device, Error};
use clap::Parser; use clap::Parser;
use patterns::Strip; use patterns::Strip;
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::sync::mpsc; 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 SERVICE_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0900c33242a893bd25e905756cb8);
const PIXEL_DATA_UUID: bluer::Uuid = bluer::Uuid::from_u128(0xadaf0903c33242a893bd25e905756cb8); 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 musique = tokio::task::spawn_blocking(move || play_sound(Path::new(&musique_file)));
let adapter = bluetooth::create_session().await?; 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( tokio::spawn(bluetooth::bluetooth_scan(
tx_scan, tx_scan,
@ -44,34 +47,9 @@ async fn main() -> bluer::Result<()> {
SERVICE_UUID, SERVICE_UUID,
)); ));
let spectacle_channels = spectacle.clone(); tokio::spawn(connect_device(spectacle.clone(), rx_scan));
tokio::spawn(async move {
while let Some(device) = rx_scan.recv().await { tokio::time::sleep(Duration::from_secs(5)).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(())
});
println!("starting"); println!("starting");
let futures; let futures;
@ -90,6 +68,37 @@ async fn main() -> bluer::Result<()> {
Ok(()) 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>( pub async fn write_strip<const N: usize>(
data: &Strip<N>, data: &Strip<N>,
char: &Characteristic, char: &Characteristic,

View File

@ -11,7 +11,8 @@ pub(crate) enum Patterns<const N: usize> {
ColorWipe(ColorWipe<N>), ColorWipe(ColorWipe<N>),
Scanner(Scanner<N>), Scanner(Scanner<N>),
FillRandom(FillRandom<N>), FillRandom(FillRandom<N>),
FillUnstable(FillUnstable<N>) FillUnstable(FillUnstable<N>),
Blink(Blink<N>),
} }
impl<const N: usize> Iterator for Patterns<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::Scanner(p) => p.next(),
Patterns::FillRandom(p) => p.next(), Patterns::FillRandom(p) => p.next(),
Patterns::FillUnstable(p) => p.next(), Patterns::FillUnstable(p) => p.next(),
Patterns::Blink(p) => p.next(),
} }
} }
} }
@ -101,6 +103,10 @@ impl<const N: usize> Strip<N> {
data data
} }
pub fn new(color: PixelColor) -> Strip<N> {
Strip { 0: [color; N] }
}
pub fn fill(&mut self, color: PixelColor) { pub fn fill(&mut self, color: PixelColor) {
self.0.fill(color); self.0.fill(color);
} }
@ -118,6 +124,7 @@ impl<const N: usize> Strip<N> {
/// ///
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Rainbow<const N: usize> { pub struct Rainbow<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize, pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>, pub(crate) max_iteration: Option<usize>,
pub(crate) step: 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)] #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct ColorWipe<const N: usize> { pub struct ColorWipe<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize, pub(crate) current_iteration: usize,
pub(crate) max_iteration: Option<usize>, pub(crate) max_iteration: Option<usize>,
pub(crate) color: PixelColor, pub(crate) color: PixelColor,
@ -222,6 +230,7 @@ impl<const N: usize> Iterator for ColorWipe<N> {
/// fade from one color to an other /// fade from one color to an other
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Fade<const N: usize> { pub struct Fade<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize, pub(crate) current_iteration: usize,
pub(crate) nbr_iterations: usize, pub(crate) nbr_iterations: usize,
pub(crate) begin_color: PixelColor, 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 /// background_color work only for color not set by scanner pattern
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct Scanner<const N: usize> { pub struct Scanner<const N: usize> {
#[serde(default)]
pub(crate) current_iteration: usize, pub(crate) current_iteration: usize,
pub(crate) color: PixelColor, pub(crate) color: PixelColor,
pub(crate) background_color: Option<PixelColor>, pub(crate) background_color: Option<PixelColor>,
@ -403,3 +413,50 @@ impl<const N: usize> Iterator for FillUnstable<N> {
Some(strip) 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),
}
}
}

View File

@ -1,5 +1,5 @@
use crate::config::Config; use crate::config::Config;
use crate::patterns::Patterns; use crate::patterns::{Patterns, PixelColor};
use crate::Strip; use crate::Strip;
use bluer::Address; use bluer::Address;
use serde_derive::{Deserialize, Serialize}; 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>) { if let Some((_, rx)) = self.runners.get(&runner as &DeviceSequence<N>) {
self.channels.insert(mac_address, rx.clone()); self.channels.insert(mac_address, rx.clone());
} else { } 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.runners.insert(runner.clone(), (tx, rx.clone()));
self.channels.insert(mac_address, rx); self.channels.insert(mac_address, rx);
} }
} }
pub fn add_default(&mut self, runner: DeviceSequence<N>) { 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.tasks.push(runner.runner_loop(tx));
self.default_runner = Some((runner, tx)); self.default_runner = Some((runner, tx));
self.default_receiver = Some(rx); 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>>> { pub fn get_channel(&self, mac_address: &Address) -> Option<Receiver<Strip<N>>> {
let channel = self.channels.get(mac_address); let channel = self.channels.get(mac_address);
match channel { match channel {