Start work on errors

This commit is contained in:
Austen Adler 2021-08-07 00:29:40 -04:00
parent 2859a23b1e
commit 409f1d65a5
4 changed files with 66 additions and 19 deletions

37
src/errors.rs Normal file
View File

@ -0,0 +1,37 @@
use core::any::Any;
use std::fmt;
#[derive(Debug)]
pub enum ProgramError {
General(String),
UiError(String),
Boxed(Box<dyn Any + Send>),
}
impl From<String> for ProgramError {
fn from(e: String) -> Self {
Self::General(e)
}
}
impl From<&str> for ProgramError {
fn from(e: &str) -> Self {
Self::General(e.to_string())
}
}
impl From<Box<dyn Any + Send>> for ProgramError {
fn from(e: Box<dyn Any + Send>) -> Self {
Self::Boxed(e)
}
}
impl fmt::Display for ProgramError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::General(s) => write!(f, "{}", s),
Self::UiError(s) => write!(f, "Critial UI error: {}", s),
Self::Boxed(s) => write!(f, "{:?}", s),
}
}
}

View File

@ -21,24 +21,25 @@
clippy::indexing_slicing, clippy::indexing_slicing,
clippy::integer_arithmetic, clippy::integer_arithmetic,
clippy::integer_division, clippy::integer_division,
// Expect prints a message when there is a critical error, so this is valid
clippy::expect_used, clippy::expect_used,
clippy::unwrap_used, clippy::unwrap_used,
)] )]
// See https://rust-lang.github.io/rust-clippy/master/index.html for more lints // See https://rust-lang.github.io/rust-clippy/master/index.html for more lints
mod color; mod color;
mod errors;
mod pattern; mod pattern;
mod strip; mod strip;
mod ui; mod ui;
use errors::ProgramError;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::thread; use std::thread;
use strip::{LEDStrip, Message}; use strip::{LEDStrip, Message};
use ui::console_ui_loop; use ui::console_ui_loop;
fn main() { fn main() -> Result<(), ProgramError> {
let (tx, rx) = channel::<Message>(); let (tx, rx) = channel::<Message>();
thread::spawn(move || { let handle = thread::spawn(move || -> Result<(), ProgramError> {
let mut strip = LEDStrip::new(strip::Config { let mut strip = LEDStrip::new(strip::Config {
// I have 89 right now, but start off with 20 // I have 89 right now, but start off with 20
num_lights: 20, num_lights: 20,
@ -47,10 +48,14 @@ fn main() {
// Scaling factor (scale 0..255) // Scaling factor (scale 0..255)
global_brightness_max: 20, global_brightness_max: 20,
tick_time_ms: strip::DEFAULT_TICK_TIME_MS, tick_time_ms: strip::DEFAULT_TICK_TIME_MS,
}); })?;
strip.strip_loop(&rx); strip.strip_loop(&rx);
panic!("Dead strip thread. Terminating"); Err(ProgramError::General(String::from(
"Dead strip thread. Terminating",
)))
}); });
console_ui_loop(&tx); console_ui_loop(&tx)?;
handle.join()?
} }

View File

@ -1,4 +1,5 @@
use crate::color; use crate::color;
use crate::errors::ProgramError;
use crate::pattern::{self, Pattern}; use crate::pattern::{self, Pattern};
use std::cmp; use std::cmp;
use std::ops::Add; use std::ops::Add;
@ -43,9 +44,10 @@ pub struct LEDStrip {
} }
impl LEDStrip { impl LEDStrip {
pub fn new(config: Config) -> Self { pub fn new(config: Config) -> Result<Self, ProgramError> {
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")
.map_err(|_| "Cannot start device /dev/spidev0.0!")?,
); );
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 num_lights = config.num_lights;
@ -55,10 +57,10 @@ impl LEDStrip {
config, config,
}; };
ret.set_num_lights(num_lights); ret.set_num_lights(num_lights);
ret Ok(ret)
} }
fn write_buf_from_pattern(&mut self) { fn write_buf_from_pattern(&mut self) -> Result<(), ProgramError> {
let global_brightness_max = self.config.global_brightness_max; let global_brightness_max = self.config.global_brightness_max;
let data = vec![color::BLACK] let data = vec![color::BLACK]
.iter() .iter()
@ -81,9 +83,8 @@ impl LEDStrip {
}) })
// TODO: Do not re-collect as u8s // TODO: Do not re-collect as u8s
.collect::<Vec<(u8, u8, u8)>>(); .collect::<Vec<(u8, u8, u8)>>();
self.adapter self.adapter.write_rgb(data.as_slice())?;
.write_rgb(data.as_slice()) Ok(())
.expect("TODO: Critical data write error!");
} }
fn set_num_lights(&mut self, num_lights: u16) { fn set_num_lights(&mut self, num_lights: u16) {

View File

@ -1,13 +1,15 @@
use crate::color::Rgb; use crate::color::Rgb;
use crate::errors::ProgramError;
use crate::pattern::{self, Pattern}; use crate::pattern::{self, Pattern};
use crate::strip; use crate::strip;
use std::io; use std::io;
use std::io::Write; use std::io::Write;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
pub fn console_ui_loop(tx: &Sender<strip::Message>) { pub fn console_ui_loop(tx: &Sender<strip::Message>) -> Result<(), ProgramError> {
loop { loop {
if let Err(msg) = parse_cmd(tx, &get_line("Command (cfqs)")) { let line = get_line("Command (cfqs)")?;
if let Err(msg) = parse_cmd(tx, &line) {
println!("Command error: {}", msg); println!("Command error: {}", msg);
} }
} }
@ -105,12 +107,14 @@ fn change_pattern(tx: &Sender<strip::Message>, pat: Box<dyn Pattern + Send>) ->
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
} }
fn get_line(prompt: &str) -> String { fn get_line(prompt: &str) -> Result<String, ProgramError> {
print!("{}: ", prompt); print!("{}: ", prompt);
std::io::stdout().flush().expect("Could not flush stdout"); std::io::stdout()
.flush()
.map_err(|_| ProgramError::UiError(String::from("Could not flush stdout")))?;
let mut input_text = String::new(); let mut input_text = String::new();
io::stdin() io::stdin()
.read_line(&mut input_text) .read_line(&mut input_text)
.expect("Could not read from stdin"); .map_err(|_| ProgramError::UiError(String::from("Could not read from stdin")))?;
input_text.trim().to_string() Ok(input_text.trim().to_string())
} }