#![no_std]
#![deny(warnings, missing_docs)]
mod fonts;
use fonts::*;
use embedded_hal::blocking::i2c::{Write, WriteRead};
use ht16k33::{
DisplayDataAddress,
DisplayData,
LedLocation,
HT16K33,
COMMONS_SIZE,
};
pub use ascii::AsciiChar;
#[derive(Debug)]
pub enum Error {
InsufficientDigits,
}
pub trait AlphaNum4<E> {
fn update_buffer_with_digit(&mut self, index: Index, value: u8);
fn update_buffer_with_dot(&mut self, index: Index, dot_on: bool);
fn update_buffer_with_char(&mut self, index: Index, value: AsciiChar);
fn update_buffer_with_float(&mut self, index: Index, value: f32, fractional_digits: u8, base: u8) -> Result<(), Error>;
}
#[derive(Clone, Copy, PartialEq)]
pub enum Index {
One,
Two,
Three,
Four,
}
impl From<Index> for u8 {
fn from(i: Index) -> u8 {
match i {
Index::One => 0,
Index::Two => 1,
Index::Three => 2,
Index::Four => 3,
}
}
}
impl From<u8> for Index {
fn from(v: u8) -> Index {
match v {
0 => Index::One,
1 => Index::Two,
2 => Index::Three,
3 => Index::Four,
_ => panic!("Invalid index > 3"),
}
}
}
fn set_bit<I2C, E>(display: &mut HT16K33<I2C>, index: Index, bit: u8, on: bool)
where
I2C:
Write<Error = E> +
WriteRead<Error = E> +
{
debug_assert!((bit as usize) < (COMMONS_SIZE * 2));
let index = u8::from(index) * 2;
let row = DisplayDataAddress::from_bits_truncate(if bit < 8 {
index
} else {
index + 1
});
let common = DisplayData::from_bits_truncate(1 << (bit % 8));
display.update_display_buffer(
LedLocation { row, common },
on,
);
}
fn update_bits<I2C, E>(display: &mut HT16K33<I2C>, index: Index, bits: u16)
where
I2C:
Write<Error = E> +
WriteRead<Error = E> +
{
for i in 0..16 {
let on = ((bits >> i) & 1) == 1;
set_bit(display, index, i, on);
}
}
impl<I2C, E> AlphaNum4<E> for HT16K33<I2C>
where
I2C:
Write<Error = E> +
WriteRead<Error = E> +
{
fn update_buffer_with_digit(&mut self, index: Index, value: u8) {
let value = value as usize;
assert!(value < NUMBER_FONT_TABLE.len());
let bits = NUMBER_FONT_TABLE[value];
update_bits(self, index, bits);
}
fn update_buffer_with_dot(&mut self, index: Index, dot_on: bool) {
set_bit(self, index, DOT_BIT, dot_on);
}
fn update_buffer_with_char(&mut self, index: Index, value: AsciiChar) {
let bits = ASCII_FONT_TABLE[value.as_byte() as usize];
update_bits(self, index, bits);
}
fn update_buffer_with_float(&mut self, index: Index, mut value: f32, mut fractional_digits: u8, base: u8) -> Result<(), Error> {
let index = u8::from(index);
let mut numeric_digits = 4 - index;
let is_negative = if value < 0. {
numeric_digits -= 1;
value *= -1.;
true
} else {
false
};
let base = base as u32;
let basef = base as f32;
let mut to_int_factor = base.pow(fractional_digits as u32) as f32;
let mut display_number = ((value * to_int_factor) + 0.5) as u32;
let too_big = base.pow(numeric_digits as u32);
while display_number >= too_big {
fractional_digits -= 1;
to_int_factor /= basef;
display_number = ((value * to_int_factor) + 0.5) as u32;
}
if to_int_factor < 1. {
return Err(Error::InsufficientDigits)
}
let mut display_pos = (3 - index) as i8;
if display_number == 0 {
self.update_buffer_with_digit(
(index + (display_pos as u8)).into(),
0,
);
display_pos -= 1;
} else {
let mut i = 0;
while display_number != 0 || i <= fractional_digits {
let digit_index = (index + (display_pos as u8)).into();
self.update_buffer_with_digit(
digit_index,
(display_number % base) as u8,
);
if fractional_digits != 0 && i == fractional_digits {
self.update_buffer_with_dot(
digit_index,
true,
);
}
display_pos -= 1;
display_number /= base;
i += 1;
}
}
if is_negative {
self.update_buffer_with_char(
(index + (display_pos as u8)).into(),
AsciiChar::new('-'),
);
display_pos -= 1;
}
while display_pos >= 0 {
update_bits(self, (index + (display_pos as u8)).into(), 0);
display_pos -= 1;
}
Ok(())
}
}