use std::fmt;
use std::thread;
use std::time::Duration;
use core::fmt::Debug;
use rppal::gpio::{Gpio, OutputPin, Level};
pub const GPIO_DAT: u8 = 10;
pub const GPIO_CLK: u8 = 11;
pub const GPIO_CS: u8 = 8;
pub const NUM_PIXELS: usize = 7;
pub const BRIGHTNESS: u8 = 7;
pub const SLEEP_TIME : u64 = 0;
#[derive(Debug)]
pub struct APA102 {
pin_dat: Option<Box<OutputPin>>,
pin_clk: Option<Box<OutputPin>>,
pin_cs: Option<Box<OutputPin>>,
pub pixels: [[u8;4] ; NUM_PIXELS],
brightness: u8,
simulation: bool,
is_setup: bool,
}
impl APA102 {
pub fn new() -> Result<APA102, Error> {
Ok(Self {
pin_dat: None,
pin_clk: None,
pin_cs: None,
pixels:[[0; 4]; NUM_PIXELS],
brightness: BRIGHTNESS,
simulation: false,
is_setup: false,
})
}
pub fn setup(&mut self) -> Result <(), Error> {
if !self.is_setup {
if !self.simulation {
let gpio_dat = Gpio::new()?;
let output_dat = gpio_dat.get(GPIO_DAT)?.into_output();
self.pin_dat = Some(Box::new(output_dat));
let gpio_clk = Gpio::new()?;
let output_clk = gpio_clk.get(GPIO_CLK)?.into_output();
self.pin_clk = Some(Box::new(output_clk));
let gpio_cs = Gpio::new()?;
let output_cs = gpio_cs.get(GPIO_CS)?.into_output();
self.pin_cs = Some(Box::new(output_cs));
}
self.is_setup = true;
}
Ok(())
}
pub fn exit(&mut self) -> Result <(), Error> {
self.clear();
self.show()?;
Ok(())
}
pub fn set_brightness(&mut self, brightness : f32) {
assert!(brightness >= 0.0);
assert!(brightness <= 1.0);
for i in 0..self.pixels.len() {
self.pixels[i][3] = (31.0 * brightness.round()) as u8;
}
}
pub fn clear(&mut self) {
for i in 0..self.pixels.len() {
self.pixels[i][0] = 0 as u8; self.pixels[i][1] = 0 as u8; self.pixels[i][2] = 0 as u8; }
}
fn write_byte (&mut self, byte : u8) {
if !self.simulation {
let output_dat = self.pin_dat.as_deref_mut().unwrap();
let output_clk = self.pin_clk.as_deref_mut().unwrap();
for i in 0..8 {
if APA102::get_bit_at(byte, 7 - i) {
output_dat.write(Level::High);
} else {
output_dat.write(Level::Low);
}
output_clk.write(Level::High);
thread::sleep(Duration::from_millis(SLEEP_TIME));
output_clk.write(Level::Low);
thread::sleep(Duration::from_millis(SLEEP_TIME));
}
}
}
fn eof(&mut self) {
if !self.simulation {
let output_dat = self.pin_dat.as_deref_mut().unwrap();
let output_clk = self.pin_clk.as_deref_mut().unwrap();
output_dat.write(Level::Low);
for _x in 0..36 {
output_clk.write(Level::High);
thread::sleep(Duration::from_millis(SLEEP_TIME));
output_clk.write(Level::Low);
thread::sleep(Duration::from_millis(SLEEP_TIME));
}
}
}
fn sof(&mut self) {
if !self.simulation {
let output_dat = self.pin_dat.as_deref_mut().unwrap();
let output_clk = self.pin_clk.as_deref_mut().unwrap();
output_dat.write(Level::Low);
for _x in 0..32 {
output_clk.write(Level::High);
thread::sleep(Duration::from_millis(SLEEP_TIME));
output_clk.write(Level::Low);
thread::sleep(Duration::from_millis(SLEEP_TIME));
}
}
}
pub fn show(&mut self) -> Result <(), Error>{
if !self.is_setup {
let _result = self.setup();
}
if !self.simulation {
let output_cs = self.pin_cs.as_deref_mut().unwrap();
output_cs.write(Level::Low);
self.sof();
for i in 0..self.pixels.len() {
self.write_byte(0b11100000 | self.pixels[i][3]); self.write_byte(self.pixels[i][2]); self.write_byte(self.pixels[i][1]); self.write_byte(self.pixels[i][0]); }
self.eof();
let output_cs = self.pin_cs.as_deref_mut().unwrap();
output_cs.write(Level::High);
}
Ok(())
}
pub fn set_all(&mut self, r : u8, g: u8, b: u8, brightness: f32) {
for i in 0..self.pixels.len() {
self.set_pixel(i, r, g, b, brightness);
}
}
pub fn set_pixel(&mut self, x: usize, r : u8, g: u8, b: u8, brightness: f32) {
assert!(brightness >= 0.0);
assert!(brightness <= 1.0);
self.pixels[x][0] = r as u8; self.pixels[x][1] = g as u8; self.pixels[x][2] = b as u8; self.pixels[x][3] = (31.0 * brightness.round()) as u8; }
fn get_bit_at(byte: u8, n: u8) -> bool {
assert!(n < 8);
byte & (1 << n) != 0
}
}
#[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_apa102_setup() -> Result<(), Error> {
let mut apa102 = APA102::new()?;
apa102.simulation = true;
assert!(apa102.is_setup == false);
let _result = apa102.setup();
assert!(apa102.is_setup == true);
Ok(())
}
#[test]
fn test_apa102_set_brightness() -> Result<(), Error> {
let mut apa102 = APA102::new()?;
apa102.simulation = true;
let _result = apa102.setup();
apa102.set_brightness(0.0);
for i in 0..apa102.pixels.len() {
assert!(apa102.pixels[i][3] == 0);
}
apa102.set_brightness(1.0);
for i in 0..apa102.pixels.len() {
assert!(apa102.pixels[i][3] == 31);
}
Ok(())
}
#[test]
fn test_apa102_clear() -> Result<(), Error> {
let mut apa102 = APA102::new()?;
apa102.simulation = true;
let _result = apa102.setup();
let brightness : u8 = 31;
for i in 0..apa102.pixels.len() {
apa102.pixels[i][0] = 250 as u8; apa102.pixels[i][1] = 250 as u8; apa102.pixels[i][2] = 250 as u8; apa102.pixels[i][3] = brightness;
}
apa102.clear();
for i in 0..apa102.pixels.len() {
assert!(apa102.pixels[i][0] == 0);
assert!(apa102.pixels[i][1] == 0);
assert!(apa102.pixels[i][2] == 0);
assert!(apa102.pixels[i][3] == 31);
}
Ok(())
}
#[test]
fn test_apa102_set_pixel() -> Result<(), Error> {
let mut apa102 = APA102::new()?;
apa102.simulation = true;
let _result = apa102.setup();
apa102.set_pixel(0, 123, 234, 012, 1.0);
apa102.set_pixel(6, 12, 58, 123, 0.0);
assert!(apa102.pixels[0][0] == 123);
assert!(apa102.pixels[0][1] == 234);
assert!(apa102.pixels[0][2] == 12);
assert!(apa102.pixels[0][3] == 31);
assert!(apa102.pixels[6][0] == 12);
assert!(apa102.pixels[6][1] == 58);
assert!(apa102.pixels[6][2] == 123);
assert!(apa102.pixels[6][3] == 0);
Ok(())
}
#[test]
fn test_apa102_set_all() -> Result<(), Error> {
let mut apa102 = APA102::new()?;
apa102.simulation = true;
let _result = apa102.setup();
apa102.set_all(123, 234, 012, 1.0);
for i in 0..apa102.pixels.len() {
assert!(apa102.pixels[i][0] == 123);
assert!(apa102.pixels[i][1] == 234);
assert!(apa102.pixels[i][2] == 12);
assert!(apa102.pixels[i][3] == 31);
}
Ok(())
}
#[test]
fn test_apa102_get_bit_at() -> Result<(), Error> {
let value = 0b00010101 as u8;
assert!(APA102::get_bit_at(value, 0) == true);
assert!(APA102::get_bit_at(value, 1) == false);
assert!(APA102::get_bit_at(value, 2) == true);
assert!(APA102::get_bit_at(value, 3) == false);
assert!(APA102::get_bit_at(value, 4) == true);
assert!(APA102::get_bit_at(value, 5) == false);
assert!(APA102::get_bit_at(value, 6) == false);
assert!(APA102::get_bit_at(value, 7) == false);
Ok(())
}
}