refactor and fix starrandom error
This commit is contained in:
parent
6deb31836f
commit
b332d75c7f
|
@ -1,10 +1,9 @@
|
|||
use crate::patterns::PixelColor;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::runner::DeviceSequence;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Config<const N: usize> {
|
||||
devices: Vec<Device<N>>,
|
||||
|
|
|
@ -3,6 +3,7 @@ mod audio;
|
|||
mod bluetooth;
|
||||
mod config;
|
||||
mod patterns;
|
||||
mod pixel_color;
|
||||
mod runner;
|
||||
mod spectacle;
|
||||
|
||||
|
|
113
src/patterns.rs
113
src/patterns.rs
|
@ -25,11 +25,9 @@ use crate::patterns::ring::Ring;
|
|||
use crate::patterns::ring_scanner::RingScanner;
|
||||
use crate::patterns::scanner::Scanner;
|
||||
use crate::patterns::stars_random::StarsRandom;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::Rng;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops::{Add, AddAssign, Div, Index, IndexMut, Sub, SubAssign};
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)]
|
||||
#[serde(tag = "type")]
|
||||
|
@ -49,6 +47,11 @@ pub(crate) enum Patterns<const N: usize> {
|
|||
StarsRandom(StarsRandom<N>),
|
||||
}
|
||||
|
||||
/// Pattern that have to be implemented
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
pub trait Pattern: Iterator {
|
||||
type Strip;
|
||||
|
||||
|
@ -151,108 +154,6 @@ impl<const N: usize> Pattern for Patterns<N> {
|
|||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// a struct for an RGB color
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Default, Eq, Hash, PartialEq)]
|
||||
pub struct PixelColor {
|
||||
pub(crate) red: u8,
|
||||
pub(crate) green: u8,
|
||||
pub(crate) blue: u8,
|
||||
}
|
||||
|
||||
impl fmt::Display for PixelColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[{},{},{}]", self.red, self.green, self.blue)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<u8> for PixelColor {
|
||||
type Output = PixelColor;
|
||||
|
||||
fn div(self, rhs: u8) -> Self::Output {
|
||||
PixelColor {
|
||||
red: self.red / rhs,
|
||||
green: self.green / rhs,
|
||||
blue: self.blue / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for PixelColor {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
PixelColor {
|
||||
red: self.red.saturating_add(rhs.red),
|
||||
green: self.green.saturating_add(rhs.green),
|
||||
blue: self.blue.saturating_add(rhs.blue),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u8> for PixelColor {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: u8) -> Self::Output {
|
||||
PixelColor {
|
||||
red: self.red.saturating_sub(rhs),
|
||||
green: self.green.saturating_sub(rhs),
|
||||
blue: self.blue.saturating_sub(rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for PixelColor {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.red = self.red.saturating_sub(rhs.red);
|
||||
self.green = self.red.saturating_sub(rhs.green);
|
||||
self.blue = self.red.saturating_sub(rhs.blue);
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for PixelColor {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.red = self.red.saturating_add(rhs.red);
|
||||
self.green = self.red.saturating_add(rhs.green);
|
||||
self.blue = self.red.saturating_add(rhs.blue);
|
||||
}
|
||||
}
|
||||
|
||||
impl PixelColor {
|
||||
/// apply random delta to pixel and return computed value
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `pixel`: pixel to apply delta
|
||||
/// * `stability`: amplitude of delta between 0 and `stability`
|
||||
///
|
||||
/// returns: PixelColor
|
||||
///
|
||||
pub fn random_delta(&self, stability: usize, rng: &mut ThreadRng) -> PixelColor {
|
||||
let minus_interval = -(stability as i8);
|
||||
let max_interval = stability as i8;
|
||||
let red_delta = rng.gen_range(minus_interval..max_interval) as i8;
|
||||
let green_delta = rng.gen_range(minus_interval..max_interval) as i8;
|
||||
let blue_delta = rng.gen_range(minus_interval..max_interval) as i8;
|
||||
self.delta((red_delta, green_delta, blue_delta))
|
||||
}
|
||||
|
||||
pub fn delta(&self, delta: (i8, i8, i8)) -> PixelColor {
|
||||
let (red, green, blue) = delta;
|
||||
PixelColor {
|
||||
red: (self.red as i16 + red as i16) as u8,
|
||||
green: (self.green as i16 + green as i16) as u8,
|
||||
blue: (self.blue as i16 + blue as i16) as u8,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closer(&self, pixel: PixelColor, distance: PixelColor) -> bool {
|
||||
(self.red as i16 - pixel.red as i16).abs() <= distance.red as i16
|
||||
&& (self.green as i16 - pixel.green as i16).abs() <= distance.green as i16
|
||||
&& (self.blue as i16 - pixel.blue as i16).abs() <= distance.blue as i16
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// a basic newtype based on a fix array size.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_init_background, impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::Strip;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_last_iteration, Strip};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_init_background, impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_init_background, impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_init_background, impl_pattern_last_iteration, Strip};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::patterns::{Pattern, PixelColor};
|
||||
use crate::patterns::Pattern;
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::{impl_pattern_last_iteration, Strip};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -26,14 +27,13 @@ impl<const N: usize> Pattern for StarsRandom<N> {
|
|||
fn init(&mut self) -> Option<Self::Strip> {
|
||||
if let Some(color) = self.background_color {
|
||||
self.strip = Strip::<N>::new(color);
|
||||
let red = (self.color.red as i16 - color.red as i16) as i8;
|
||||
let green = (color.green as i16 - self.color.green as i16) as i8;
|
||||
let blue = (self.color.blue as i16 - color.blue as i16) as i8;
|
||||
println!("{} {} {}", red, green, blue);
|
||||
let red = (self.color.red as i16 - color.red as i16);
|
||||
let green = (color.green as i16 - self.color.green as i16);
|
||||
let blue = (self.color.blue as i16 - color.blue as i16);
|
||||
self.step = (
|
||||
red / self.steps as i8,
|
||||
green / self.steps as i8,
|
||||
blue / self.steps as i8,
|
||||
-(red / self.steps as i16) as i8,
|
||||
-(green / self.steps as i16) as i8,
|
||||
-(blue / self.steps as i16) as i8,
|
||||
);
|
||||
Some(self.strip)
|
||||
} else {
|
||||
|
@ -59,10 +59,8 @@ impl<const N: usize> Iterator for StarsRandom<N> {
|
|||
let mut rng = rand::thread_rng();
|
||||
for i in 0..N {
|
||||
let current_color = self.strip[i];
|
||||
if current_color == self.background_color {
|
||||
if rng.gen_bool(1.0 / self.ratio as f64) {
|
||||
self.strip[i] = Some(self.color);
|
||||
}
|
||||
} else {
|
||||
let color = current_color.unwrap();
|
||||
let background = self.background_color.unwrap_or(PixelColor::default());
|
||||
|
|
122
src/pixel_color.rs
Normal file
122
src/pixel_color.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use rand::prelude::ThreadRng;
|
||||
use rand::Rng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops::{Add, AddAssign, Div, Sub, SubAssign};
|
||||
|
||||
///
|
||||
/// a struct for an RGB color
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Default, Eq, Hash, PartialEq)]
|
||||
pub struct PixelColor {
|
||||
pub(crate) red: u8,
|
||||
pub(crate) green: u8,
|
||||
pub(crate) blue: u8,
|
||||
}
|
||||
|
||||
impl fmt::Display for PixelColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[{},{},{}]", self.red, self.green, self.blue)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<u8> for PixelColor {
|
||||
type Output = PixelColor;
|
||||
|
||||
fn div(self, rhs: u8) -> Self::Output {
|
||||
PixelColor {
|
||||
red: self.red / rhs,
|
||||
green: self.green / rhs,
|
||||
blue: self.blue / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for PixelColor {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
PixelColor {
|
||||
red: self.red.saturating_add(rhs.red),
|
||||
green: self.green.saturating_add(rhs.green),
|
||||
blue: self.blue.saturating_add(rhs.blue),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u8> for PixelColor {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: u8) -> Self::Output {
|
||||
PixelColor {
|
||||
red: self.red.saturating_sub(rhs),
|
||||
green: self.green.saturating_sub(rhs),
|
||||
blue: self.blue.saturating_sub(rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for PixelColor {
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.red = self.red.saturating_sub(rhs.red);
|
||||
self.green = self.red.saturating_sub(rhs.green);
|
||||
self.blue = self.red.saturating_sub(rhs.blue);
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for PixelColor {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.red = self.red.saturating_add(rhs.red);
|
||||
self.green = self.red.saturating_add(rhs.green);
|
||||
self.blue = self.red.saturating_add(rhs.blue);
|
||||
}
|
||||
}
|
||||
|
||||
impl PixelColor {
|
||||
/// apply random delta to pixel and return computed value
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `pixel`: pixel to apply delta
|
||||
/// * `stability`: amplitude of delta between 0 and `stability`
|
||||
///
|
||||
/// returns: PixelColor
|
||||
///
|
||||
pub fn random_delta(&self, stability: usize, rng: &mut ThreadRng) -> PixelColor {
|
||||
let minus_interval = -(stability as i8);
|
||||
let max_interval = stability as i8;
|
||||
let red_delta = rng.gen_range(minus_interval..max_interval) as i8;
|
||||
let green_delta = rng.gen_range(minus_interval..max_interval) as i8;
|
||||
let blue_delta = rng.gen_range(minus_interval..max_interval) as i8;
|
||||
self.delta((red_delta, green_delta, blue_delta))
|
||||
}
|
||||
|
||||
pub fn delta(&self, delta: (i8, i8, i8)) -> PixelColor {
|
||||
let (red, green, blue) = delta;
|
||||
|
||||
let red = self.red as i16 + red as i16;
|
||||
let green = self.green as i16 + green as i16;
|
||||
let blue = self.blue as i16 + blue as i16;
|
||||
|
||||
let bound = |color: i16| {
|
||||
if color < 0 {
|
||||
0
|
||||
} else if color > 255 {
|
||||
255
|
||||
} else {
|
||||
color as u8
|
||||
}
|
||||
};
|
||||
|
||||
PixelColor {
|
||||
red: bound(red),
|
||||
green: bound(green),
|
||||
blue: bound(blue),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closer(&self, pixel: PixelColor, distance: PixelColor) -> bool {
|
||||
(self.red as i16 - pixel.red as i16).abs() <= distance.red as i16
|
||||
&& (self.green as i16 - pixel.green as i16).abs() <= distance.green as i16
|
||||
&& (self.blue as i16 - pixel.blue as i16).abs() <= distance.blue as i16
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use crate::config::Device;
|
||||
use crate::patterns::{Pattern, Patterns, PixelColor};
|
||||
use crate::patterns::{Pattern, Patterns};
|
||||
use crate::pixel_color::PixelColor;
|
||||
use crate::Strip;
|
||||
use bluer::Address;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -41,7 +42,16 @@ pub struct Context<const N: usize> {
|
|||
|
||||
pub(crate) type DeviceSequence<const N: usize> = Vec<Context<N>>;
|
||||
|
||||
pub async fn runner_loop<const N: usize>(runner: DeviceSequence<N>, tx: Sender<Strip<N>>) {
|
||||
/// iterate over `runner` and stream strip data to `tx` channel
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `runner`: Sequence to stream
|
||||
/// * `tx`: channel to stream data to
|
||||
///
|
||||
/// returns: ()
|
||||
///
|
||||
async fn runner_loop<const N: usize>(runner: DeviceSequence<N>, tx: Sender<Strip<N>>) {
|
||||
let mut background = Strip::<N>::default();
|
||||
for mut context in runner {
|
||||
let mut strip = context.pattern.init().unwrap_or(background);
|
||||
|
@ -59,7 +69,7 @@ pub async fn runner_loop<const N: usize>(runner: DeviceSequence<N>, tx: Sender<S
|
|||
}
|
||||
}
|
||||
|
||||
pub fn apply_mask<const N: usize>(previous_strip: Strip<N>, strip: Strip<{ N }>) -> Strip<N> {
|
||||
fn apply_mask<const N: usize>(previous_strip: Strip<N>, strip: Strip<{ N }>) -> Strip<N> {
|
||||
let mut new_strip = Strip::default();
|
||||
for i in 0..N {
|
||||
if let Some(color) = strip[i] {
|
||||
|
@ -94,6 +104,15 @@ impl<const N: usize> Spectacle<N> {
|
|||
}
|
||||
}
|
||||
|
||||
/// add default sequence for any device implementing **adafruit neopixel BLE**
|
||||
/// not specified in an other sequence.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `runner`: sequence to stream
|
||||
///
|
||||
/// returns: ()
|
||||
///
|
||||
pub fn add_default(&mut self, runner: DeviceSequence<N>) {
|
||||
let (tx, rx) = tokio::sync::watch::channel(Strip::<N>::new(PixelColor {
|
||||
red: 0,
|
||||
|
@ -104,6 +123,15 @@ impl<const N: usize> Spectacle<N> {
|
|||
self.default_receiver = Some(rx);
|
||||
}
|
||||
|
||||
/// Get channel associated with the mac address passed in parameters. If no channel found,
|
||||
/// give back the default channel if existing.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `mac_address`: mac address to look for
|
||||
///
|
||||
/// returns: Option<Receiver<Strip<{ N }>>>
|
||||
///
|
||||
pub fn get_channel(&self, mac_address: &Address) -> Option<Receiver<Strip<N>>> {
|
||||
let channel = self.channels.get(mac_address);
|
||||
match channel {
|
||||
|
@ -124,6 +152,12 @@ impl<const N: usize> Spectacle<N> {
|
|||
}
|
||||
}
|
||||
|
||||
/// start to stream configured sequences. Returns the joinhandle of task to wait for
|
||||
///
|
||||
///
|
||||
///
|
||||
/// returns: Vec<impl Future<Output = ()>>
|
||||
///
|
||||
pub fn run(&mut self) -> Vec<impl Future<Output = ()>> {
|
||||
let mut joinhandles = vec![];
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user