culvert_async/client/
frl.rs1use hdmi_hal_async::scdc::ScdcTransport;
2
3use crate::{FrlConfig, LtpReq, ProtocolError, ScdcError, StatusFlags};
4
5use super::Scdc;
6use super::address;
7
8impl<T: ScdcTransport> Scdc<T> {
9 pub async fn write_frl_config(&mut self, config: FrlConfig) -> Result<(), ScdcError<T::Error>> {
14 let byte = (config.frl_rate as u8)
15 | ((config.dsc_frl_max as u8) << 4)
16 | ((config.ffe_levels as u8) << 5);
17 self.transport
18 .write(address::CONFIG_0, byte)
19 .await
20 .map_err(ScdcError::Transport)
21 }
22
23 pub async fn read_status_flags(&mut self) -> Result<StatusFlags, ScdcError<T::Error>> {
28 let flags0 = self
29 .transport
30 .read(address::STATUS_FLAGS_0)
31 .await
32 .map_err(ScdcError::Transport)?;
33 let flags1 = self
34 .transport
35 .read(address::STATUS_FLAGS_1)
36 .await
37 .map_err(ScdcError::Transport)?;
38
39 let ltp_req = match (flags1 >> 4) & 0x0F {
40 0 => LtpReq::None,
41 1 => LtpReq::Lfsr0,
42 2 => LtpReq::Lfsr1,
43 3 => LtpReq::Lfsr2,
44 4 => LtpReq::Lfsr3,
45 raw => return Err(ScdcError::Protocol(ProtocolError::UnknownLtpReq(raw))),
46 };
47
48 Ok(StatusFlags::new(
49 flags0 & 0x01 != 0,
50 flags0 & 0x02 != 0,
51 flags0 & 0x04 != 0,
52 flags0 & 0x08 != 0,
53 flags0 & 0x10 != 0,
54 flags0 & 0x20 != 0,
55 flags0 & 0x40 != 0,
56 flags1 & 0x01 != 0,
57 ltp_req,
58 ))
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::super::Scdc;
65 use super::super::test_transport::TestTransport;
66 use crate::{FfeLevels, FrlConfig, FrlRate, LtpReq, ProtocolError, ScdcError, StatusFlags};
67
68 #[pollster::test]
69 async fn frl_config_rate_field() {
70 let mut scdc = Scdc::new(TestTransport::new());
71 scdc.write_frl_config(FrlConfig {
72 frl_rate: FrlRate::Rate12Gbps4Lanes, dsc_frl_max: false,
74 ffe_levels: FfeLevels::Ffe0,
75 })
76 .await
77 .unwrap();
78 assert_eq!(scdc.into_transport().get(0x30), 0x06);
79 }
80
81 #[pollster::test]
82 async fn frl_config_dsc_frl_max_field() {
83 let mut scdc = Scdc::new(TestTransport::new());
84 scdc.write_frl_config(FrlConfig {
85 frl_rate: FrlRate::NotSupported,
86 dsc_frl_max: true,
87 ffe_levels: FfeLevels::Ffe0,
88 })
89 .await
90 .unwrap();
91 assert_eq!(scdc.into_transport().get(0x30), 0x10);
92 }
93
94 #[pollster::test]
95 async fn frl_config_ffe_levels_field() {
96 let mut scdc = Scdc::new(TestTransport::new());
97 scdc.write_frl_config(FrlConfig {
98 frl_rate: FrlRate::NotSupported,
99 dsc_frl_max: false,
100 ffe_levels: FfeLevels::Ffe7, })
102 .await
103 .unwrap();
104 assert_eq!(scdc.into_transport().get(0x30), 0xE0);
105 }
106
107 #[pollster::test]
108 async fn status_flags_all_zero() {
109 let mut scdc = Scdc::new(TestTransport::new());
110 assert_eq!(
111 scdc.read_status_flags().await.unwrap(),
112 StatusFlags::new(
113 false,
114 false,
115 false,
116 false,
117 false,
118 false,
119 false,
120 false,
121 LtpReq::None
122 )
123 );
124 }
125
126 #[pollster::test]
127 async fn status_flags_ltp_req_variants() {
128 for (nibble, expected) in [
129 (0u8, LtpReq::None),
130 (1, LtpReq::Lfsr0),
131 (2, LtpReq::Lfsr1),
132 (3, LtpReq::Lfsr2),
133 (4, LtpReq::Lfsr3),
134 ] {
135 let mut sim = TestTransport::new();
136 sim.set(0x41, nibble << 4);
137 assert_eq!(
138 Scdc::new(sim).read_status_flags().await.unwrap().ltp_req,
139 expected
140 );
141 }
142 }
143
144 #[pollster::test]
145 async fn status_flags_unknown_ltp_req() {
146 for nibble in 5u8..=15 {
147 let mut sim = TestTransport::new();
148 sim.set(0x41, nibble << 4);
149 assert!(matches!(
150 Scdc::new(sim).read_status_flags().await,
151 Err(ScdcError::Protocol(ProtocolError::UnknownLtpReq(n))) if n == nibble
152 ));
153 }
154 }
155
156 #[pollster::test]
157 async fn status_flags_all_flags0_bits_set() {
158 let mut sim = TestTransport::new();
159 sim.set(0x40, 0x7F); sim.set(0x41, 0x01); let f = Scdc::new(sim).read_status_flags().await.unwrap();
162 assert!(f.clock_detected && f.cable_connected);
163 assert!(f.ch0_locked && f.ch1_locked && f.ch2_locked && f.ch3_locked);
164 assert!(f.flt_ready && f.frl_start);
165 assert_eq!(f.ltp_req, LtpReq::None);
166 }
167
168 #[pollster::test]
169 async fn transport_error_propagates() {
170 assert!(
171 Scdc::new(TestTransport::failing_after(0))
172 .write_frl_config(FrlConfig {
173 frl_rate: FrlRate::NotSupported,
174 dsc_frl_max: false,
175 ffe_levels: FfeLevels::Ffe0,
176 })
177 .await
178 .is_err()
179 );
180 assert!(
182 Scdc::new(TestTransport::failing_after(0))
183 .read_status_flags()
184 .await
185 .is_err()
186 );
187 assert!(
189 Scdc::new(TestTransport::failing_after(1))
190 .read_status_flags()
191 .await
192 .is_err()
193 );
194 }
195}