Skip to main content

culvert_async/client/
ced.rs

1use hdmi_hal_async::scdc::ScdcTransport;
2
3use crate::{CedCount, CedCounters, ScdcError};
4
5use super::Scdc;
6use super::address;
7
8impl<T: ScdcTransport> Scdc<T> {
9    /// Reads per-lane character error counts from `ERR_DET` registers (0x50–0x57).
10    ///
11    /// Each lane's counter is decoded from a low/high byte pair. The high byte's
12    /// bit 7 is a validity flag; if it is not set the lane's counter is `None`.
13    pub async fn read_ced(&mut self) -> Result<CedCounters, ScdcError<T::Error>> {
14        let l0 = self
15            .transport
16            .read(address::ERR_DET_0_L)
17            .await
18            .map_err(ScdcError::Transport)?;
19        let h0 = self
20            .transport
21            .read(address::ERR_DET_0_H)
22            .await
23            .map_err(ScdcError::Transport)?;
24        let l1 = self
25            .transport
26            .read(address::ERR_DET_1_L)
27            .await
28            .map_err(ScdcError::Transport)?;
29        let h1 = self
30            .transport
31            .read(address::ERR_DET_1_H)
32            .await
33            .map_err(ScdcError::Transport)?;
34        let l2 = self
35            .transport
36            .read(address::ERR_DET_2_L)
37            .await
38            .map_err(ScdcError::Transport)?;
39        let h2 = self
40            .transport
41            .read(address::ERR_DET_2_H)
42            .await
43            .map_err(ScdcError::Transport)?;
44        let l3 = self
45            .transport
46            .read(address::ERR_DET_3_L)
47            .await
48            .map_err(ScdcError::Transport)?;
49        let h3 = self
50            .transport
51            .read(address::ERR_DET_3_H)
52            .await
53            .map_err(ScdcError::Transport)?;
54
55        let decode = |lo: u8, hi: u8| -> Option<CedCount> {
56            (hi & 0x80 != 0).then(|| CedCount::new(((hi as u16) << 8) | lo as u16))
57        };
58
59        Ok(CedCounters::new(
60            decode(l0, h0),
61            decode(l1, h1),
62            decode(l2, h2),
63            decode(l3, h3),
64        ))
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::super::Scdc;
71    use super::super::test_transport::TestTransport;
72    use crate::CedCount;
73
74    #[pollster::test]
75    async fn ced_validity_bit_required() {
76        // High byte with bit 7 clear → None regardless of counter value.
77        let mut sim = TestTransport::new();
78        sim.set(0x50, 0xFF);
79        sim.set(0x51, 0x7F); // validity bit clear
80        let ced = Scdc::new(sim).read_ced().await.unwrap();
81        assert_eq!(ced.lane0, None);
82    }
83
84    #[pollster::test]
85    async fn ced_counter_validity_bit_stripped() {
86        // High byte: bit 7 set (valid), counter bits = 0x01; low byte = 0x23.
87        let mut sim = TestTransport::new();
88        sim.set(0x50, 0x23);
89        sim.set(0x51, 0x81);
90        let ced = Scdc::new(sim).read_ced().await.unwrap();
91        assert_eq!(ced.lane0, Some(CedCount::new(0x0123)));
92    }
93
94    #[pollster::test]
95    async fn ced_lane3_independent() {
96        let mut sim = TestTransport::new();
97        sim.set(0x56, 0x01);
98        sim.set(0x57, 0x80); // lane3 valid, count = 1
99        let ced = Scdc::new(sim).read_ced().await.unwrap();
100        assert_eq!(ced.lane0, None);
101        assert_eq!(ced.lane3.map(|c| c.value()), Some(0x0001));
102    }
103
104    #[pollster::test]
105    async fn transport_error_on_any_read() {
106        for n in 0..8 {
107            assert!(
108                Scdc::new(TestTransport::failing_after(n))
109                    .read_ced()
110                    .await
111                    .is_err()
112            );
113        }
114    }
115}