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"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
|
@ -500,6 +506,36 @@ dependencies = [
|
|||
"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]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
|
@ -515,6 +551,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bluer",
|
||||
"futures",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_yaml",
|
||||
|
|
|
@ -9,6 +9,7 @@ edition = "2018"
|
|||
bluer = "0.13.1"
|
||||
tokio = {version = "1.15.0", features = ["full"]}
|
||||
futures = "0.3.19"
|
||||
rand = "0.8.5"
|
||||
|
||||
serde_derive = "1.0.136"
|
||||
serde = "1.0.136"
|
||||
|
|
|
@ -13,6 +13,16 @@
|
|||
period:
|
||||
secs: 0
|
||||
nanos: 200000000
|
||||
- pattern:
|
||||
type: FillRandom
|
||||
color:
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 255
|
||||
stability: 40
|
||||
period:
|
||||
secs: 0
|
||||
nanos: 100000000
|
||||
- pattern:
|
||||
type: ColorWipe
|
||||
current_iteration: 0
|
||||
|
@ -20,17 +30,11 @@
|
|||
red: 0
|
||||
green: 255
|
||||
blue: 0
|
||||
background_color:
|
||||
red: 255
|
||||
green: 0
|
||||
blue: 255
|
||||
infinite: false
|
||||
period:
|
||||
secs: 0
|
||||
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 spectacle;
|
||||
|
||||
use crate::patterns::{ColorWipe, Fade, Patterns, PixelColor};
|
||||
use crate::runner::Runner;
|
||||
use bluer::gatt::remote::Characteristic;
|
||||
use patterns::Strip;
|
||||
|
@ -19,44 +18,8 @@ const BASE_STRIP_DATA: [u8; 3] = [0x00, 0x00, 0x01];
|
|||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
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 config: Runner<25> = Runner::load_from_file(file);
|
||||
println!("{:?}", config);
|
||||
|
||||
let adapter = bluetooth::create_session().await?;
|
||||
|
||||
|
|
186
src/patterns.rs
186
src/patterns.rs
|
@ -1,8 +1,7 @@
|
|||
use rand::Rng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::cmp::{max, min, Ordering};
|
||||
use std::convert::Infallible;
|
||||
use std::fmt;
|
||||
use std::ops::Div;
|
||||
use std::ops::{Div, Index, IndexMut, SubAssign};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
|
@ -11,6 +10,7 @@ pub(crate) enum Patterns<const N: usize> {
|
|||
Fade(Fade<N>),
|
||||
ColorWipe(ColorWipe<N>),
|
||||
Scanner(Scanner<N>),
|
||||
FillRandom(FillRandom<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::ColorWipe(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(crate) red: u8,
|
||||
pub(crate) green: u8,
|
||||
pub(crate) blue: u8,
|
||||
}
|
||||
|
||||
impl PixelColor {
|
||||
fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PixelColor {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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)]
|
||||
pub struct Strip<const N: usize> {
|
||||
pub strip: [PixelColor; N],
|
||||
pub struct Strip<const N: usize>([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> {
|
||||
|
@ -67,30 +94,26 @@ impl<const N: usize> Strip<N> {
|
|||
let mut data: Vec<u8> = vec![];
|
||||
|
||||
for i in 0..N {
|
||||
data.append(&mut vec![
|
||||
self.strip[i].green,
|
||||
self.strip[i].red,
|
||||
self.strip[i].blue,
|
||||
]);
|
||||
data.append(&mut vec![self[i].green, self[i].red, self[i].blue]);
|
||||
}
|
||||
data
|
||||
}
|
||||
|
||||
pub fn fill(&mut self, color: PixelColor) {
|
||||
self.strip = [color; N];
|
||||
self.0.fill(color);
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> Default for Strip<N> {
|
||||
fn default() -> Self {
|
||||
Strip {
|
||||
strip: [PixelColor::new(); N],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rainbow pattern /////////////////////////////////////////////////
|
||||
|
||||
/// # Rainbow pattern
|
||||
///
|
||||
/// every pattern implement the iterator trait
|
||||
///
|
||||
/// This pattern display a moving rainbow over the strip
|
||||
///
|
||||
/// ### Note
|
||||
///
|
||||
/// If max iteration is let to None, it's an infinite pattern.
|
||||
///
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Rainbow<const N: 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);
|
||||
for i in 0..N {
|
||||
let pos = (i * step + self.current_iteration) as u8;
|
||||
strip.strip[i] = wheel(pos)
|
||||
strip[i] = wheel(pos)
|
||||
}
|
||||
self.current_iteration += 1;
|
||||
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 {
|
||||
let pos = 255 - index;
|
||||
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)]
|
||||
pub struct ColorWipe<const N: usize> {
|
||||
pub(crate) current_iteration: usize,
|
||||
pub(crate) max_iteration: Option<usize>,
|
||||
pub(crate) color: PixelColor,
|
||||
pub(crate) infinite: bool,
|
||||
pub(crate) background_color: Option<PixelColor>,
|
||||
}
|
||||
|
||||
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> {
|
||||
let mut strip = Strip::default();
|
||||
if self.infinite {
|
||||
self.current_iteration %= N;
|
||||
} else if self.current_iteration >= N {
|
||||
if let Some(c) = self.background_color {
|
||||
strip.fill(c);
|
||||
}
|
||||
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 {
|
||||
strip.strip[i] = self.color;
|
||||
for i in 0..iteration {
|
||||
strip[i] = self.color;
|
||||
}
|
||||
self.current_iteration += 1;
|
||||
Some(strip)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// fade pattern ////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// # fade pattern
|
||||
/// fade from one color to an other
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Fade<const N: 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)]
|
||||
pub struct Scanner<const N: usize> {
|
||||
pub(crate) current_iteration: usize,
|
||||
|
@ -260,11 +301,58 @@ impl<const N: usize> Iterator for Scanner<N> {
|
|||
}
|
||||
let mut c = self.color;
|
||||
for i in min_led..current_led {
|
||||
strip.strip[i] = c;
|
||||
strip[i] = c;
|
||||
c = c / 2;
|
||||
println!("{}", c);
|
||||
}
|
||||
self.current_iteration += 1;
|
||||
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