Add exiting, settings, changing tick time

This commit is contained in:
Your Name 2021-08-01 23:56:05 +01:00
parent d4408ed005
commit 6c0a379aa7
4 changed files with 93 additions and 27 deletions

View File

@ -39,9 +39,17 @@ use ui::console_ui_loop;
fn main() { fn main() {
let (tx, rx) = channel::<Message>(); let (tx, rx) = channel::<Message>();
thread::spawn(move || { thread::spawn(move || {
let mut strip = LEDStrip::new(3); let mut strip = LEDStrip::new(strip::Config {
// I have 89 right now, but start off with 20
num_lights: 20,
// Skip 14 lights
shift_lights: 14,
// Scaling factor (scale 0..255)
global_brightness_max: 20,
tick_time_ms: strip::DEFAULT_TICK_TIME_MS,
});
strip.strip_loop(&rx); strip.strip_loop(&rx);
println!("Dead therad"); panic!("Dead strip thread. Terminating");
}); });
console_ui_loop(&tx); console_ui_loop(&tx);

View File

@ -190,13 +190,6 @@ impl Pattern for Collide {
} else { } else {
(self.left_color, self.right_color) (self.left_color, self.right_color)
}; };
// let colors = match self.step {
// // If we are in the conjoined bounds region, these will be the same color
// // (self.conjoined_bounds.0)..=(self.conjoined_bounds.1) => (self.conjoined_color, self.conjoined_color),
// l..=r => (self.conjoined_color, self.conjoined_color),
// // If
// _ => (self.left_color, self.right_color),
// };
// Turn off the previous LED // Turn off the previous LED
lights_buf[usize::from(self.previous_offset)] = color::BLACK; lights_buf[usize::from(self.previous_offset)] = color::BLACK;

View File

@ -1,53 +1,85 @@
use crate::color::{self, RGB}; use crate::color::{self, RGB};
use crate::pattern::{self, Pattern}; use crate::pattern::{self, Pattern};
use std::cmp;
use std::ops::Add; use std::ops::Add;
use std::process;
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use ws2818_rgb_led_spi_driver::adapter_gen::WS28xxAdapter; use ws2818_rgb_led_spi_driver::adapter_gen::WS28xxAdapter;
use ws2818_rgb_led_spi_driver::adapter_spi::WS28xxSpiAdapter; use ws2818_rgb_led_spi_driver::adapter_spi::WS28xxSpiAdapter;
const MAX_NUM_LIGHTS: u16 = 32; /// Maximum number of lights allowed
const TICK_TIME: u64 = 400; const MAX_NUM_LIGHTS: u16 = 128;
/// Default time per tick
pub const DEFAULT_TICK_TIME_MS: u64 = 50;
/// Minimum time per tick before strip breaks
const MIN_TICK_TIME: u64 = 10;
#[derive(Debug, Clone)]
pub struct Config {
/// Number of lights
pub num_lights: u16,
/// Number of lights to skip
pub shift_lights: u16,
/// Global brightness multiplier
pub global_brightness_max: u8,
/// Time per tick
pub tick_time_ms: u64,
}
pub enum Message { pub enum Message {
ClearLights, ClearLights,
ChangePattern(Box<dyn Pattern + Send>), ChangePattern(Box<dyn Pattern + Send>),
SetNumLights(u16), SetNumLights(u16),
SetTickTime(u64),
Quit,
} }
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub struct LEDStrip { pub struct LEDStrip {
pub adapter: Box<dyn WS28xxAdapter>, pub adapter: Box<dyn WS28xxAdapter>,
pub num_lights: u16, pub config: Config,
pub pattern: Box<dyn Pattern>, pub pattern: Box<dyn Pattern>,
pub lights_buf: Vec<RGB>, pub lights_buf: Vec<RGB>,
} }
impl LEDStrip { impl LEDStrip {
pub fn new(num_lights: u16) -> Self { pub fn new(config: Config) -> Self {
let adapter = Box::new( let adapter = Box::new(
WS28xxSpiAdapter::new("/dev/spidev0.0").expect("Cannot locate device /dev/spidev0.0!"), WS28xxSpiAdapter::new("/dev/spidev0.0").expect("Cannot locate device /dev/spidev0.0!"),
); );
// let pattern = Pattern::default();
let pattern = Box::new(pattern::Solid::new(color::BLACK)); let pattern = Box::new(pattern::Solid::new(color::BLACK));
let num_lights = config.num_lights;
let lights_buf = vec![color::BLACK; num_lights.into()]; let lights_buf = vec![color::BLACK; num_lights.into()];
let mut ret = Self { let mut ret = Self {
adapter, adapter,
pattern, pattern,
lights_buf, lights_buf,
num_lights, config,
}; };
ret.set_num_lights(num_lights); ret.set_num_lights(num_lights);
ret ret
} }
fn write_buf(&mut self) { fn write_buf(&mut self) {
let data = self let data = vec![color::BLACK]
.lights_buf .iter()
.cycle()
.take(self.config.shift_lights.into())
.chain(
self.lights_buf
.as_slice() .as_slice()
.iter() .iter()
.take(self.num_lights.into()) .take(self.config.num_lights.into()),
)
.map(|c| c.to_tuple()) .map(|c| c.to_tuple())
.map(|(r, g, b)| {
(
cmp::min(r, self.config.global_brightness_max),
cmp::min(g, self.config.global_brightness_max),
cmp::min(b, self.config.global_brightness_max),
)
})
.collect::<Vec<(u8, u8, u8)>>(); .collect::<Vec<(u8, u8, u8)>>();
self.adapter self.adapter
.write_rgb(data.as_slice()) .write_rgb(data.as_slice())
@ -63,19 +95,23 @@ impl LEDStrip {
return; return;
} }
if self.pattern.init(&mut self.lights_buf, num_lights).is_ok() { if self.pattern.init(&mut self.lights_buf, num_lights).is_ok() {
self.num_lights = num_lights; self.config.num_lights = num_lights;
} }
} }
pub fn strip_loop(&mut self, rx: &Receiver<Message>) { pub fn strip_loop(&mut self, rx: &Receiver<Message>) {
let mut exit = false;
loop { loop {
let target_time = Instant::now().add(Duration::from_millis(TICK_TIME)); let target_time = Instant::now().add(Duration::from_millis(self.config.tick_time_ms));
if let Ok(message) = rx.try_recv() { if let Ok(message) = rx.try_recv() {
match message { match message {
Message::ClearLights => { Message::ClearLights => {
let mut pat = Box::new(pattern::Solid::new(color::BLACK)); let mut pat = Box::new(pattern::Solid::new(color::BLACK));
if pat.init(&mut self.lights_buf, self.num_lights).is_ok() { if pat
.init(&mut self.lights_buf, self.config.num_lights)
.is_ok()
{
self.pattern = pat; self.pattern = pat;
} else { } else {
println!("Clearing light strip: {:?}", pat); println!("Clearing light strip: {:?}", pat);
@ -83,7 +119,10 @@ impl LEDStrip {
} }
Message::ChangePattern(pat) => { Message::ChangePattern(pat) => {
let mut pat = pat; let mut pat = pat;
if pat.init(&mut self.lights_buf, self.num_lights).is_ok() { if pat
.init(&mut self.lights_buf, self.config.num_lights)
.is_ok()
{
self.pattern = pat; self.pattern = pat;
} else { } else {
println!("Error with pattern: {:?}", pat); println!("Error with pattern: {:?}", pat);
@ -92,6 +131,24 @@ impl LEDStrip {
Message::SetNumLights(num_lights) => { Message::SetNumLights(num_lights) => {
self.set_num_lights(num_lights); self.set_num_lights(num_lights);
} }
Message::SetTickTime(tick_time_ms) => {
if tick_time_ms < MIN_TICK_TIME {
println!("Error with tick time: {}", tick_time_ms);
}
self.config.tick_time_ms = tick_time_ms;
}
Message::Quit => {
exit = true;
let mut pat = pattern::Solid::new(color::BLACK);
if pat
.init(&mut self.lights_buf, self.config.num_lights)
.is_ok()
{
self.pattern = Box::new(pat);
} else {
println!("Could not construct clear pattern");
}
}
} }
} }
@ -99,12 +156,15 @@ impl LEDStrip {
self.write_buf(); self.write_buf();
} }
// let mut num_iter = 0; if exit {
println!("Exiting as requested");
process::exit(0);
}
loop { loop {
if Instant::now() >= target_time { if Instant::now() >= target_time {
break; break;
} }
// num_iter += 1;
} }
} }
} }

View File

@ -73,14 +73,19 @@ fn parse_cmd(tx: &Sender<strip::Message>, s: &str) -> Result<(), String> {
["x"] => tx ["x"] => tx
.send(strip::Message::ClearLights) .send(strip::Message::ClearLights)
.map_err(|e| e.to_string()), .map_err(|e| e.to_string()),
["q"] => Ok(()), ["q"] => tx.send(strip::Message::Quit).map_err(|e| e.to_string()),
["s", n] => tx ["s", n] => tx
.send(strip::Message::SetNumLights( .send(strip::Message::SetNumLights(
n.parse::<u16>() n.parse::<u16>()
.map_err(|_| String::from("Could not parse light count"))?, .map_err(|_| String::from("Could not parse light count"))?,
)) ))
.map_err(|e| e.to_string()), .map_err(|e| e.to_string()),
_ => Err(String::from("Unknown command. Available commands: solidColor movingRainbow Bouncing Fade clear(X) Setnumlights")), ["t", n] => tx.send(strip::Message::SetTickTime(
n.parse::<u64>()
.map_err(|_| String::from("Could not parse light count"))?,
))
.map_err(|e| e.to_string()),
_ => Err(String::from("Unknown command. Available commands: solidColor movingRainbow Bouncing Fade clear(X) Setnumlights setTicktime")),
} }
} }