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
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

View File

@ -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,

View File

@ -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),
}
}
}

View File

@ -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 {