use crate::{bus::LcdBus, Chip, Config, Layout, LcdError};
use embedded_hal_async::delay::DelayNs;
pub struct Lcd<Bus> {
bus: Bus,
layout: Layout,
config: Config,
}
impl<Bus: LcdBus> Lcd<Bus> {
pub fn new(bus: Bus, layout: Layout, config: Config) -> Result<Self, LcdError> {
match config {
Config::SingleChip(_) => {
for i in 0..layout.line_count() {
match layout.line_config(i)?.0 {
Chip::One => continue,
_ => return Err(LcdError::InitSingleChipWrongLayout),
}
}
if bus.has_en2() {
return Err(LcdError::InitSingleChipWrongBus);
}
Ok(Lcd {
bus,
layout,
config,
})
}
Config::DoubleChip(_) => {
let mut chip_two_used = false;
for i in 0..layout.line_count() {
match layout.line_config(i)?.0 {
Chip::Two => chip_two_used = true,
_ => continue,
};
}
if !chip_two_used {
return Err(LcdError::InitDoubleChipWrongLayout);
}
if bus.has_en2() {
Ok(Lcd {
bus,
layout,
config,
})
} else {
Err(LcdError::InitDoubleChipWrongBus)
}
}
}
}
pub async fn init<D: DelayNs>(&mut self, delay: &mut D, chip: Chip) -> Result<(), LcdError> {
self.bus
.init(
delay,
chip,
self.config.chip_config(chip)?.function_mode,
self.config.chip_config(chip)?.display_mode,
self.config.chip_config(chip)?.entry_mode,
)
.await
}
pub async fn print<D: DelayNs>(
&mut self,
delay: &mut D,
line: usize,
column: u8,
string: &str,
) -> Result<(), LcdError> {
self.print_bytes(delay, line, column, string.as_bytes())
.await
}
pub async fn print_bytes<D: DelayNs>(
&mut self,
delay: &mut D,
line: usize,
column: u8,
byte_slice: &[u8],
) -> Result<(), LcdError> {
let (chip, address_range) = self.layout.line_config(line)?;
if column > address_range[1] - address_range[0] {
return Err(LcdError::PrintStartOutsideLayout);
}
let increment_mode = self.config.chip_config(chip)?.entry_mode & 0b0000_0010;
let printable_char_count = match increment_mode {
2 => {
if (address_range[1] - address_range[0] + 1 - column) as usize
>= byte_slice.len() - 1
{
byte_slice.len()
} else {
(address_range[1] - address_range[0] + 1 - column) as usize
}
}
_ => {
if column as usize >= byte_slice.len() - 1 {
byte_slice.len()
} else {
column as usize
}
}
};
self.write_instruction(delay, chip, 0b1000_0000 | (address_range[0] + column))
.await?;
for byte in byte_slice.iter().take(printable_char_count) {
self.write_data(delay, chip, *byte).await?;
}
Ok(())
}
pub async fn display_off<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.display_off();
let display_mode = self.config.chip_config(chip)?.display_mode;
self.write_instruction(delay, chip, display_mode).await
}
pub async fn display_on<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.display_on();
let display_mode = self.config.chip_config(chip)?.display_mode;
self.write_instruction(delay, chip, display_mode).await
}
pub async fn cursor_off<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.cursor_off();
let display_mode = self.config.chip_config(chip)?.display_mode;
self.write_instruction(delay, chip, display_mode).await
}
pub async fn cursor_on<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.cursor_on();
let display_mode = self.config.chip_config(chip)?.display_mode;
self.write_instruction(delay, chip, display_mode).await
}
pub async fn blink_off<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.blink_off();
let display_mode = self.config.chip_config(chip)?.display_mode;
self.write_instruction(delay, chip, display_mode).await
}
pub async fn blink_on<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.blink_on();
let display_mode = self.config.chip_config(chip)?.display_mode;
self.write_instruction(delay, chip, display_mode).await
}
pub async fn right_to_left<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.right_to_left();
let entry_mode = self.config.chip_config(chip)?.entry_mode;
self.write_instruction(delay, chip, entry_mode).await
}
pub async fn left_to_right<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.left_to_right();
let entry_mode = self.config.chip_config(chip)?.entry_mode;
self.write_instruction(delay, chip, entry_mode).await
}
pub async fn autoscroll_off<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.autoscroll_off();
let entry_mode = self.config.chip_config(chip)?.entry_mode;
self.write_instruction(delay, chip, entry_mode).await
}
pub async fn autoscroll_on<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.config.chip_config(chip)?.autoscroll_on();
let entry_mode = self.config.chip_config(chip)?.entry_mode;
self.write_instruction(delay, chip, entry_mode).await?;
Ok(())
}
pub async fn clear_display<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0000_0001).await
}
pub async fn return_home<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0000_0010).await
}
pub async fn move_cursor_left<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0001_0000).await
}
pub async fn move_cursor_right<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0001_0100).await
}
pub async fn scroll_display_left<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0001_1100).await
}
pub async fn scroll_display_right<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0001_1000).await
}
pub async fn set_cg_address<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
address: u8,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b0100_0000 | (0b0011_1111 & address))
.await
}
pub async fn set_dd_address<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
address: u8,
) -> Result<(), LcdError> {
self.write_instruction(delay, chip, 0b1000_0000 | (0b0111_1111 & address))
.await
}
pub async fn read_data<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<u8, LcdError> {
self.bus.wait_for_display(delay, chip).await?;
self.bus.read_data(delay, chip).await
}
pub async fn busy_flag_and_address_counter<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
) -> Result<(bool, u8), LcdError> {
self.bus.wait_for_display(delay, chip).await?;
self.bus.busy_flag_and_address_counter(delay, chip).await
}
pub async fn write_instruction<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
instruction: u8,
) -> Result<(), LcdError> {
self.bus.wait_for_display(delay, chip).await?;
self.bus.write_instruction(delay, chip, instruction).await
}
pub async fn write_data<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
data: u8,
) -> Result<(), LcdError> {
self.bus.wait_for_display(delay, chip).await?;
self.bus.write_data(delay, chip, data).await
}
pub async fn set_custom_character<D: DelayNs>(
&mut self,
delay: &mut D,
chip: Chip,
address: u8,
pattern: [u8; 8],
) -> Result<(), LcdError> {
if (address & 0b0111) != address {
return Err(LcdError::InvalidCGAddress);
}
self.set_cg_address(delay, chip, address << 3).await?;
for line in pattern.iter() {
self.write_data(delay, chip, line & 0b0001_1111).await?;
}
Ok(())
}
pub fn release(self) -> (Bus, Layout, Config) {
(self.bus, self.layout, self.config)
}
}