use std::fmt;
use core::fmt::Debug;
use rppal::gpio::{Gpio, OutputPin, Level};
pub const GPIO_LIGHT_RED: u8 = 6;
pub const GPIO_LIGHT_GREEN: u8 = 19;
pub const GPIO_LIGHT_BLUE: u8 = 26;
#[derive(Debug)]
pub struct Light {
pub bcm_pin: u8,
pin: Option<Box<OutputPin>>,
pub state: bool,
simulation: bool,
is_setup: bool,
}
impl Light {
pub fn new(bcm_pin: u8) -> Result<Light, Error> {
Ok(Self {
bcm_pin,
pin: None,
state: false,
simulation: false,
is_setup: false,
})
}
pub fn setup(&mut self) -> Result <(), Error> {
if !self.is_setup {
if !self.simulation {
let gpio = Gpio::new()?;
let output = gpio.get(self.bcm_pin)?.into_output();
self.pin = Some(Box::new(output));
}
self.is_setup = true;
}
Ok(())
}
pub fn on(&mut self) {
self.write(true);
}
pub fn off(&mut self) {
self.write(false);
}
pub fn toggle(&mut self) {
self.write(!self.state);
}
pub fn write(&mut self, state: bool) {
self.state = state;
if !self.is_setup {
let _result = self.setup();
}
if !self.simulation {
let pin = self.pin.as_deref_mut().unwrap();
if state {
pin.write(Level::High);
} else {
pin.write(Level::Low);
}
}
}
}
pub struct Lights {
pub red : Light,
pub green: Light,
pub blue: Light,
}
impl Lights {
pub fn new() -> Result<Lights, Error> {
Ok(Self {
red: Light::new(GPIO_LIGHT_RED)?,
green: Light::new(GPIO_LIGHT_GREEN)?,
blue: Light::new(GPIO_LIGHT_BLUE)?,
})
}
pub fn all(&mut self, state: bool) {
self.red.write(state);
self.green.write(state);
self.blue.write(state);
}
pub fn rgb(&mut self, r: bool, g: bool, b: bool) {
self.red.write(r);
self.green.write(g);
self.blue.write(b);
}
pub fn enable_simulation(&mut self) {
self.red.simulation = true;
self.green.simulation = true;
self.blue.simulation = true;
}
}
#[derive(Debug)]
pub enum Error {
Gpio(rppal::gpio::Error),
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self {
Error::Gpio(err) => write!(f, "Gpio error: {}", &err),
}
}
}
impl From<rppal::gpio::Error> for Error {
fn from(err: rppal::gpio::Error) -> Error {
Error::Gpio(err)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_light_setup() -> Result<(), Error> {
let mut light = Light::new(GPIO_LIGHT_RED)?;
light.simulation = true;
assert!(light.is_setup == false);
let _result = light.setup();
assert!(light.is_setup == true);
Ok(())
}
#[test]
fn test_light_on() -> Result<(), Error> {
let mut light = Light::new(GPIO_LIGHT_RED)?;
light.simulation = true;
assert!(light.state == false);
light.on();
assert!(light.state == true);
Ok(())
}
#[test]
fn test_light_off() -> Result<(), Error> {
let mut light = Light::new(GPIO_LIGHT_RED)?;
light.simulation = true;
light.state = true;
light.off();
assert!(light.state == false);
Ok(())
}
#[test]
fn test_light_toggle() -> Result<(), Error> {
let mut light = Light::new(GPIO_LIGHT_RED)?;
light.simulation = true;
light.toggle();
assert!(light.state == true);
light.toggle();
assert!(light.state == false);
Ok(())
}
#[test]
fn test_lights_rgb() -> Result<(), Error> {
let mut lights = Lights::new()?;
lights.enable_simulation();
let bool_array: [bool; 2] = [true, false];
for red_state in &bool_array {
for green_state in &bool_array {
for blue_state in &bool_array {
lights.rgb(*red_state, *green_state, *blue_state);
assert!(lights.red.state == *red_state);
assert!(lights.green.state == *green_state);
assert!(lights.blue.state == *blue_state);
}
}
}
Ok(())
}
#[test]
fn test_lights_all() -> Result<(), Error> {
let mut lights = Lights::new()?;
lights.enable_simulation();
lights.all(true);
assert!(lights.red.state == true);
assert!(lights.green.state == true);
assert!(lights.blue.state == true);
lights.all(false);
assert!(lights.red.state == false);
assert!(lights.green.state == false);
assert!(lights.blue.state == false);
Ok(())
}
#[test]
fn test_lights_enable_simulation() -> Result<(), Error> {
let mut lights = Lights::new()?;
assert!(!lights.red.simulation);
assert!(!lights.green.simulation);
assert!(!lights.blue.simulation);
lights.enable_simulation();
assert!(lights.red.simulation);
assert!(lights.green.simulation);
assert!(lights.blue.simulation);
Ok(())
}
}