// 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>| { 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::::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; } }