st7305-lcd 0.3.0

Platform-independent no_std driver for the Sitronix ST7305 and ST7306 reflective LCD controllers (embedded-hal 1.0, blocking and async)
Documentation
//! Commands that program the NVM (MTP) of the panel or change its identity.
//!
//! Only available with the `nvm-program` feature. The ST7305 datasheet v0.2
//! (§6.5, §8.2.26–8.2.29, §9) requires an external programming supply VPP of
//! about 7.5 V (> 8 mA) and the EXTB pin pulled to VDGND; without them the
//! commands have no effect.

use crate::{command::WriteCommand, instr::Instr};

/// `NVMCTRL2` (§8.2.27): NVM register address and data to program.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NvmProgramSetting {
    /// `PA[5:0]`: register address
    pa: u8,
    /// `PIN[7:0]`: data
    pin: u8,
}

impl NvmProgramSetting {
    /// Register default: address 0, data 0.
    pub const DEFAULT: Self = Self { pa: 0, pin: 0 };

    /// Programs `pin` at the NVM address `pa` (6 bits).
    ///
    /// # Panics
    ///
    /// If `pa > 63` (at compile time in a `const`).
    pub const fn new(pa: u8, pin: u8) -> Self {
        assert!(pa >> 6 == 0, "PA out of range");
        Self { pa, pin }
    }

    const fn bytes(&self) -> [u8; 2] {
        [self.pa, self.pin]
    }
}

impl Default for NvmProgramSetting {
    fn default() -> Self {
        Self::DEFAULT
    }
}

impl WriteCommand for NvmProgramSetting {
    const OPCODE: Instr = Instr::NVMCTRL2;
    type Params = [u8; 2];
    fn params(&self) -> Self::Params {
        self.bytes()
    }
}

const _: () = assert!(matches!(NvmProgramSetting::DEFAULT.bytes(), [0x00, 0x00]));

/// `NVMPROM` (§8.2.29): enables NVM program mode (sends the key `29h A5h`).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NvmProgramEnable;

impl NvmProgramEnable {
    const fn bytes(&self) -> [u8; 2] {
        [0x29, 0xA5]
    }
}

impl WriteCommand for NvmProgramEnable {
    const OPCODE: Instr = Instr::NVMPROM;
    type Params = [u8; 2];
    fn params(&self) -> Self::Params {
        self.bytes()
    }
}

const _: () = assert!(matches!(NvmProgramEnable.bytes(), [0x29, 0xA5]));

/// `ID1SET` (§8.2.17): the ID1 code, read back with `RDID1`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Id1Setting {
    id: u8,
}

impl Id1Setting {
    /// Register default `0x00`.
    pub const DEFAULT: Self = Self { id: 0 };

    /// ID1 = `id`.
    pub const fn new(id: u8) -> Self {
        Self { id }
    }
}

impl Default for Id1Setting {
    fn default() -> Self {
        Self::DEFAULT
    }
}

impl WriteCommand for Id1Setting {
    const OPCODE: Instr = Instr::ID1SET;
    type Params = [u8; 1];
    fn params(&self) -> Self::Params {
        [self.id]
    }
}

/// `ID2SET` (§8.2.18): the ID2 code, read back with `RDID2`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Id2Setting {
    id: u8,
}

impl Id2Setting {
    /// Register default `0x00`.
    pub const DEFAULT: Self = Self { id: 0 };

    /// ID2 = `id`.
    pub const fn new(id: u8) -> Self {
        Self { id }
    }
}

impl Default for Id2Setting {
    fn default() -> Self {
        Self::DEFAULT
    }
}

impl WriteCommand for Id2Setting {
    const OPCODE: Instr = Instr::ID2SET;
    type Params = [u8; 1];
    fn params(&self) -> Self::Params {
        [self.id]
    }
}

/// `ID3SET` (§8.2.19): the ID3 code, read back with `RDID3`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Id3Setting {
    id: u8,
}

impl Id3Setting {
    /// Register default `0x00`.
    pub const DEFAULT: Self = Self { id: 0 };

    /// ID3 = `id`.
    pub const fn new(id: u8) -> Self {
        Self { id }
    }
}

impl Default for Id3Setting {
    fn default() -> Self {
        Self::DEFAULT
    }
}

impl WriteCommand for Id3Setting {
    const OPCODE: Instr = Instr::ID3SET;
    type Params = [u8; 1];
    fn params(&self) -> Self::Params {
        [self.id]
    }
}

/// `EXTBCTRL` (§8.2.25): internal level of the EXTB signal.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ExtbControl {
    extb_ctrl: ExtbCtrl,
}

impl ExtbControl {
    /// Register default `0x5A`: EXTB high.
    pub const DEFAULT: Self = Self {
        extb_ctrl: ExtbCtrl::Vdd,
    };

    /// `EXTB_CTRL[7:0]` = `extb_ctrl`.
    pub const fn new(extb_ctrl: ExtbCtrl) -> Self {
        Self { extb_ctrl }
    }

    const fn bytes(&self) -> [u8; 1] {
        [self.extb_ctrl as u8]
    }
}

impl Default for ExtbControl {
    fn default() -> Self {
        Self::DEFAULT
    }
}

impl WriteCommand for ExtbControl {
    const OPCODE: Instr = Instr::EXTBCTRL;
    type Params = [u8; 1];
    fn params(&self) -> Self::Params {
        self.bytes()
    }
}

/// `EXTB_CTRL[7:0]`: EXTB level.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ExtbCtrl {
    /// EXTB high (VDD)
    Vdd = 0x5A,
    /// EXTB low (VSS)
    Vss = 0xA5,
}

const _: () = assert!(matches!(ExtbControl::DEFAULT.bytes(), [0x5A]));