add fillRandom pattern
This commit is contained in:
parent
20983a8c08
commit
3d8adc0d52
37
Cargo.lock
generated
37
Cargo.lock
generated
|
@ -482,6 +482,12 @@ version = "0.3.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.36"
|
version = "1.0.36"
|
||||||
|
@ -500,6 +506,36 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -515,6 +551,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bluer",
|
"bluer",
|
||||||
"futures",
|
"futures",
|
||||||
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
|
|
@ -9,6 +9,7 @@ edition = "2018"
|
||||||
bluer = "0.13.1"
|
bluer = "0.13.1"
|
||||||
tokio = {version = "1.15.0", features = ["full"]}
|
tokio = {version = "1.15.0", features = ["full"]}
|
||||||
futures = "0.3.19"
|
futures = "0.3.19"
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
||||||
serde_derive = "1.0.136"
|
serde_derive = "1.0.136"
|
||||||
serde = "1.0.136"
|
serde = "1.0.136"
|
||||||
|
|
|
@ -13,6 +13,16 @@
|
||||||
period:
|
period:
|
||||||
secs: 0
|
secs: 0
|
||||||
nanos: 200000000
|
nanos: 200000000
|
||||||
|
- pattern:
|
||||||
|
type: FillRandom
|
||||||
|
color:
|
||||||
|
red: 0
|
||||||
|
green: 0
|
||||||
|
blue: 255
|
||||||
|
stability: 40
|
||||||
|
period:
|
||||||
|
secs: 0
|
||||||
|
nanos: 100000000
|
||||||
- pattern:
|
- pattern:
|
||||||
type: ColorWipe
|
type: ColorWipe
|
||||||
current_iteration: 0
|
current_iteration: 0
|
||||||
|
@ -20,17 +30,11 @@
|
||||||
red: 0
|
red: 0
|
||||||
green: 255
|
green: 255
|
||||||
blue: 0
|
blue: 0
|
||||||
|
background_color:
|
||||||
|
red: 255
|
||||||
|
green: 0
|
||||||
|
blue: 255
|
||||||
infinite: false
|
infinite: false
|
||||||
period:
|
period:
|
||||||
secs: 0
|
secs: 0
|
||||||
nanos: 100000000
|
nanos: 100000000
|
||||||
- pattern:
|
|
||||||
type: Scanner
|
|
||||||
current_iteration: 0
|
|
||||||
color:
|
|
||||||
red: 0
|
|
||||||
green: 0
|
|
||||||
blue: 255
|
|
||||||
period:
|
|
||||||
secs: 0
|
|
||||||
nanos: 100000000
|
|
37
src/main.rs
37
src/main.rs
|
@ -3,7 +3,6 @@ mod patterns;
|
||||||
mod runner;
|
mod runner;
|
||||||
mod spectacle;
|
mod spectacle;
|
||||||
|
|
||||||
use crate::patterns::{ColorWipe, Fade, Patterns, PixelColor};
|
|
||||||
use crate::runner::Runner;
|
use crate::runner::Runner;
|
||||||
use bluer::gatt::remote::Characteristic;
|
use bluer::gatt::remote::Characteristic;
|
||||||
use patterns::Strip;
|
use patterns::Strip;
|
||||||
|
@ -19,44 +18,8 @@ const BASE_STRIP_DATA: [u8; 3] = [0x00, 0x00, 0x01];
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> bluer::Result<()> {
|
async fn main() -> bluer::Result<()> {
|
||||||
let pixel = PixelColor {
|
|
||||||
red: 231,
|
|
||||||
green: 124,
|
|
||||||
blue: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let fade = Fade::<25> {
|
|
||||||
current_iteration: 0,
|
|
||||||
nbr_iterations: 0,
|
|
||||||
begin_color: pixel,
|
|
||||||
end_color: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let context = runner::Context {
|
|
||||||
pattern: Patterns::Fade(fade),
|
|
||||||
period: Duration::from_millis(300),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut runner = runner::Runner::<25>::new();
|
|
||||||
runner.push(context);
|
|
||||||
|
|
||||||
let context = runner::Context {
|
|
||||||
pattern: Patterns::ColorWipe(ColorWipe {
|
|
||||||
current_iteration: 0,
|
|
||||||
color: Default::default(),
|
|
||||||
infinite: false,
|
|
||||||
}),
|
|
||||||
period: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
runner.push(context);
|
|
||||||
|
|
||||||
let yaml = serde_yaml::to_string(&runner).unwrap();
|
|
||||||
println!("{}", yaml);
|
|
||||||
|
|
||||||
let file = Path::new("spectacle.yml");
|
let file = Path::new("spectacle.yml");
|
||||||
let config: Runner<25> = Runner::load_from_file(file);
|
let config: Runner<25> = Runner::load_from_file(file);
|
||||||
println!("{:?}", config);
|
|
||||||
|
|
||||||
let adapter = bluetooth::create_session().await?;
|
let adapter = bluetooth::create_session().await?;
|
||||||
|
|
||||||
|
|
188
src/patterns.rs
188
src/patterns.rs
|
@ -1,8 +1,7 @@
|
||||||
|
use rand::Rng;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::cmp::{max, min, Ordering};
|
|
||||||
use std::convert::Infallible;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Div;
|
use std::ops::{Div, Index, IndexMut, SubAssign};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
|
@ -11,6 +10,7 @@ pub(crate) enum Patterns<const N: usize> {
|
||||||
Fade(Fade<N>),
|
Fade(Fade<N>),
|
||||||
ColorWipe(ColorWipe<N>),
|
ColorWipe(ColorWipe<N>),
|
||||||
Scanner(Scanner<N>),
|
Scanner(Scanner<N>),
|
||||||
|
FillRandom(FillRandom<N>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Iterator for Patterns<N> {
|
impl<const N: usize> Iterator for Patterns<N> {
|
||||||
|
@ -22,23 +22,20 @@ impl<const N: usize> Iterator for Patterns<N> {
|
||||||
Patterns::Fade(p) => p.next(),
|
Patterns::Fade(p) => p.next(),
|
||||||
Patterns::ColorWipe(p) => p.next(),
|
Patterns::ColorWipe(p) => p.next(),
|
||||||
Patterns::Scanner(p) => p.next(),
|
Patterns::Scanner(p) => p.next(),
|
||||||
|
Patterns::FillRandom(p) => p.next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
|
///
|
||||||
|
/// a struct for an RGB color
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Default)]
|
||||||
pub struct PixelColor {
|
pub struct PixelColor {
|
||||||
pub(crate) red: u8,
|
pub(crate) red: u8,
|
||||||
pub(crate) green: u8,
|
pub(crate) green: u8,
|
||||||
pub(crate) blue: u8,
|
pub(crate) blue: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PixelColor {
|
|
||||||
fn new() -> Self {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PixelColor {
|
impl fmt::Display for PixelColor {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "[{},{},{}]", self.red, self.green, self.blue)
|
write!(f, "[{},{},{}]", self.red, self.green, self.blue)
|
||||||
|
@ -57,9 +54,39 @@ impl Div<u8> for PixelColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SubAssign for PixelColor {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
println!("self.red {}, red {}", self.red, rhs.red);
|
||||||
|
self.red = self.red.saturating_sub(rhs.red);
|
||||||
|
self.green = self.red.saturating_sub(rhs.green);
|
||||||
|
self.blue = self.red.saturating_sub(rhs.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// a basic newtype based on a fix array size.
|
||||||
|
///
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Strip<const N: usize> {
|
pub struct Strip<const N: usize>([PixelColor; N]);
|
||||||
pub strip: [PixelColor; N],
|
|
||||||
|
impl<const N: usize> Default for Strip<N> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Strip([PixelColor::default(); N])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Index<usize> for Strip<N> {
|
||||||
|
type Output = PixelColor;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> IndexMut<usize> for Strip<N> {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut PixelColor {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Strip<N> {
|
impl<const N: usize> Strip<N> {
|
||||||
|
@ -67,30 +94,26 @@ impl<const N: usize> Strip<N> {
|
||||||
let mut data: Vec<u8> = vec![];
|
let mut data: Vec<u8> = vec![];
|
||||||
|
|
||||||
for i in 0..N {
|
for i in 0..N {
|
||||||
data.append(&mut vec![
|
data.append(&mut vec![self[i].green, self[i].red, self[i].blue]);
|
||||||
self.strip[i].green,
|
|
||||||
self.strip[i].red,
|
|
||||||
self.strip[i].blue,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill(&mut self, color: PixelColor) {
|
pub fn fill(&mut self, color: PixelColor) {
|
||||||
self.strip = [color; N];
|
self.0.fill(color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Default for Strip<N> {
|
/// # Rainbow pattern
|
||||||
fn default() -> Self {
|
///
|
||||||
Strip {
|
/// every pattern implement the iterator trait
|
||||||
strip: [PixelColor::new(); N],
|
///
|
||||||
}
|
/// This pattern display a moving rainbow over the strip
|
||||||
}
|
///
|
||||||
}
|
/// ### Note
|
||||||
|
///
|
||||||
/// Rainbow pattern /////////////////////////////////////////////////
|
/// If max iteration is let to None, it's an infinite pattern.
|
||||||
|
///
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Rainbow<const N: usize> {
|
pub struct Rainbow<const N: usize> {
|
||||||
pub(crate) current_iteration: usize,
|
pub(crate) current_iteration: usize,
|
||||||
|
@ -111,13 +134,21 @@ impl<const N: usize> Iterator for Rainbow<N> {
|
||||||
let step = self.step.unwrap_or(255 / N);
|
let step = self.step.unwrap_or(255 / N);
|
||||||
for i in 0..N {
|
for i in 0..N {
|
||||||
let pos = (i * step + self.current_iteration) as u8;
|
let pos = (i * step + self.current_iteration) as u8;
|
||||||
strip.strip[i] = wheel(pos)
|
strip[i] = wheel(pos)
|
||||||
}
|
}
|
||||||
self.current_iteration += 1;
|
self.current_iteration += 1;
|
||||||
Some(strip)
|
Some(strip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// compute **rgb** pixel color according to the **hsv** wheel
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `index`: position in the hsv wheel
|
||||||
|
///
|
||||||
|
/// returns: PixelColor
|
||||||
|
///
|
||||||
fn wheel(index: u8) -> PixelColor {
|
fn wheel(index: u8) -> PixelColor {
|
||||||
let pos = 255 - index;
|
let pos = 255 - index;
|
||||||
match pos {
|
match pos {
|
||||||
|
@ -145,15 +176,21 @@ fn wheel(index: u8) -> PixelColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
/// # Colorwipe pattern
|
||||||
/// Colorwipe pattern ////////////////////////////////////////////////////
|
/// every pattern implement the iterator trait
|
||||||
//////////////////////////////////////////////////////////////////////////
|
///
|
||||||
|
/// This pattern fill the strip with a specific color, one by one.
|
||||||
|
///
|
||||||
|
/// ### Note
|
||||||
|
///
|
||||||
|
/// setting max_iteration to None lead the pattern to loop infinitely
|
||||||
|
///
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct ColorWipe<const N: usize> {
|
pub struct ColorWipe<const N: usize> {
|
||||||
pub(crate) current_iteration: usize,
|
pub(crate) current_iteration: usize,
|
||||||
|
pub(crate) max_iteration: Option<usize>,
|
||||||
pub(crate) color: PixelColor,
|
pub(crate) color: PixelColor,
|
||||||
pub(crate) infinite: bool,
|
pub(crate) background_color: Option<PixelColor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Iterator for ColorWipe<N> {
|
impl<const N: usize> Iterator for ColorWipe<N> {
|
||||||
|
@ -161,24 +198,26 @@ impl<const N: usize> Iterator for ColorWipe<N> {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let mut strip = Strip::default();
|
let mut strip = Strip::default();
|
||||||
if self.infinite {
|
if let Some(c) = self.background_color {
|
||||||
self.current_iteration %= N;
|
strip.fill(c);
|
||||||
} else if self.current_iteration >= N {
|
}
|
||||||
return None;
|
let iteration = self.current_iteration % N;
|
||||||
|
if let Some(max_iteration) = self.max_iteration {
|
||||||
|
if self.current_iteration >= max_iteration {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..self.current_iteration {
|
for i in 0..iteration {
|
||||||
strip.strip[i] = self.color;
|
strip[i] = self.color;
|
||||||
}
|
}
|
||||||
self.current_iteration += 1;
|
self.current_iteration += 1;
|
||||||
Some(strip)
|
Some(strip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
/// # fade pattern
|
||||||
/// fade pattern ////////////////////////////////////////////////////
|
/// fade from one color to an other
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Fade<const N: usize> {
|
pub struct Fade<const N: usize> {
|
||||||
pub(crate) current_iteration: usize,
|
pub(crate) current_iteration: usize,
|
||||||
|
@ -229,10 +268,12 @@ impl<const N: usize> Iterator for Fade<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
/// # scanner pattern
|
||||||
/// scanner pattern ////////////////////////////////////////////////////
|
/// color one pixel with a color and leave a train of this color fading to black
|
||||||
//////////////////////////////////////////////////////////////////////////
|
///
|
||||||
|
/// # note
|
||||||
|
///
|
||||||
|
/// background_color work only for color not set by scanner pattern
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Scanner<const N: usize> {
|
pub struct Scanner<const N: usize> {
|
||||||
pub(crate) current_iteration: usize,
|
pub(crate) current_iteration: usize,
|
||||||
|
@ -260,11 +301,58 @@ impl<const N: usize> Iterator for Scanner<N> {
|
||||||
}
|
}
|
||||||
let mut c = self.color;
|
let mut c = self.color;
|
||||||
for i in min_led..current_led {
|
for i in min_led..current_led {
|
||||||
strip.strip[i] = c;
|
strip[i] = c;
|
||||||
c = c / 2;
|
c = c / 2;
|
||||||
println!("{}", c);
|
|
||||||
}
|
}
|
||||||
self.current_iteration += 1;
|
self.current_iteration += 1;
|
||||||
Some(strip)
|
Some(strip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # FillRandom
|
||||||
|
///
|
||||||
|
/// fill strip with color then apply random variation
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct FillRandom<const N: usize> {
|
||||||
|
pub(crate) color: PixelColor,
|
||||||
|
pub(crate) stability: usize,
|
||||||
|
pub(crate) max_iteration: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Iterator for FillRandom<N> {
|
||||||
|
type Item = Strip<N>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(iteration) = self.max_iteration {
|
||||||
|
if iteration == 0 {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
self.max_iteration = Some(iteration - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut strip = Strip::<N>::default();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
for i in 0..N {
|
||||||
|
let red_delta = rng.gen_range(0..self.stability) as u8;
|
||||||
|
let green_delta = rng.gen_range(0..self.stability) as u8;
|
||||||
|
let blue_delta = rng.gen_range(0..self.stability) as u8;
|
||||||
|
let operation = rng.gen_bool(0.5);
|
||||||
|
let red;
|
||||||
|
let green;
|
||||||
|
let blue;
|
||||||
|
if operation {
|
||||||
|
red = self.color.red.saturating_add(red_delta);
|
||||||
|
green = self.color.green.saturating_add(green_delta);
|
||||||
|
blue = self.color.blue.saturating_add(blue_delta);
|
||||||
|
} else {
|
||||||
|
red = self.color.red.saturating_sub(red_delta);
|
||||||
|
green = self.color.green.saturating_sub(green_delta);
|
||||||
|
blue = self.color.blue.saturating_sub(blue_delta);
|
||||||
|
}
|
||||||
|
let c = PixelColor { red, green, blue };
|
||||||
|
strip[i] = c;
|
||||||
|
}
|
||||||
|
Some(strip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
Loading…
Reference in New Issue
Block a user