#![no_std]
use arbitrary_int::{u4, u6};
use derive_setters::Setters;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
mod bus;
pub use bus::Ht1621bBus;
pub mod cmd {
pub const SYS_DIS: u8 = 0x00; pub const SYS_EN: u8 = 0x01; pub const LCD_OFF: u8 = 0x02; pub const LCD_ON: u8 = 0x03;
pub const TIMER_DIS: u8 = 0x04; pub const WDT_DIS: u8 = 0x05; pub const TIMER_EN: u8 = 0x06; pub const WDT_EN: u8 = 0x07;
pub const TONE_OFF: u8 = 0x08; pub const TONE_ON: u8 = 0x09;
pub const CLR_TIMER: u8 = 0x0C; pub const CLR_WDT: u8 = 0x0E;
pub const XTAL_32K: u8 = 0x14; pub const RC_256K: u8 = 0x18; pub const EXT_256K: u8 = 0x1C;
pub const BIAS_1_2_2COM: u8 = 0x20; pub const BIAS_1_2_3COM: u8 = 0x24; pub const BIAS_1_2_4COM: u8 = 0x28; pub const BIAS_1_3_2COM: u8 = 0x21; pub const BIAS_1_3_3COM: u8 = 0x25; pub const BIAS_1_3_4COM: u8 = 0x29;
pub const TONE_4K: u8 = 0x40; pub const TONE_2K: u8 = 0x60;
pub const IRQ_DIS: u8 = 0x80; pub const IRQ_EN: u8 = 0x88;
pub const F1: u8 = 0xA0; pub const F2: u8 = 0xA1; pub const F4: u8 = 0xA2; pub const F8: u8 = 0xA3; pub const F16: u8 = 0xA4; pub const F32: u8 = 0xA5; pub const F64: u8 = 0xA6; pub const F128: u8 = 0xA7;
pub const TEST: u8 = 0xE0; pub const NORMAL: u8 = 0xE3; }
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Bias {
Half,
Third,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Commons {
Two,
Three,
Four,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ClockSource {
Rc256k,
Xtal32k,
Ext256k,
}
impl ClockSource {
#[inline]
fn command(self) -> u8 {
match self {
ClockSource::Rc256k => cmd::RC_256K,
ClockSource::Xtal32k => cmd::XTAL_32K,
ClockSource::Ext256k => cmd::EXT_256K,
}
}
#[inline]
fn stabilize_ms(self) -> u32 {
match self {
ClockSource::Rc256k => 2,
ClockSource::Ext256k => 2,
ClockSource::Xtal32k => 50,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ToneFreq {
Khz4,
Khz2,
}
impl ToneFreq {
#[inline]
fn command(self) -> u8 {
match self {
ToneFreq::Khz4 => cmd::TONE_4K,
ToneFreq::Khz2 => cmd::TONE_2K,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TimerFreq {
F1,
F2,
F4,
F8,
F16,
F32,
F64,
F128,
}
impl TimerFreq {
#[inline]
fn command(self) -> u8 {
match self {
TimerFreq::F1 => cmd::F1,
TimerFreq::F2 => cmd::F2,
TimerFreq::F4 => cmd::F4,
TimerFreq::F8 => cmd::F8,
TimerFreq::F16 => cmd::F16,
TimerFreq::F32 => cmd::F32,
TimerFreq::F64 => cmd::F64,
TimerFreq::F128 => cmd::F128,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TimerMode {
Off,
TimeBase(TimerFreq),
Watchdog(TimerFreq),
}
#[derive(Clone, Copy, Setters)]
pub struct Config {
pub bias: Bias,
pub commons: Commons,
pub clock: ClockSource,
}
impl Default for Config {
fn default() -> Self {
Self {
bias: Bias::Third,
commons: Commons::Four,
clock: ClockSource::Rc256k,
}
}
}
impl Config {
#[inline]
fn bias_command(self) -> u8 {
match (self.bias, self.commons) {
(Bias::Half, Commons::Two) => cmd::BIAS_1_2_2COM,
(Bias::Half, Commons::Three) => cmd::BIAS_1_2_3COM,
(Bias::Half, Commons::Four) => cmd::BIAS_1_2_4COM,
(Bias::Third, Commons::Two) => cmd::BIAS_1_3_2COM,
(Bias::Third, Commons::Three) => cmd::BIAS_1_3_3COM,
(Bias::Third, Commons::Four) => cmd::BIAS_1_3_4COM,
}
}
}
pub struct Ht1621b<CS, WR, DA, D> {
bus: Ht1621bBus<CS, WR, DA, D>,
}
impl<CS, WR, DA, D> Ht1621b<CS, WR, DA, D>
where
CS: OutputPin,
WR: OutputPin,
DA: OutputPin,
D: DelayNs,
{
pub async fn new<AD>(
cs: CS,
wr: WR,
da: DA,
delay: D,
async_delay: &mut AD,
config: Config,
) -> Self
where
AD: embedded_hal_async::delay::DelayNs,
{
let bus = Ht1621bBus::new(cs, wr, da, delay);
let mut this = Self { bus };
async_delay.delay_ms(1).await;
this.bus.write_command(config.bias_command());
this.bus.write_command(config.clock.command());
this.bus.write_command(cmd::SYS_DIS);
this.bus.write_command(cmd::SYS_EN);
async_delay.delay_ms(config.clock.stabilize_ms()).await;
this.clear();
this.bus.write_command(cmd::LCD_ON);
this
}
#[inline]
pub fn clear(&mut self) {
self.bus.write_bytes(u6::new(0), &[0u8; 16]);
}
#[inline]
pub fn set_config(&mut self, config: Config) {
self.bus.write_command(config.bias_command());
self.bus.write_command(config.clock.command());
}
#[inline]
pub fn lcd_on(&mut self) {
self.bus.write_command(cmd::LCD_ON);
}
#[inline]
pub fn lcd_off(&mut self) {
self.bus.write_command(cmd::LCD_OFF);
}
#[inline]
pub fn sleep(&mut self) {
self.bus.write_command(cmd::LCD_OFF);
self.bus.write_command(cmd::SYS_DIS);
}
#[inline]
pub fn wake(&mut self) {
self.bus.write_command(cmd::SYS_EN);
self.bus.write_command(cmd::LCD_ON);
}
#[inline]
pub fn tone_on(&mut self, freq: ToneFreq) {
self.bus.write_command(freq.command());
self.bus.write_command(cmd::TONE_ON);
}
#[inline]
pub fn tone_off(&mut self) {
self.bus.write_command(cmd::TONE_OFF);
}
pub fn set_timer_mode(&mut self, mode: TimerMode) {
match mode {
TimerMode::Off => {
self.bus.write_command(cmd::TIMER_DIS);
self.bus.write_command(cmd::WDT_DIS);
self.bus.write_command(cmd::IRQ_DIS);
}
TimerMode::TimeBase(freq) => {
self.bus.write_command(cmd::WDT_DIS);
self.bus.write_command(freq.command());
self.bus.write_command(cmd::CLR_TIMER);
self.bus.write_command(cmd::TIMER_EN);
self.bus.write_command(cmd::IRQ_EN);
}
TimerMode::Watchdog(freq) => {
self.bus.write_command(cmd::TIMER_DIS);
self.bus.write_command(freq.command());
self.bus.write_command(cmd::CLR_WDT);
self.bus.write_command(cmd::WDT_EN);
self.bus.write_command(cmd::IRQ_EN);
}
}
}
#[inline]
pub fn wdt_feed(&mut self) {
self.bus.write_command(cmd::CLR_WDT);
}
#[inline]
pub fn timer_clear(&mut self) {
self.bus.write_command(cmd::CLR_TIMER);
}
#[inline]
pub fn bus(&mut self) -> &mut Ht1621bBus<CS, WR, DA, D> {
&mut self.bus
}
#[inline]
pub fn write_words(&mut self, addr: u6, words: &[u4]) {
self.bus.write_words(addr, words);
}
#[inline]
pub fn write_word(&mut self, addr: u6, word: u4) {
self.bus.write_word(addr, word);
}
#[inline]
pub fn write_bytes(&mut self, addr: u6, data: &[u8]) {
self.bus.write_bytes(addr, data);
}
#[inline]
pub fn write_byte(&mut self, addr: u6, data: u8) {
self.bus.write_byte(addr, data);
}
}