1use hdmi_hal_async::scdc::ScdcTransport;
8use plumbob_async::ScdcClient;
9
10use crate::{Config0, ScdcError};
11
12use super::Scdc;
13
14#[cfg_attr(docsrs, doc(cfg(feature = "plumbob-async")))]
24impl<T: ScdcTransport> ScdcClient for Scdc<T> {
25 type Error = ScdcError<T::Error>;
26
27 async fn read_flt_ready(&mut self) -> Result<bool, Self::Error> {
28 Ok(Scdc::read_status_flags(self).await?.flt_ready)
29 }
30
31 async fn read_update_flags(&mut self) -> Result<plumbob_async::UpdateFlags, Self::Error> {
32 Scdc::read_update_flags(self).await.map(Into::into)
33 }
34
35 async fn clear_update_flags(
36 &mut self,
37 flags: plumbob_async::ClearableUpdateFlags,
38 ) -> Result<(), Self::Error> {
39 Scdc::clear_update_flags(self, flags.into()).await
40 }
41
42 async fn read_ltp_requests(&mut self) -> Result<plumbob_async::LtpRequests, Self::Error> {
43 Scdc::read_ltp_requests(self).await.map(Into::into)
44 }
45
46 async fn read_source_test_config(
47 &mut self,
48 ) -> Result<plumbob_async::SourceTestConfig, Self::Error> {
49 Scdc::read_source_test_config(self).await.map(Into::into)
50 }
51
52 async fn write_config_0_defaults(&mut self) -> Result<(), Self::Error> {
53 Scdc::write_config_0(self, Config0::default()).await
54 }
55
56 async fn write_frl_config(
57 &mut self,
58 config: plumbob_async::FrlConfig,
59 ) -> Result<(), Self::Error> {
60 Scdc::write_frl_config(self, config.into()).await
61 }
62
63 async fn read_ced(&mut self) -> Result<plumbob_async::CedCounters, Self::Error> {
64 Scdc::read_ced(self).await.map(Into::into)
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::super::Scdc;
71 use super::super::test_transport::TestTransport;
72 use crate::{ProtocolError, ScdcError};
73 use display_types::HdmiForumFrl;
74 use plumbob_async::{
75 ClearableUpdateFlags, FfeLevels, FrlConfig, LtpReq, LtpRequests, ScdcClient,
76 SourceTestConfig, UpdateFlags,
77 };
78
79 fn scdc_with(regs: &[(u8, u8)]) -> Scdc<TestTransport> {
80 let mut t = TestTransport::new();
81 for &(addr, value) in regs {
82 t.set(addr, value);
83 }
84 Scdc::new(t)
85 }
86
87 #[pollster::test]
90 async fn read_flt_ready_reads_status_flags_0_bit_6() {
91 assert!(
92 ScdcClient::read_flt_ready(&mut scdc_with(&[(0x40, 0x40)]))
93 .await
94 .unwrap()
95 );
96 assert!(
97 !ScdcClient::read_flt_ready(&mut scdc_with(&[(0x40, 0xBF)]))
98 .await
99 .unwrap()
100 );
101 }
102
103 #[pollster::test]
106 async fn read_update_flags_maps_every_flag() {
107 let read = |byte| {
108 pollster::block_on(ScdcClient::read_update_flags(&mut scdc_with(&[(
109 0x10, byte,
110 )])))
111 .unwrap()
112 };
113 let flag = |n: usize| {
114 let b = |i| i == n;
115 UpdateFlags::new(b(0), b(1), b(2), b(3), b(4), b(5), b(6))
116 };
117 for n in 0..7 {
118 assert_eq!(read(1 << n), flag(n), "bit {n}");
119 }
120 assert_eq!(
121 read(0x7F),
122 UpdateFlags::new(true, true, true, true, true, true, true)
123 );
124 assert_eq!(read(0x80), UpdateFlags::default());
126 }
127
128 #[pollster::test]
131 async fn clear_update_flags_writes_each_given_bit() {
132 let clear = |flags| {
133 let mut scdc = Scdc::new(TestTransport::new());
134 pollster::block_on(ScdcClient::clear_update_flags(&mut scdc, flags)).unwrap();
135 scdc.into_transport().get(0x10)
136 };
137 for (n, bit) in [0, 1, 3, 4, 5, 6].into_iter().enumerate() {
139 let b = |i| i == n;
140 let flags = ClearableUpdateFlags::new(b(0), b(1), b(2), b(3), b(4), b(5));
141 assert_eq!(clear(flags), 1 << bit, "bit {bit}");
142 }
143 assert_eq!(clear(ClearableUpdateFlags::default()), 0x00);
144 }
145
146 #[pollster::test]
149 async fn read_ltp_requests_maps_each_lane() {
150 let mut scdc = scdc_with(&[(0x41, 0x65), (0x42, 0x87)]);
151 assert_eq!(
152 ScdcClient::read_ltp_requests(&mut scdc).await.unwrap(),
153 LtpRequests::new(LtpReq::Lfsr0, LtpReq::Lfsr1, LtpReq::Lfsr2, LtpReq::Lfsr3)
154 );
155 }
156
157 #[pollster::test]
158 async fn read_ltp_requests_maps_every_request_value() {
159 let cases = [
160 (0x0, LtpReq::None),
161 (0x1, LtpReq::AllOnes),
162 (0x2, LtpReq::AllZeros),
163 (0x3, LtpReq::NyquistClock),
164 (0x4, LtpReq::DdeCompliance),
165 (0x5, LtpReq::Lfsr0),
166 (0x6, LtpReq::Lfsr1),
167 (0x7, LtpReq::Lfsr2),
168 (0x8, LtpReq::Lfsr3),
169 (0xE, LtpReq::FfeChange),
170 (0xF, LtpReq::RateChange),
171 ];
172 for (nibble, expected) in cases {
173 let requests = ScdcClient::read_ltp_requests(&mut scdc_with(&[(0x41, nibble)]))
174 .await
175 .unwrap();
176 assert_eq!(requests.lane0, expected, "{nibble:#x}");
177 }
178 }
179
180 #[pollster::test]
181 async fn read_ltp_requests_passes_undefined_values_on() {
182 let requests = ScdcClient::read_ltp_requests(&mut scdc_with(&[(0x42, 0x90)]))
183 .await
184 .unwrap();
185 assert_eq!(requests.lane3, LtpReq::Reserved(0x9));
186 assert_eq!(requests.lane2, LtpReq::None);
187 }
188
189 #[pollster::test]
192 async fn read_source_test_config_maps_every_bit() {
193 let read = |byte| {
194 pollster::block_on(ScdcClient::read_source_test_config(&mut scdc_with(&[(
195 0x35, byte,
196 )])))
197 .unwrap()
198 };
199 for (n, bit) in [1, 2, 3, 5, 6, 7].into_iter().enumerate() {
201 let b = |i| i == n;
202 let expected = SourceTestConfig::new(b(0), b(1), b(2), b(3), b(4), b(5));
203 assert_eq!(read(1 << bit), expected, "bit {bit}");
204 }
205 assert_eq!(read(0x11), SourceTestConfig::default());
206 }
207
208 #[pollster::test]
211 async fn write_config_0_defaults_clears_config_0() {
212 let mut scdc = scdc_with(&[(0x30, 0xFF)]);
213 ScdcClient::write_config_0_defaults(&mut scdc)
214 .await
215 .unwrap();
216 assert_eq!(scdc.into_transport().get(0x30), 0x00);
217 }
218
219 #[pollster::test]
222 async fn write_frl_config_encodes_rate_and_ffe_levels() {
223 let mut scdc = Scdc::new(TestTransport::new());
224 ScdcClient::write_frl_config(
225 &mut scdc,
226 FrlConfig::new(HdmiForumFrl::Rate12Gbps4Lanes, FfeLevels::new(3).unwrap()),
227 )
228 .await
229 .unwrap();
230 assert_eq!(scdc.into_transport().get(0x31), 0x36);
231 }
232
233 #[pollster::test]
234 async fn write_frl_config_turns_frl_off() {
235 let mut scdc = scdc_with(&[(0x31, 0x36)]);
236 ScdcClient::write_frl_config(
237 &mut scdc,
238 FrlConfig::new(HdmiForumFrl::NotSupported, FfeLevels::default()),
239 )
240 .await
241 .unwrap();
242 assert_eq!(scdc.into_transport().get(0x31), 0x00);
243 }
244
245 #[pollster::test]
246 async fn write_frl_config_keeps_culverts_rate_check() {
247 let mut scdc = Scdc::new(TestTransport::new());
249 let result = ScdcClient::write_frl_config(
250 &mut scdc,
251 FrlConfig::new(HdmiForumFrl::Rate6Gbps4Lanes, FfeLevels::MAX),
252 )
253 .await;
254 assert!(matches!(
255 result,
256 Err(ScdcError::Protocol(ProtocolError::FfeLevelsOutOfRange {
257 levels: 7,
258 ..
259 }))
260 ));
261 }
262
263 #[pollster::test]
266 async fn read_ced_maps_each_lane() {
267 let mut scdc = scdc_with(&[
268 (0x50, 0x34),
269 (0x51, 0x92),
270 (0x52, 0x01),
271 (0x53, 0x00),
272 (0x54, 0xFF),
273 (0x55, 0xFF),
274 (0x57, 0x00),
275 (0x58, 0x80),
276 ]);
277 let ced = ScdcClient::read_ced(&mut scdc).await.unwrap();
278 assert_eq!(ced.lane0.map(|c| c.value()), Some(0x1234));
279 assert_eq!(ced.lane1, None);
280 assert_eq!(ced.lane2.map(|c| c.value()), Some(0x7FFF));
281 assert_eq!(ced.lane3.map(|c| c.value()), Some(0));
282 }
283
284 #[pollster::test]
287 async fn transport_errors_are_returned() {
288 let fails = || Scdc::new(TestTransport::failing_after(0));
289 assert!(matches!(
290 ScdcClient::read_flt_ready(&mut fails()).await,
291 Err(ScdcError::Transport(()))
292 ));
293 assert!(
294 ScdcClient::read_update_flags(&mut fails())
295 .await
296 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
297 );
298 assert!(
299 ScdcClient::clear_update_flags(&mut fails(), ClearableUpdateFlags::default())
300 .await
301 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
302 );
303 assert!(
304 ScdcClient::read_ltp_requests(&mut fails())
305 .await
306 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
307 );
308 assert!(
309 ScdcClient::read_source_test_config(&mut fails())
310 .await
311 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
312 );
313 assert!(
314 ScdcClient::write_config_0_defaults(&mut fails())
315 .await
316 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
317 );
318 assert!(
319 ScdcClient::write_frl_config(
320 &mut fails(),
321 FrlConfig::new(HdmiForumFrl::Rate6Gbps4Lanes, FfeLevels::default())
322 )
323 .await
324 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
325 );
326 assert!(
327 ScdcClient::read_ced(&mut fails())
328 .await
329 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
330 );
331 }
332}