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