use std::error;
use std::fmt;
use rppal::i2c::I2c;
pub const DEFAULT_ADDRESS: u16 = 0x70;
pub const HT16K33_BLINK_CMD: u8 = 0x80;
pub const HT16K33_BLINK_DISPLAYON: u8 = 0x01;
pub const HT16K33_BLINK_OFF: u8 = 0x00;
pub const HT16K33_BLINK_2HZ: u8 = 0x02;
pub const HT16K33_BLINK_1HZ: u8 = 0x04;
pub const HT16K33_BLINK_HALFHZ: u8 = 0x06;
pub const HT16K33_SYSTEM_SETUP: u8 = 0x20;
pub const HT16K33_OSCILLATOR: u8 = 0x01;
pub const HT16K33_CMD_BRIGHTNESS: u8 = 0xE0;
#[derive(Debug)]
pub struct HT16K33 {
i2c_address: u16,
i2c: Option<Box<I2c>>,
pub buffer: [u8; 8],
blink_frequency: u8,
brightness: u8,
simulation: bool,
is_setup: bool
}
impl HT16K33 {
pub fn new() -> Result<HT16K33, Error> {
Ok(Self {
i2c_address: DEFAULT_ADDRESS,
i2c: None,
buffer:[0; 8],
blink_frequency: HT16K33_BLINK_OFF,
brightness: 15 as u8,
simulation: false,
is_setup: false,
})
}
fn i2c_block_write(&mut self, command: u8, buffer: &[u8]) -> Result <(), Error> {
if !self.simulation {
let i2c = self.i2c.as_deref_mut().unwrap();
i2c.block_write(command, buffer)?;
}
Ok(())
}
fn setup(&mut self) -> Result <(), Error> {
if !self.is_setup {
if !self.simulation {
let mut i2c = I2c::new()?;
i2c.set_slave_address(self.i2c_address)?;
i2c.block_write(
(HT16K33_SYSTEM_SETUP | HT16K33_OSCILLATOR) as u8, &[]
)?;
self.i2c = Some(Box::new(i2c));
}
self.set_blink(self.blink_frequency)?;
self.set_brightness(self.brightness)?;
self.is_setup = true;
}
Ok(())
}
pub fn set_blink(&mut self, frequency: u8) -> Result <(), Error> {
self.blink_frequency = frequency;
self.i2c_block_write(
(HT16K33_BLINK_CMD | HT16K33_BLINK_DISPLAYON | frequency) as u8, &[]
)?;
Ok(())
}
pub fn set_brightness(&mut self, brightness: u8) -> Result <(), Error> {
assert!(brightness <= 15);
self.brightness = brightness;
self.i2c_block_write(
(HT16K33_CMD_BRIGHTNESS | brightness) as u8, &[]
)?;
Ok(())
}
pub fn write_display(&mut self) -> Result <(), Error> {
if !self.is_setup {
let _result = self.setup();
}
let buffer = self.buffer;
self.i2c_block_write(
0x00 as u8, &buffer
)?;
Ok(())
}
pub fn clear(&mut self) {
for i in 0..self.buffer.len() {
self.buffer[i] = 0;
}
}
}
#[derive(Debug)]
pub enum Error {
I2c(rppal::i2c::Error),
}
impl error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self {
Error::I2c(err) => write!(f, "I2C error: {}", &err),
}
}
}
impl From<rppal::i2c::Error> for Error {
fn from(err: rppal::i2c::Error) -> Error {
Error::I2c(err)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ht16k33_setup() -> Result<(), Error> {
let mut ht16k33 = HT16K33::new()?;
ht16k33.simulation = true;
assert!(ht16k33.is_setup == false);
let _result = ht16k33.setup();
assert!(ht16k33.is_setup == true);
assert!(ht16k33.blink_frequency == HT16K33_BLINK_OFF);
assert!(ht16k33.brightness == 15);
Ok(())
}
#[test]
fn test_ht16k33_set_blink() -> Result<(), Error> {
let mut ht16k33 = HT16K33::new()?;
ht16k33.simulation = true;
assert!(ht16k33.blink_frequency == HT16K33_BLINK_OFF);
let _result = ht16k33.set_blink(HT16K33_BLINK_2HZ);
assert!(ht16k33.blink_frequency == HT16K33_BLINK_2HZ);
Ok(())
}
#[test]
fn test_ht16k33_set_brightness() -> Result<(), Error> {
let mut ht16k33 = HT16K33::new()?;
ht16k33.simulation = true;
assert!(ht16k33.brightness == 15);
let _result = ht16k33.set_brightness(14);
assert!(ht16k33.brightness == 14);
Ok(())
}
}