add blink pattern
This commit is contained in:
parent
4451917154
commit
c2b2517661
|
@ -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
|
||||||
|
|
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::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,
|
||||||
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user