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: I2c,
pub buffer: [u8; 8],
blink_frequency: u8,
brightness: u8,
is_setup: bool
}
impl HT16K33 {
pub fn new() -> Result<HT16K33, Error> {
let i2c = I2c::new()?;
Ok(Self {
i2c_address: DEFAULT_ADDRESS,
i2c,
buffer:[0; 8],
blink_frequency: HT16K33_BLINK_OFF,
brightness: 15 as u8,
is_setup: false,
})
}
fn begin(&mut self) -> Result <(), Error> {
self.i2c.set_slave_address(self.i2c_address)?;
self.i2c.block_write(
(HT16K33_SYSTEM_SETUP | HT16K33_OSCILLATOR) as u8, &[]
)?;
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 {
self.begin()?;
}
self.i2c.block_write(
0x00 as u8, &self.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)
}
}