use display_types::cea861::hdmi_forum::HdmiForumFrl;
use hdmi_hal_async::phy::HdmiPhy;
use hdmi_hal_async::{EqParams, FrlOutput, LanePatterns};
use plumbob::ClearableUpdateFlags;
use plumbob::lts::{self, TrainingIo};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crate::client::ScdcClient;
use crate::{
ExitError, FrlConfig, LtpRequests, SourceTestConfig, Trained, TrainingConfig, TrainingError,
TrainingEvent, UpdateFlags,
};
#[cfg(feature = "alloc")]
use crate::TrainingTrace;
type Error<C, P> = TrainingError<<C as ScdcClient>::Error, <P as HdmiPhy>::Error>;
pub struct FrlTrainer<C, P> {
scdc: C,
phy: P,
}
impl<C: ScdcClient, P: HdmiPhy> FrlTrainer<C, P> {
pub fn new(scdc: C, phy: P) -> Self {
Self { scdc, phy }
}
pub fn into_parts(self) -> (C, P) {
(self.scdc, self.phy)
}
pub fn scdc(&self) -> &C {
&self.scdc
}
pub fn scdc_mut(&mut self) -> &mut C {
&mut self.scdc
}
pub fn phy(&self) -> &P {
&self.phy
}
pub fn phy_mut(&mut self) -> &mut P {
&mut self.phy
}
pub async fn exit_to_tmds(&mut self) -> Result<(), ExitError<C::Error, P::Error>> {
let mut io = AsyncIo {
scdc: &mut self.scdc,
phy: &mut self.phy,
};
lts::exit_to_tmds(&mut io, &mut |_| {}).await
}
pub async fn train_at_rate(
&mut self,
rate: HdmiForumFrl,
config: &TrainingConfig,
) -> Result<Trained, Error<C, P>> {
self.train(&[rate], config).await
}
pub async fn train(
&mut self,
rates: &[HdmiForumFrl],
config: &TrainingConfig,
) -> Result<Trained, Error<C, P>> {
self.train_with_events(rates, config, &mut |_| {}).await
}
#[cfg(feature = "alloc")]
pub async fn train_at_rate_traced(
&mut self,
rate: HdmiForumFrl,
config: &TrainingConfig,
) -> (Result<Trained, Error<C, P>>, TrainingTrace) {
self.train_traced(&[rate], config).await
}
#[cfg(feature = "alloc")]
pub async fn train_traced(
&mut self,
rates: &[HdmiForumFrl],
config: &TrainingConfig,
) -> (Result<Trained, Error<C, P>>, TrainingTrace) {
let mut events = Vec::new();
let result = self
.train_with_events(rates, config, &mut |event| events.push(event))
.await;
(result, TrainingTrace::new(rates.to_vec(), *config, events))
}
pub async fn train_with_events<F: FnMut(TrainingEvent)>(
&mut self,
rates: &[HdmiForumFrl],
config: &TrainingConfig,
record: &mut F,
) -> Result<Trained, Error<C, P>> {
let mut io = AsyncIo {
scdc: &mut self.scdc,
phy: &mut self.phy,
};
lts::run(&mut io, rates, config, record).await
}
}
struct AsyncIo<'a, C, P> {
scdc: &'a mut C,
phy: &'a mut P,
}
impl<C: ScdcClient, P: HdmiPhy> TrainingIo for AsyncIo<'_, C, P> {
type ScdcError = C::Error;
type PhyError = P::Error;
async fn read_flt_ready(&mut self) -> Result<bool, C::Error> {
self.scdc.read_flt_ready().await
}
async fn read_update_flags(&mut self) -> Result<UpdateFlags, C::Error> {
self.scdc.read_update_flags().await
}
async fn clear_update_flags(&mut self, flags: ClearableUpdateFlags) -> Result<(), C::Error> {
self.scdc.clear_update_flags(flags).await
}
async fn read_ltp_requests(&mut self) -> Result<LtpRequests, C::Error> {
self.scdc.read_ltp_requests().await
}
async fn read_source_test_config(&mut self) -> Result<SourceTestConfig, C::Error> {
self.scdc.read_source_test_config().await
}
async fn write_config_0_defaults(&mut self) -> Result<(), C::Error> {
self.scdc.write_config_0_defaults().await
}
async fn write_frl_config(&mut self, config: FrlConfig) -> Result<(), C::Error> {
self.scdc.write_frl_config(config).await
}
async fn set_frl_rate(&mut self, rate: HdmiForumFrl) -> Result<(), P::Error> {
self.phy.set_frl_rate(rate).await
}
async fn send_ltp(&mut self, patterns: LanePatterns) -> Result<(), P::Error> {
self.phy.send_ltp(patterns).await
}
async fn set_frl_output(&mut self, output: FrlOutput) -> Result<(), P::Error> {
self.phy.set_frl_output(output).await
}
async fn adjust_equalization(&mut self, params: EqParams) -> Result<(), P::Error> {
self.phy.adjust_equalization(params).await
}
}
#[cfg(test)]
mod tests;