Skip to main content

culvert_async/client/
update.rs

1use hdmi_hal_async::scdc::ScdcTransport;
2
3use crate::ScdcError;
4use crate::{ClearableUpdateFlags, UpdateFlags};
5use culvert::codec;
6
7use super::Scdc;
8
9impl<T: ScdcTransport> Scdc<T> {
10    /// Reads update flags from `Update_0` (0x10).
11    pub async fn read_update_flags(&mut self) -> Result<UpdateFlags, ScdcError<T::Error>> {
12        let update_0 = self
13            .transport
14            .read(codec::UPDATE_0)
15            .await
16            .map_err(ScdcError::Transport)?;
17        Ok(codec::decode_update_flags(update_0))
18    }
19
20    /// Clears the specified update flags in `Update_0` (0x10).
21    ///
22    /// Each flag set to `true` in `flags` is cleared (write-1-to-clear). Flags
23    /// set to `false` are left unchanged, and so is `RR_Test`, which the source does not
24    /// clear ([`ClearableUpdateFlags`] has no field for it). To acknowledge every flag just
25    /// read, pass [`UpdateFlags::clearable`].
26    pub async fn clear_update_flags(
27        &mut self,
28        flags: ClearableUpdateFlags,
29    ) -> Result<(), ScdcError<T::Error>> {
30        let byte = codec::encode_clear_update_flags(flags);
31        self.transport
32            .write(codec::UPDATE_0, byte)
33            .await
34            .map_err(ScdcError::Transport)
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::super::Scdc;
41    use super::super::test_transport::{Op, TestTransport};
42    use crate::ScdcError;
43    use crate::{ClearableUpdateFlags, UpdateFlags};
44
45    fn read(byte: u8) -> UpdateFlags {
46        let mut sim = TestTransport::new();
47        sim.set(0x10, byte);
48        pollster::block_on(Scdc::new(sim).read_update_flags()).unwrap()
49    }
50
51    #[pollster::test]
52    async fn update_flags_individual_bits() {
53        assert!(read(0x01).status_update);
54        assert!(read(0x02).ced_update);
55        assert!(read(0x04).rr_test);
56        assert!(read(0x08).source_test_update);
57        assert!(read(0x10).frl_start);
58        assert!(read(0x20).flt_update);
59        assert!(read(0x40).rsed_update);
60        assert_eq!(
61            read(0x00),
62            UpdateFlags::new(false, false, false, false, false, false, false)
63        );
64    }
65
66    #[pollster::test]
67    async fn update_1_is_not_read() {
68        let mut sim = TestTransport::new();
69        sim.set(0x11, 0xFF);
70        assert_eq!(
71            Scdc::new(sim).read_update_flags().await.unwrap(),
72            UpdateFlags::new(false, false, false, false, false, false, false)
73        );
74    }
75
76    #[pollster::test]
77    async fn clear_update_flags_w1c() {
78        let mut scdc = Scdc::new(TestTransport::new());
79        scdc.clear_update_flags(ClearableUpdateFlags::new(
80            true, true, true, true, true, true,
81        ))
82        .await
83        .unwrap();
84        let t = scdc.into_transport();
85        assert_eq!(t.get(0x10), 0x7B); // every flag except RR_Test (bit 2)
86        assert_eq!(t.get(0x11), 0x00);
87    }
88
89    #[pollster::test]
90    async fn read_then_clear_acknowledges_every_flag_but_rr_test() {
91        // A sink under read-request test keeps RR_Test set; clearing what was read must
92        // still acknowledge the other flags.
93        let mut sim = TestTransport::new();
94        sim.set(0x10, 0x24); // RR_Test | FLT_update
95        let mut scdc = Scdc::new(sim);
96        let flags = scdc.read_update_flags().await.unwrap();
97        assert!(flags.rr_test && flags.flt_update);
98        scdc.clear_update_flags(flags.clearable()).await.unwrap();
99        assert_eq!(scdc.into_transport().get(0x10), 0x20);
100    }
101
102    #[pollster::test]
103    async fn clear_update_flags_partial() {
104        let mut scdc = Scdc::new(TestTransport::new());
105        // Clear only flt_update, as the training loop does after reading LTP requests.
106        scdc.clear_update_flags(ClearableUpdateFlags::new(
107            false, false, false, false, true, false,
108        ))
109        .await
110        .unwrap();
111        assert_eq!(scdc.into_transport().get(0x10), 0x20);
112    }
113
114    #[pollster::test]
115    async fn clear_update_flags_is_one_write() {
116        let mut scdc = Scdc::new(TestTransport::new());
117        scdc.clear_update_flags(ClearableUpdateFlags::new(
118            false, false, false, true, true, false,
119        ))
120        .await
121        .unwrap();
122        assert_eq!(
123            scdc.into_transport().log()[..2],
124            [Some(Op::Write(0x10, 0x30)), None]
125        );
126    }
127
128    #[pollster::test]
129    async fn transport_error_propagates() {
130        assert!(
131            Scdc::new(TestTransport::failing_after(0))
132                .read_update_flags()
133                .await
134                .is_err_and(|error| matches!(error, ScdcError::Transport(())))
135        );
136        assert!(
137            Scdc::new(TestTransport::failing_after(0))
138                .clear_update_flags(ClearableUpdateFlags::default())
139                .await
140                .is_err_and(|error| matches!(error, ScdcError::Transport(())))
141        );
142    }
143}