1use display_types::cea861::hdmi_forum::HdmiForumFrl;
2use hdmi_hal_async::phy::HdmiPhy;
3use hdmi_hal_async::{EqParams, FrlOutput, LanePatterns};
4use plumbob::ClearableUpdateFlags;
5use plumbob::lts::{self, TrainingIo};
6
7#[cfg(feature = "alloc")]
8use alloc::vec::Vec;
9
10use crate::client::ScdcClient;
11use crate::{
12 ExitError, FrlConfig, LtpRequests, SourceTestConfig, Trained, TrainingConfig, TrainingError,
13 TrainingEvent, UpdateFlags,
14};
15
16#[cfg(feature = "alloc")]
17use crate::TrainingTrace;
18
19type Error<C, P> = TrainingError<<C as ScdcClient>::Error, <P as HdmiPhy>::Error>;
20
21pub struct FrlTrainer<C, P> {
37 scdc: C,
38 phy: P,
39}
40
41impl<C: ScdcClient, P: HdmiPhy> FrlTrainer<C, P> {
42 pub fn new(scdc: C, phy: P) -> Self {
44 Self { scdc, phy }
45 }
46
47 pub fn into_parts(self) -> (C, P) {
49 (self.scdc, self.phy)
50 }
51
52 pub fn scdc(&self) -> &C {
54 &self.scdc
55 }
56
57 pub fn scdc_mut(&mut self) -> &mut C {
59 &mut self.scdc
60 }
61
62 pub fn phy(&self) -> &P {
64 &self.phy
65 }
66
67 pub fn phy_mut(&mut self) -> &mut P {
70 &mut self.phy
71 }
72
73 pub async fn exit_to_tmds(&mut self) -> Result<(), ExitError<C::Error, P::Error>> {
83 let mut io = AsyncIo {
84 scdc: &mut self.scdc,
85 phy: &mut self.phy,
86 };
87 lts::exit_to_tmds(&mut io, &mut |_| {}).await
88 }
89
90 pub async fn train_at_rate(
92 &mut self,
93 rate: HdmiForumFrl,
94 config: &TrainingConfig,
95 ) -> Result<Trained, Error<C, P>> {
96 self.train(&[rate], config).await
97 }
98
99 pub async fn train(
104 &mut self,
105 rates: &[HdmiForumFrl],
106 config: &TrainingConfig,
107 ) -> Result<Trained, Error<C, P>> {
108 self.train_with_events(rates, config, &mut |_| {}).await
109 }
110
111 #[cfg(feature = "alloc")]
114 pub async fn train_at_rate_traced(
115 &mut self,
116 rate: HdmiForumFrl,
117 config: &TrainingConfig,
118 ) -> (Result<Trained, Error<C, P>>, TrainingTrace) {
119 self.train_traced(&[rate], config).await
120 }
121
122 #[cfg(feature = "alloc")]
127 pub async fn train_traced(
128 &mut self,
129 rates: &[HdmiForumFrl],
130 config: &TrainingConfig,
131 ) -> (Result<Trained, Error<C, P>>, TrainingTrace) {
132 let mut events = Vec::new();
133 let result = self
134 .train_with_events(rates, config, &mut |event| events.push(event))
135 .await;
136 (result, TrainingTrace::new(rates.to_vec(), *config, events))
137 }
138
139 pub async fn train_with_events<F: FnMut(TrainingEvent)>(
144 &mut self,
145 rates: &[HdmiForumFrl],
146 config: &TrainingConfig,
147 record: &mut F,
148 ) -> Result<Trained, Error<C, P>> {
149 let mut io = AsyncIo {
150 scdc: &mut self.scdc,
151 phy: &mut self.phy,
152 };
153 lts::run(&mut io, rates, config, record).await
154 }
155}
156
157struct AsyncIo<'a, C, P> {
159 scdc: &'a mut C,
160 phy: &'a mut P,
161}
162
163impl<C: ScdcClient, P: HdmiPhy> TrainingIo for AsyncIo<'_, C, P> {
164 type ScdcError = C::Error;
165 type PhyError = P::Error;
166
167 async fn read_flt_ready(&mut self) -> Result<bool, C::Error> {
168 self.scdc.read_flt_ready().await
169 }
170
171 async fn read_update_flags(&mut self) -> Result<UpdateFlags, C::Error> {
172 self.scdc.read_update_flags().await
173 }
174
175 async fn clear_update_flags(&mut self, flags: ClearableUpdateFlags) -> Result<(), C::Error> {
176 self.scdc.clear_update_flags(flags).await
177 }
178
179 async fn read_ltp_requests(&mut self) -> Result<LtpRequests, C::Error> {
180 self.scdc.read_ltp_requests().await
181 }
182
183 async fn read_source_test_config(&mut self) -> Result<SourceTestConfig, C::Error> {
184 self.scdc.read_source_test_config().await
185 }
186
187 async fn write_config_0_defaults(&mut self) -> Result<(), C::Error> {
188 self.scdc.write_config_0_defaults().await
189 }
190
191 async fn write_frl_config(&mut self, config: FrlConfig) -> Result<(), C::Error> {
192 self.scdc.write_frl_config(config).await
193 }
194
195 async fn set_frl_rate(&mut self, rate: HdmiForumFrl) -> Result<(), P::Error> {
196 self.phy.set_frl_rate(rate).await
197 }
198
199 async fn send_ltp(&mut self, patterns: LanePatterns) -> Result<(), P::Error> {
200 self.phy.send_ltp(patterns).await
201 }
202
203 async fn set_frl_output(&mut self, output: FrlOutput) -> Result<(), P::Error> {
204 self.phy.set_frl_output(output).await
205 }
206
207 async fn adjust_equalization(&mut self, params: EqParams) -> Result<(), P::Error> {
208 self.phy.adjust_equalization(params).await
209 }
210}
211
212#[cfg(test)]
213mod tests;