#![no_std]
extern crate embedded_hal as hal;
use core::fmt;
use hal::blocking::delay::DelayMs;
use hal::blocking::i2c::{Read, Write, WriteRead};
pub const I2C_ADRESS: u8 = 0x3e;
#[derive(Debug, PartialEq)]
enum InstructionSet {
Normal,
Extented,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Direction {
LeftToRigh,
RightToLeft,
}
#[derive(Debug)]
pub struct ST7032i<I2C, D> {
i2c: I2C,
delay: D,
entry: Direction,
lines: u8,
scroll: bool,
display: bool,
cursor: bool,
blink: bool,
}
impl<I2C, E, D> ST7032i<I2C, D>
where
I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
D: DelayMs<u8>,
{
pub fn new(i2c: I2C, delay: D, lines: u8) -> Self {
ST7032i {
i2c,
delay,
lines,
entry: Direction::RightToLeft,
scroll: false,
display: false,
cursor: false,
blink: false,
}
}
pub fn init(&mut self) -> Result<(), E> {
match self.send_function(InstructionSet::Normal, 1, false) {
Ok(_) => self.delay.delay_ms(1),
Err(_) => self.delay.delay_ms(20),
};
self.send_function(InstructionSet::Extented, 1, false)?;
self.delay.delay_ms(5);
self.send_function(InstructionSet::Extented, 1, false)?;
self.delay.delay_ms(5);
self.send_function(InstructionSet::Extented, self.lines, false)?;
self.delay.delay_ms(5);
self.off()?;
self.send_osc_config(true, 0)?;
self.send_contrast(0)?;
self.send_booster_config(true, false, 0)?;
self.send_follower_config(true, 0)?;
self.send_entry_mode()?;
self.delay.delay_ms(20);
self.on()?;
self.clear()
}
pub fn on(&mut self) -> Result<(), E> {
self.display = true;
self.send_display_mode()
}
pub fn off(&mut self) -> Result<(), E> {
self.display = false;
self.send_display_mode()
}
pub fn clear(&mut self) -> Result<(), E> {
const CLEAR_DISPLAY: u8 = 0b_00000001;
self.send_command(CLEAR_DISPLAY)?;
self.delay.delay_ms(2);
Ok(())
}
pub fn home(&mut self) -> Result<(), E> {
const RETURN_HOME: u8 = 0b_00000010;
self.send_command(RETURN_HOME)?;
self.delay.delay_ms(2);
Ok(())
}
pub fn move_cursor(&mut self, row: u8, col: u8) -> Result<(), E> {
let command = match row {
0 => col | 0b_10000000,
_ => col | 0b_11000000,
};
self.send_command(command)
}
pub fn show_cursor(&mut self, blink: bool) -> Result<(), E> {
self.cursor = true;
self.blink = blink;
self.send_display_mode()
}
pub fn hide_cursor(&mut self) -> Result<(), E> {
self.cursor = false;
self.blink = false;
self.send_display_mode()
}
pub fn enable_scroll(&mut self, entry: Direction) -> Result<(), E> {
self.scroll = true;
self.entry = entry;
self.send_entry_mode()
}
pub fn disable_scroll(&mut self) -> Result<(), E> {
self.scroll = false;
self.send_entry_mode()
}
pub fn shift_display(&mut self, dir: Direction) -> Result<(), E> {
let mut command = 0b_00011000;
if dir == Direction::LeftToRigh {
command |= 0b_00000100;
}
self.send_command(command)
}
pub fn shift_cursor(&mut self, dir: Direction) -> Result<(), E> {
let mut command = 0b_00010000;
if dir == Direction::LeftToRigh {
command |= 0b_00000100;
}
self.send_command(command)
}
fn send_entry_mode(&mut self) -> Result<(), E> {
let mut command = 0b_00000100;
if self.scroll {
command |= 0b_00000001;
}
if self.entry == Direction::LeftToRigh {
command |= 0b_00000010;
}
self.send_command(command)
}
fn send_display_mode(&mut self) -> Result<(), E> {
let mut command = 0b_00001000;
if self.blink {
command |= 0b_00000001;
}
if self.cursor {
command |= 0b_00000010;
}
if self.display {
command |= 0b_00000100;
}
self.send_command(command)
}
fn send_function(&mut self, is: InstructionSet, lines: u8, dbl: bool) -> Result<(), E> {
let mut command = 0b_00110000;
if lines > 1 {
command |= 0b_00001000;
} else if dbl {
command |= 0b_00000100;
}
if is == InstructionSet::Extented {
command |= 0b_00000001;
}
self.send_command(command)
}
fn send_osc_config(&mut self, bias: bool, freq: u8) -> Result<(), E> {
assert!(freq < 8);
let mut command = 0b_00010000 | freq;
if bias {
command |= 0b_00001000;
}
self.send_command(command)
}
fn send_contrast(&mut self, contrast: u8) -> Result<(), E> {
assert!(contrast < 16);
self.send_command(0b_01110000 | contrast)
}
fn send_booster_config(&mut self, on: bool, icon: bool, contrast_low: u8) -> Result<(), E> {
assert!(contrast_low < 4);
let mut command = 0b_01010000 | contrast_low;
if on {
command |= 0b_00000100;
}
if icon {
command |= 0b_00001000;
}
self.send_command(command)
}
fn send_follower_config(&mut self, on: bool, ratio: u8) -> Result<(), E> {
assert!(ratio < 8);
let mut command = 0b_01100000 | ratio;
if on {
command |= 0b_00001000;
}
self.send_command(command)
}
fn send_command(&mut self, command: u8) -> Result<(), E> {
self.i2c.write(I2C_ADRESS, &[0x80, command])?;
self.delay.delay_ms(1);
Ok(())
}
}
impl<I2C, E, D> fmt::Write for ST7032i<I2C, D>
where
I2C: Read<Error = E> + Write<Error = E> + WriteRead<Error = E>,
D: DelayMs<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
self.write_char(c)?;
}
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
let mut command = [0x40, 0, 0, 0];
c.encode_utf8(&mut command[1..]);
self.i2c.write(I2C_ADRESS, &command[..2]).ok();
Ok(())
}
}