102 lines
3.8 KiB
Rust
102 lines
3.8 KiB
Rust
// src/display/task.rs
|
|
use embassy_time::{Duration, Timer};
|
|
use log::{error, info};
|
|
|
|
use alloc::boxed::Box;
|
|
use mousefood::{EmbeddedBackend, EmbeddedBackendConfig};
|
|
use ratatui::Terminal;
|
|
use ssd1306::{mode::BufferedGraphicsMode, prelude::*, I2CDisplayInterface, Ssd1306};
|
|
|
|
use crate::bus::I2cDevice;
|
|
use crate::display::api::receiver;
|
|
use crate::display::tui::{render_frame, DisplayState, Screen, ScreenEvent};
|
|
use crate::contracts::DisplayCommand;
|
|
use pages_tui::prelude::*;
|
|
|
|
const REFRESH_INTERVAL_MS: u64 = 100;
|
|
|
|
#[embassy_executor::task]
|
|
pub async fn display_task(i2c: I2cDevice) {
|
|
info!("Display task starting...");
|
|
|
|
let interface = I2CDisplayInterface::new(i2c);
|
|
let mut display = Ssd1306::new(interface, DisplaySize128x32, DisplayRotation::Rotate0)
|
|
.into_buffered_graphics_mode();
|
|
|
|
if let Err(e) = display.init() {
|
|
error!("Display init failed: {:?}", e);
|
|
loop { Timer::after(Duration::from_secs(60)).await; }
|
|
}
|
|
|
|
let config = EmbeddedBackendConfig {
|
|
flush_callback: Box::new(|d: &mut Ssd1306<_, _, BufferedGraphicsMode<DisplaySize128x32>>| {
|
|
let _ = d.flush();
|
|
}),
|
|
..Default::default()
|
|
};
|
|
|
|
let backend = EmbeddedBackend::new(&mut display, config);
|
|
let mut terminal = Terminal::new(backend).expect("terminal init failed");
|
|
|
|
let mut state = DisplayState::default();
|
|
let mut orchestrator = Orchestrator::<Screen>::new();
|
|
let rx = receiver();
|
|
|
|
// Register pages
|
|
// Enum-based registration
|
|
orchestrator.register(Screen::Menu);
|
|
orchestrator.register(Screen::Imu);
|
|
orchestrator.register(Screen::Chat);
|
|
|
|
orchestrator.bind(Key::tab(), ComponentAction::Next);
|
|
orchestrator.bind(Key::enter(), ComponentAction::Select);
|
|
|
|
let _ = orchestrator.navigate_to(Screen::Menu);
|
|
|
|
info!("Display ready");
|
|
|
|
loop {
|
|
while let Ok(cmd) = rx.try_receive() {
|
|
match cmd {
|
|
DisplayCommand::PushKey(key) => {
|
|
if key == Key::tab() {
|
|
orchestrator.focus_manager_mut().next();
|
|
} else if key == Key::enter() {
|
|
if let Ok(events) = orchestrator.process_frame(key) {
|
|
for event in events {
|
|
match event {
|
|
ScreenEvent::GoToImu => {
|
|
let _ = orchestrator.navigate_to(Screen::Imu);
|
|
}
|
|
ScreenEvent::GoToChat => {
|
|
let _ = orchestrator.navigate_to(Screen::Chat);
|
|
}
|
|
ScreenEvent::NavigatePrev => {
|
|
if let Some(cur) = orchestrator.current() {
|
|
let prev = cur.prev();
|
|
let _ = orchestrator.navigate_to(prev);
|
|
}
|
|
}
|
|
ScreenEvent::NavigateNext => {
|
|
if let Some(cur) = orchestrator.current() {
|
|
let next = cur.next();
|
|
let _ = orchestrator.navigate_to(next);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_ => state.apply_command(cmd),
|
|
}
|
|
}
|
|
|
|
if let Some(screen) = orchestrator.current() {
|
|
render_frame(&mut terminal, screen, orchestrator.focus_manager().current(), &state);
|
|
}
|
|
|
|
Timer::after(Duration::from_millis(REFRESH_INTERVAL_MS)).await;
|
|
}
|
|
}
|