itpdp/pico/src/screen.rs
Daniel Bulant 37936d121d
update
2026-05-10 12:43:10 +02:00

103 lines
2.6 KiB
Rust

use core::convert::Infallible;
use ag_lcd::LcdDisplay;
use embassy_rp::gpio::Output;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex, signal::Signal};
use embassy_time::{Delay, Timer};
use ufmt::uWrite;
pub struct ScreenBuffer {
line1: [u8; 16],
line2: [u8; 16],
line1_ptr: u8,
line2_ptr: u8,
}
impl ScreenBuffer {
pub fn clear(&mut self) {
self.line1.fill(0);
self.line2.fill(0);
self.line1_ptr = 0;
self.line2_ptr = 0;
}
pub fn line1(&mut self) -> ScreenBufferWriter<'_> {
ScreenBufferWriter { buf: self, line: 0 }
}
pub fn line2(&mut self) -> ScreenBufferWriter<'_> {
ScreenBufferWriter { buf: self, line: 1 }
}
}
pub struct ScreenBufferWriter<'a> {
buf: &'a mut ScreenBuffer,
line: u8,
}
impl<'a> uWrite for ScreenBufferWriter<'a> {
type Error = Infallible;
fn write_char(&mut self, c: char) -> Result<(), Self::Error> {
if self.line == 0 {
let ptr = self.buf.line1_ptr as usize;
self.buf.line1[ptr] = c as u8;
self.buf.line1_ptr = (self.buf.line1_ptr + 1) % 16;
} else {
let ptr = self.buf.line2_ptr as usize;
self.buf.line2[ptr] = c as u8;
self.buf.line2_ptr = (self.buf.line2_ptr + 1) % 16;
}
Ok(())
}
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
for c in s.chars() {
self.write_char(c)?;
}
Ok(())
}
}
impl Drop for ScreenBufferWriter<'_> {
fn drop(&mut self) {
LCD_UPDATE.signal(());
}
}
pub static SCREEN_BUFFER: Mutex<CriticalSectionRawMutex, ScreenBuffer> = Mutex::new(ScreenBuffer {
line1: [0; 16],
line1_ptr: 0,
line2: [0; 16],
line2_ptr: 0,
});
static LCD_UPDATE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
#[embassy_executor::task]
pub async fn lcd_display_task(mut lcd: LcdDisplay<Output<'static>, Delay>) {
loop {
LCD_UPDATE.wait().await;
let buffer = SCREEN_BUFFER.lock().await;
lcd.clear();
for byte in &buffer.line1 {
lcd.write(*byte);
}
lcd.set_position(0, 1);
for byte in &buffer.line2 {
lcd.write(*byte);
}
Timer::after_millis(20).await;
}
}
pub async fn overwrite_lcd(line1: &str, line2: &str) {
let mut buffer = SCREEN_BUFFER.lock().await;
buffer.line1_ptr = 0;
buffer.line2_ptr = 0;
buffer.line1.fill(0);
buffer.line2.fill(0);
buffer.line1[..line1.len()].copy_from_slice(line1.as_bytes());
buffer.line2[..line2.len()].copy_from_slice(line2.as_bytes());
LCD_UPDATE.signal(());
}