ht16k33-async 0.0.2

An async driver for the Holtek HT16K33 "RAM Mapping 16*8 LED Controller Driver with keyscan"
Documentation
use crate::hal::i2c::{self, Operation};

/// The HT16K33 state and configuration.
pub struct HT16K33<I2C> {
    i2c: I2C,

    // Device I2C address.
    address: u8,

    // These registers are write-only but control multiple states
    // so we must store them to be able to change values independently
    display: DisplaySetup,
}

enum RowIntStatus {
    Row,
    IntActiveLow,
    IntActiveHigh,
}

impl Into<u8> for RowIntStatus {
    fn into(self) -> u8 {
        let base = 0b10100000;
        base | match self {
            RowIntStatus::Row => 0b00,
            RowIntStatus::IntActiveLow => 0b01,
            RowIntStatus::IntActiveHigh => 0b11,
        }
    }
}

#[derive(Clone, Copy)]
struct DisplaySetup {
    on_off: DisplayOnOff,
    blinking: DisplayBlink,
}

impl Into<u8> for DisplaySetup {
    fn into(self) -> u8 {
        let byte = 0b10000000;
        let byte = byte | match self.on_off {
            DisplayOnOff::Off => 0,
            DisplayOnOff::On => 1,
        };
        byte | match self.blinking {
            DisplayBlink::Off => 0b000,
            DisplayBlink::TwoHz => 0b010,
            DisplayBlink::OneHz => 0b100,
            DisplayBlink::HalfHz => 0b110,
        }
    }
}

#[derive(Clone, Copy)]
pub enum DisplayOnOff {On, Off}
#[derive(Clone, Copy)]
pub enum DisplayBlink {Off, TwoHz, OneHz, HalfHz}

impl Default for DisplaySetup {
    fn default() -> Self {
        Self { on_off: DisplayOnOff::On, blinking: DisplayBlink::Off }
    }
}

impl <I2C, E> HT16K33<I2C>
where
    I2C: i2c::I2c<Error = E>,
{
    /// Create a new HT16K33 instance on the provided I2C bus at the provided address.
    pub fn new(i2c: I2C, address: u8) -> Self {
        // TODO: ensure address is within allowed range for the IC
        Self {i2c, address, display: DisplaySetup::default()}
    }

    /// Initialize the IC with default values
    ///
    /// - Enable the internal oscillator
    /// - Set ROW/INT register to row mode
    /// - Turn display on, with no blinking
    pub async fn setup(&mut self) -> Result<(), E> {
        self.enable_oscillator().await?;
        self.set_row_int(RowIntStatus::Row).await?;
        self.set_display_setup().await
    }

    /// Write row values for one of the common LED register
    pub async fn write_to_common(&mut self, common_id: u8, pin_states: &[u8; 2]) -> Result<(), E> {
        let ram_address = (common_id << 1) & 0b00001110;
        self.i2c.write(self.address, &[ram_address, pin_states[0], pin_states[1]]).await
    }

    /// Write row values for multiple commons, starting at common 0
    pub async fn write_whole_display(&mut self, pin_states: &[u8]) -> Result<(), E> {
        let ram_address = 0b00000000;
        self.i2c.transaction(self.address, &mut [Operation::Write(&[ram_address]), Operation::Write(pin_states)]).await
    }

    async fn enable_oscillator(&mut self) -> Result<(), E> {
        self.i2c.write(self.address, &[0b00100001]).await
    }

    async fn set_row_int(&mut self, row_int: RowIntStatus) -> Result<(), E> {
        self.i2c.write(self.address, &[row_int.into()]).await
    }

    async fn set_display_setup(&mut self) -> Result<(), E> {
        self.i2c.write(self.address, &[self.display.into()]).await
    }

    /// Turn the display on or off
    pub async fn set_display_on_off(&mut self, status: DisplayOnOff) -> Result<(), E> {
        self.display.on_off = status;
        self.set_display_setup().await
    }

    /// Set display blinking mode
    pub async fn set_display_blink(&mut self, status: DisplayBlink) -> Result<(), E> {
        self.display.blinking = status;
        self.set_display_setup().await
    }

    /// Read key data
    ///
    /// Be aware that inputs accumulate and only reset when they are read from the IC.
    /// You should pass a buffer with all the keys that you wish to read every time.
    ///
    /// Key bits are as follows:
    ///
    /// | KS# | D7 | D6 | D5 | D4  | D3  | D2  | D1  | D0 |
    /// |-----|----|----|----|-----|-----|-----|-----|----|
    /// | KS1 | K8 | K7 | K6 | K5  | K4  | K3  | K2  | K1 |
    /// | KS1 |    |    |    | K13 | K12 | K11 | K10 | K9 |
    /// | KS2 | K8 | K7 | K6 | K5  | K4  | K3  | K2  | K1 |
    /// | KS2 |    |    |    | K13 | K12 | K11 | K10 | K9 |
    /// | KS3 | K8 | K7 | K6 | K5  | K4  | K3  | K2  | K1 |
    /// | KS3 |    |    |    | K13 | K12 | K11 | K10 | K9 |
    pub async fn read_keys(&mut self, keys: &mut [u8]) -> Result<(), E> {
        self.i2c.write_read(self.address, &[0x40], keys).await
    }
}