#![cfg(feature = "osd")]
use radio_controllers::RcMode;
use crate::{
display::{
Display, DisplayPort, DisplayPortDeviceType,
DisplayPortLayer::{self, Background},
DisplayPortMutex,
},
osd::{OsdConfig, OsdDrawContext, elements::OsdElements},
};
#[allow(unused)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum OsdState {
#[default]
Init,
Idle,
Start,
ProcessStats1,
RefreshStats,
ProcessStats2,
ProcessStats3,
UpdateAlarms,
RefreshPreArm,
UpdateCanvas,
SetCurrentElement {
element_index: usize,
},
RenderCurrentElement {
element_index: usize,
},
FlushCurrentElement {
element_index: usize,
more_to_draw: bool,
},
UpdateHeartbeat,
Commit,
Transfer,
}
#[allow(unused)]
impl OsdState {
fn sync_blink(&mut self, _time_us: u64) {
_ = self;
}
fn draw_logo_and_complete_initialization(&mut self) {
_ = self;
}
async fn init(&mut self, display_port_mutex: &'static DisplayPortMutex) -> Self {
let mut display_port = display_port_mutex.lock().await;
if display_port.check_ready(false) {
display_port.begin_transaction(DisplayPort::DISPLAY_TRANSACTION_OPTION_RESET_DRAWING);
self.draw_logo_and_complete_initialization();
return Self::Commit;
}
if display_port.device_type() == DisplayPortDeviceType::FrskyOsd {
display_port.redraw();
}
Self::Init
}
async fn start(&mut self, display_port_mutex: &'static DisplayPortMutex) -> Self {
let mut display_port = display_port_mutex.lock().await;
if display_port.is_transfer_in_progress() { Self::Start } else { Self::UpdateHeartbeat }
}
async fn update_heartbeat(&mut self, display_port_mutex: &'static DisplayPortMutex) -> Self {
let mut display_port = display_port_mutex.lock().await;
if display_port.heartbeat() == 0 {
Self::ProcessStats1
} else {
Self::UpdateHeartbeat
}
}
async fn process_stats1(&mut self, display_port_mutex: &'static DisplayPortMutex, _time_us: u64) -> Self {
let mut display_port = display_port_mutex.lock().await;
display_port.begin_transaction(DisplayPort::DISPLAY_TRANSACTION_OPTION_RESET_DRAWING);
Self::RefreshStats
}
fn refresh_stats(&mut self) -> Self {
_ = self;
Self::ProcessStats2
}
fn process_stats2(&mut self, _time_us: u64) -> Self {
_ = self;
Self::ProcessStats3
}
fn process_stats3(&mut self) -> Self {
_ = self;
Self::UpdateAlarms
}
fn update_alarms(&mut self) -> Self {
_ = self;
Self::UpdateCanvas
}
async fn update_canvas(
&mut self,
osd_elements: &mut OsdElements,
draw_ctx: &OsdDrawContext,
display_port_mutex: &'static DisplayPortMutex,
osd_config: &OsdConfig,
time_us: u64,
) -> Self {
let mut display_port = display_port_mutex.lock().await;
if draw_ctx.rx_message.rc_modes.test(RcMode::OSD) {
display_port.clear_screen().await;
return Self::Commit;
}
if display_port.layer_supported(Background) {
display_port.layer_copy(DisplayPortLayer::Foreground, DisplayPortLayer::Background);
} else {
display_port.clear_screen().await;
}
self.sync_blink(time_us);
let orientation = draw_ctx.orientation;
osd_elements.update_cache(
orientation.calculate_roll_degrees(),
orientation.calculate_pitch_degrees(),
orientation.calculate_yaw_degrees(),
);
Self::SetCurrentElement { element_index: 0 }
}
fn set_current_element(element_index: usize, osd_elements: &mut OsdElements) -> Self {
if osd_elements.set_current_element_by_index(element_index) {
Self::RenderCurrentElement { element_index }
} else {
Self::Commit
}
}
async fn render_current_element(
element_index: usize,
osd_elements: &mut OsdElements,
draw_ctx: &OsdDrawContext,
display_port_mutex: &'static DisplayPortMutex,
osd_config: &OsdConfig,
) -> Self {
let mut display_port = display_port_mutex.lock().await;
let more_to_draw = osd_elements.draw_current_element(draw_ctx, &mut *display_port, osd_config).await;
Self::FlushCurrentElement { element_index, more_to_draw }
}
async fn flush_current_element(
element_index: usize,
more_to_draw: bool,
osd_elements: &mut OsdElements,
display_port_mutex: &'static DisplayPortMutex,
) -> Self {
let mut display_port = display_port_mutex.lock().await;
let more_to_display = osd_elements.display_current_element(&mut *display_port);
if more_to_display {
return Self::FlushCurrentElement { element_index, more_to_draw };
}
if more_to_draw {
Self::RenderCurrentElement { element_index }
} else {
Self::SetCurrentElement { element_index: element_index + 1 }
}
}
fn refresh_prearm(osd_elements: &mut OsdElements) -> Self {
if osd_elements.draw_spec() {
Self::Commit
} else {
Self::RefreshPreArm
}
}
async fn commit(display_port_mutex: &'static DisplayPortMutex) -> Self {
let mut display_port = display_port_mutex.lock().await;
display_port.commit_transaction();
Self::Transfer
}
async fn transfer(display_port_mutex: &'static DisplayPortMutex) -> Self {
let mut display_port = display_port_mutex.lock().await;
match display_port.transfer_screen().await {
Ok(still_transferring) => {
if still_transferring {
Self::Transfer
} else {
Self::Idle
}
}
Err(_err) => {
Self::Idle
}
}
}
}
#[allow(unused)]
impl OsdState {
pub fn start_frame(&mut self) -> bool {
if *self == OsdState::Idle {
*self = OsdState::Start;
true
} else {
false
}
}
pub async fn update_display_iteration(
&mut self,
osd_elements: &mut OsdElements,
draw_ctx: &OsdDrawContext,
display_port_mutex: &'static DisplayPortMutex,
osd_config: &OsdConfig,
time_us: u64,
) {
*self = match core::mem::take(self) {
Self::Init => self.init(display_port_mutex).await,
Self::Start => self.start(display_port_mutex).await,
Self::UpdateHeartbeat => self.update_heartbeat(display_port_mutex).await,
Self::ProcessStats1 => self.process_stats1(display_port_mutex, time_us).await,
Self::RefreshStats => self.refresh_stats(),
Self::ProcessStats2 => self.process_stats2(time_us), Self::ProcessStats3 => self.process_stats3(),
Self::UpdateAlarms => self.update_alarms(),
Self::UpdateCanvas => {
self.update_canvas(osd_elements, draw_ctx, display_port_mutex, osd_config, time_us).await
}
Self::SetCurrentElement { element_index } => Self::set_current_element(element_index, osd_elements),
Self::RenderCurrentElement { element_index } => {
Self::render_current_element(element_index, osd_elements, draw_ctx, display_port_mutex, osd_config)
.await
}
Self::FlushCurrentElement { element_index, more_to_draw } => {
Self::flush_current_element(element_index, more_to_draw, osd_elements, display_port_mutex).await
}
Self::RefreshPreArm => Self::refresh_prearm(osd_elements),
Self::Commit => Self::commit(display_port_mutex).await,
Self::Transfer => Self::transfer(display_port_mutex).await,
Self::Idle => Self::Idle,
}
}
}