#![no_std]
#![allow(clippy::needless_doctest_main)]
#![deny(warnings)]
#[derive(Copy, Clone, Debug)]
pub enum FunctionMode {
Bit4 = 0x00,
Bit8 = 0x10,
}
#[derive(Copy, Clone, Debug)]
pub enum FunctionDots {
Dots5x8 = 0x00,
Dots5x10 = 0x04,
}
#[derive(Copy, Clone, Debug)]
pub enum FunctionLine {
Line1 = 0x00,
Line2 = 0x08,
}
#[derive(Copy, Clone, Debug)]
pub enum DisplayBlink {
BlinkOff = 0x00,
BlinkOn = 0x01,
}
#[derive(Copy, Clone, Debug)]
pub enum DisplayCursor {
CursorOff = 0x00,
CursorOn = 0x02,
}
#[derive(Copy, Clone, Debug)]
pub enum DisplayMode {
DisplayOff = 0x00,
DisplayOn = 0x04,
}
#[derive(Copy, Clone, Debug)]
pub enum Direction {
Left = 0x00,
Right = 0x04,
}
#[derive(Copy, Clone, Debug)]
pub enum Scroll {
CursorMove = 0x00,
DisplayMove = 0x08,
}
#[derive(Copy, Clone, Debug)]
pub enum EntryModeDirection {
EntryLeft = 0x00,
EntryRight = 0x02,
}
#[derive(Copy, Clone, Debug)]
pub enum EntryModeShift {
NoShift = 0x00,
Shift = 0x01,
}
#[derive(Copy, Clone, Debug)]
pub enum Command {
ClearDisplay = 0x01,
ReturnHome = 0x02,
EntryModeSet = 0x04,
DisplayControl = 0x08,
CursorShift = 0x10,
FunctionSet = 0x20,
SetCGRamAddr = 0x40,
SetDDRamAddr = 0x80,
}
pub trait Delay {
fn delay_us(&mut self, delay_usec: u32);
}
trait InternalHardware {
fn rs(&self, bit: bool);
fn enable(&self, bit: bool);
fn data(&self, data: u8);
fn wait_address(&self) {}
fn mode(&self) -> FunctionMode;
fn rw(&self, bit: bool);
fn read_data(&self) -> u8;
}
pub trait Hardware {
fn rs(&mut self, bit: bool);
fn enable(&mut self, bit: bool);
fn data(&mut self, data: u8);
fn wait_address(&mut self) {}
fn mode(&self) -> FunctionMode {
FunctionMode::Bit4
}
fn can_read(&self) -> bool {
false
}
fn rw(&mut self, _bit: bool) {
unimplemented!()
}
fn read_data(&mut self) -> u8 {
unimplemented!()
}
fn apply(&mut self) {}
}
pub struct Display<HW: Hardware + Delay> {
hw: HW,
}
trait WaitReady {
fn wait_ready(&self, delay: u32);
}
impl<HW: Hardware + Delay> core::fmt::Write for Display<HW> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.print(s);
Ok(())
}
}
impl<HW: Hardware + Delay> Display<HW> {
pub fn new(hw: HW) -> Display<HW> {
Display { hw }
}
#[inline(never)]
pub fn init(&mut self, line: FunctionLine, dots: FunctionDots) {
let mode = self.hw.mode();
self.hw.rs(false);
self.hw.apply();
self.hw.wait_address();
match mode {
FunctionMode::Bit8 => {
self.send_data(
(Command::FunctionSet as u8)
| (FunctionMode::Bit8 as u8)
| (FunctionLine::Line2 as u8)
| (FunctionDots::Dots5x10 as u8),
);
self.hw.delay_us(4500);
self.pulse_enable(); self.hw.delay_us(150);
self.pulse_enable(); self.wait_ready_default();
}
FunctionMode::Bit4 => {
self.send_data(((Command::FunctionSet as u8) | (FunctionMode::Bit8 as u8)) >> 4);
self.hw.delay_us(4500);
self.pulse_enable(); self.hw.delay_us(150);
self.pulse_enable(); self.wait_ready_default();
self.send_data(((Command::FunctionSet as u8) | (FunctionMode::Bit4 as u8)) >> 4);
self.wait_ready_default(); }
}
self.command((Command::FunctionSet as u8) | (mode as u8) | (line as u8) | (dots as u8));
self.display(
DisplayMode::DisplayOff,
DisplayCursor::CursorOff,
DisplayBlink::BlinkOff,
);
self.clear();
self.entry_mode(EntryModeDirection::EntryRight, EntryModeShift::NoShift);
}
pub fn clear(&mut self) -> &Self {
self.command(Command::ClearDisplay as u8);
self.wait_ready(2000);
self
}
pub fn home(&mut self) -> &Self {
self.command(Command::ReturnHome as u8);
self.wait_ready(2000);
self
}
pub fn entry_mode(&mut self, dir: EntryModeDirection, scroll: EntryModeShift) -> &Self {
self.command((Command::EntryModeSet as u8) | (dir as u8) | (scroll as u8))
}
pub fn display(
&mut self,
display: DisplayMode,
cursor: DisplayCursor,
blink: DisplayBlink,
) -> &Self {
self.command(
(Command::DisplayControl as u8) | (display as u8) | (cursor as u8) | (blink as u8),
)
}
pub fn scroll(&mut self, dir: Direction) -> &Self {
self.command((Command::CursorShift as u8) | (Scroll::DisplayMove as u8) | (dir as u8))
}
pub fn cursor(&mut self, dir: Direction) -> &Self {
self.command((Command::CursorShift as u8) | (Scroll::CursorMove as u8) | (dir as u8))
}
pub fn position(&mut self, col: u8, row: u8) {
let offset = match row {
1 => 0x40,
2 => 0x14,
3 => 0x54,
_ => 0,
};
self.command((Command::SetDDRamAddr as u8) | (col + offset));
}
pub fn print(&mut self, str: &str) -> &Self {
for c in str.as_bytes() {
self.write(*c);
}
self
}
#[inline(never)]
pub fn write(&mut self, data: u8) -> &Self {
self.hw.rs(true);
self.hw.apply();
self.hw.wait_address(); self.send(data);
self.wait_ready_default();
self.hw.delay_us(5);
self
}
#[inline(never)]
pub fn upload_character(&mut self, location: u8, map: [u8; 8]) -> &Self {
assert!(location <= 7);
self.command((Command::SetCGRamAddr as u8) | ((location & 0x7) << 3));
for item in map.iter().take(8) {
self.write(*item);
}
self
}
#[inline(never)]
fn command(&mut self, cmd: u8) -> &Self {
self.hw.rs(false);
self.hw.apply();
self.hw.wait_address(); self.send(cmd);
self.wait_ready_default();
self
}
fn wait_ready_default(&mut self) {
self.wait_ready(50);
}
#[inline(never)]
fn pulse_enable(&mut self) {
self.hw.enable(true);
self.hw.apply();
self.hw.delay_us(1); self.hw.enable(false);
self.hw.apply();
}
#[inline(never)]
fn send(&mut self, data: u8) {
match self.hw.mode() {
FunctionMode::Bit8 => {
self.send_data(data);
}
FunctionMode::Bit4 => {
self.send_data(data >> 4);
self.send_data(data & 0xf);
}
}
}
#[inline(never)]
fn send_data(&mut self, data: u8) {
self.hw.data(data);
self.hw.apply();
self.pulse_enable();
}
#[inline(never)]
fn wait_ready(&mut self, delay: u32) {
if self.hw.can_read() {
self.hw.rs(false);
self.hw.rw(true);
self.hw.apply();
self.hw.wait_address();
while self.receive() & 0b1000_0000 != 0 {}
self.hw.rw(false);
self.hw.apply();
} else {
self.hw.delay_us(delay);
}
}
#[inline(never)]
fn receive_data(&mut self) -> u8 {
self.hw.enable(true);
self.hw.apply();
self.hw.delay_us(1);
let data = self.hw.read_data();
self.hw.delay_us(1);
self.hw.enable(false);
self.hw.apply();
data
}
fn receive(&mut self) -> u8 {
match self.hw.mode() {
FunctionMode::Bit8 => self.receive_data(),
FunctionMode::Bit4 => (self.receive_data() << 4) | (self.receive_data() & 0xf),
}
}
pub fn unwrap(self) -> HW {
self.hw
}
}