culvert_async/client/
ced.rs1use hdmi_hal_async::scdc::ScdcTransport;
2
3use crate::ScdcError;
4use crate::{CedCounters, RsCorrectionCount};
5use culvert::codec;
6
7use super::Scdc;
8
9impl<T: ScdcTransport> Scdc<T> {
10 pub async fn read_ced(&mut self) -> Result<CedCounters, ScdcError<T::Error>> {
20 let mut bytes = [0; 8];
21 for (byte, reg) in bytes.iter_mut().zip(codec::CED_REGISTERS) {
22 *byte = self
23 .transport
24 .read(reg)
25 .await
26 .map_err(ScdcError::Transport)?;
27 }
28 Ok(codec::decode_ced(bytes))
29 }
30
31 pub async fn read_rs_correction(
39 &mut self,
40 ) -> Result<Option<RsCorrectionCount>, ScdcError<T::Error>> {
41 let low = self
42 .transport
43 .read(codec::RS_CORRECTION_L)
44 .await
45 .map_err(ScdcError::Transport)?;
46 let high = self
47 .transport
48 .read(codec::RS_CORRECTION_H)
49 .await
50 .map_err(ScdcError::Transport)?;
51 Ok(codec::decode_rs_correction(low, high))
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::super::Scdc;
58 use super::super::test_transport::{Op, TestTransport};
59 use crate::CedCount;
60 use crate::ScdcError;
61
62 #[pollster::test]
63 async fn ced_validity_bit_required() {
64 let mut sim = TestTransport::new();
66 sim.set(0x50, 0xFF);
67 sim.set(0x51, 0x7F); let ced = Scdc::new(sim).read_ced().await.unwrap();
69 assert_eq!(ced.lane0, None);
70 }
71
72 #[pollster::test]
73 async fn ced_counter_validity_bit_stripped() {
74 let mut sim = TestTransport::new();
76 sim.set(0x50, 0x23);
77 sim.set(0x51, 0x81);
78 let ced = Scdc::new(sim).read_ced().await.unwrap();
79 assert_eq!(ced.lane0, Some(CedCount::new(0x0123)));
80 }
81
82 #[pollster::test]
83 async fn ced_lane3_independent() {
84 let mut sim = TestTransport::new();
85 sim.set(0x56, 0xAA); sim.set(0x57, 0x01);
87 sim.set(0x58, 0x80); let ced = Scdc::new(sim).read_ced().await.unwrap();
89 assert_eq!(ced.lane0, None);
90 assert_eq!(ced.lane3.map(|c| c.value()), Some(0x0001));
91 }
92
93 #[pollster::test]
94 async fn read_ced_reads_each_counter_register_once_in_order() {
95 let mut scdc = Scdc::new(TestTransport::new());
96 scdc.read_ced().await.unwrap();
97 let reads = [0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x57, 0x58].map(|r| Some(Op::Read(r)));
99 let log = scdc.into_transport().log();
100 assert_eq!(log[..8], reads);
101 assert_eq!(log[8], None);
102 }
103
104 #[pollster::test]
105 async fn read_rs_correction_reads_low_then_high() {
106 let mut scdc = Scdc::new(TestTransport::new());
107 scdc.read_rs_correction().await.unwrap();
108 assert_eq!(
109 scdc.into_transport().log()[..3],
110 [Some(Op::Read(0x59)), Some(Op::Read(0x5A)), None]
111 );
112 }
113
114 #[pollster::test]
115 async fn ced_each_lane_from_its_own_registers() {
116 let mut sim = TestTransport::new();
118 for (low, value) in [(0x50, 0x02), (0x52, 0x04), (0x54, 0x06)] {
119 sim.set(low, value);
120 sim.set(low + 1, 0x80 | (value + 1));
121 }
122 sim.set(0x56, 0xFF); sim.set(0x57, 0x08);
124 sim.set(0x58, 0x89);
125 let ced = Scdc::new(sim).read_ced().await.unwrap();
126 assert_eq!(ced.lane0.map(|c| c.value()), Some(0x0302));
127 assert_eq!(ced.lane1.map(|c| c.value()), Some(0x0504));
128 assert_eq!(ced.lane2.map(|c| c.value()), Some(0x0706));
129 assert_eq!(ced.lane3.map(|c| c.value()), Some(0x0908));
130 }
131
132 #[pollster::test]
133 async fn transport_error_on_any_read() {
134 for n in 0..8 {
135 assert!(
136 Scdc::new(TestTransport::failing_after(n))
137 .read_ced()
138 .await
139 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
140 );
141 }
142 }
143
144 #[pollster::test]
145 async fn rs_correction_valid_and_invalid() {
146 let mut sim = TestTransport::new();
147 sim.set(0x59, 0x34);
148 sim.set(0x5A, 0x81); assert_eq!(
150 Scdc::new(sim)
151 .read_rs_correction()
152 .await
153 .unwrap()
154 .map(|c| c.value()),
155 Some(0x0134)
156 );
157
158 let mut sim = TestTransport::new();
159 sim.set(0x59, 0xFF);
160 sim.set(0x5A, 0x7F); assert_eq!(Scdc::new(sim).read_rs_correction().await.unwrap(), None);
162 }
163
164 #[pollster::test]
165 async fn rs_correction_transport_error() {
166 for n in 0..2 {
167 assert!(
168 Scdc::new(TestTransport::failing_after(n))
169 .read_rs_correction()
170 .await
171 .is_err_and(|error| matches!(error, ScdcError::Transport(())))
172 );
173 }
174 }
175}