1pub trait ScdcTransport {
14 type Error;
16
17 async fn read(&self, reg: u8) -> Result<u8, Self::Error>;
19
20 async fn write(&mut self, reg: u8, value: u8) -> Result<(), Self::Error>;
22
23 async fn read_block(&self, reg: u8, buf: &mut [u8]) -> Result<(), Self::Error> {
32 let mut addr = reg;
33 for byte in buf {
34 *byte = self.read(addr).await?;
35 addr = addr.wrapping_add(1);
36 }
37 Ok(())
38 }
39}
40
41pub trait SendScdcTransport: Send + Sync {
62 type Error: Send;
64
65 fn read(&self, reg: u8) -> impl Future<Output = Result<u8, Self::Error>> + Send;
67
68 fn write(&mut self, reg: u8, value: u8)
70 -> impl Future<Output = Result<(), Self::Error>> + Send;
71
72 fn read_block(
75 &self,
76 reg: u8,
77 buf: &mut [u8],
78 ) -> impl Future<Output = Result<(), Self::Error>> + Send {
79 async move {
80 let mut addr = reg;
81 for byte in buf {
82 *byte = self.read(addr).await?;
83 addr = addr.wrapping_add(1);
84 }
85 Ok(())
86 }
87 }
88}
89
90impl<T: SendScdcTransport> ScdcTransport for T {
91 type Error = <T as SendScdcTransport>::Error;
92
93 fn read(&self, reg: u8) -> impl Future<Output = Result<u8, Self::Error>> {
94 <T as SendScdcTransport>::read(self, reg)
95 }
96
97 fn write(&mut self, reg: u8, value: u8) -> impl Future<Output = Result<(), Self::Error>> {
98 <T as SendScdcTransport>::write(self, reg, value)
99 }
100
101 fn read_block(&self, reg: u8, buf: &mut [u8]) -> impl Future<Output = Result<(), Self::Error>> {
102 <T as SendScdcTransport>::read_block(self, reg, buf)
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use core::cell::Cell;
110 use core::sync::atomic::{AtomicU32, Ordering};
111
112 struct MockTransport {
113 registers: [u8; 256],
114 reads: Cell<u32>,
115 fail_at: Option<u8>,
116 }
117
118 impl MockTransport {
119 fn new() -> Self {
120 Self {
121 registers: [0u8; 256],
122 reads: Cell::new(0),
123 fail_at: None,
124 }
125 }
126
127 fn filled() -> Self {
129 let mut t = Self::new();
130 for (i, r) in t.registers.iter_mut().enumerate() {
131 *r = i as u8;
132 }
133 t
134 }
135 }
136
137 impl ScdcTransport for MockTransport {
138 type Error = u8;
139
140 async fn read(&self, reg: u8) -> Result<u8, Self::Error> {
141 if self.fail_at == Some(reg) {
142 return Err(reg);
143 }
144 self.reads.set(self.reads.get() + 1);
145 Ok(self.registers[reg as usize])
146 }
147
148 async fn write(&mut self, reg: u8, value: u8) -> Result<(), Self::Error> {
149 self.registers[reg as usize] = value;
150 Ok(())
151 }
152 }
153
154 #[pollster::test]
155 async fn write_then_read_returns_written_value() {
156 let mut t = MockTransport::new();
157 t.write(0x20, 0xAB).await.unwrap();
158 assert_eq!(t.read(0x20).await.unwrap(), 0xAB);
159 }
160
161 #[pollster::test]
162 async fn unwritten_register_reads_zero() {
163 let t = MockTransport::new();
164 assert_eq!(t.read(0x31).await.unwrap(), 0x00);
165 }
166
167 #[pollster::test]
168 async fn write_is_register_specific() {
169 let mut t = MockTransport::new();
170 t.write(0x01, 0xFF).await.unwrap();
171 assert_eq!(t.read(0x00).await.unwrap(), 0x00);
172 assert_eq!(t.read(0x02).await.unwrap(), 0x00);
173 }
174
175 #[pollster::test]
176 async fn write_overwrites_previous_value() {
177 let mut t = MockTransport::new();
178 t.write(0x20, 0x01).await.unwrap();
179 t.write(0x20, 0x02).await.unwrap();
180 assert_eq!(t.read(0x20).await.unwrap(), 0x02);
181 }
182
183 #[pollster::test]
184 async fn read_block_reads_consecutive_registers() {
185 let t = MockTransport::filled();
186 let mut buf = [0u8; 3];
187 t.read_block(0x40, &mut buf).await.unwrap();
188 assert_eq!(buf, [0x40, 0x41, 0x42]);
189 assert_eq!(t.reads.get(), 3);
190 }
191
192 #[pollster::test]
193 async fn read_block_empty_buffer_reads_nothing() {
194 let t = MockTransport::filled();
195 t.read_block(0x40, &mut []).await.unwrap();
196 assert_eq!(t.reads.get(), 0);
197 }
198
199 #[pollster::test]
200 async fn read_block_stops_at_first_error() {
201 let mut t = MockTransport::filled();
202 t.fail_at = Some(0x41);
203 let mut buf = [0u8; 3];
204 assert_eq!(t.read_block(0x40, &mut buf).await, Err(0x41));
205 assert_eq!(buf, [0x40, 0x00, 0x00]);
206 assert_eq!(t.reads.get(), 1);
207 }
208
209 #[pollster::test]
210 async fn read_block_wraps_past_0xff() {
211 let t = MockTransport::filled();
212 let mut buf = [0u8; 2];
213 t.read_block(0xFF, &mut buf).await.unwrap();
214 assert_eq!(buf, [0xFF, 0x00]);
215 }
216
217 #[pollster::test]
218 async fn write_then_read_block() {
219 let mut t = MockTransport::new();
220 t.write(0x20, 0xAB).await.unwrap();
221 let mut buf = [0u8; 1];
222 t.read_block(0x20, &mut buf).await.unwrap();
223 assert_eq!(buf, [0xAB]);
224 }
225
226 struct SendMockTransport {
229 registers: [u8; 256],
230 reads: AtomicU32,
231 fail_at: Option<u8>,
232 }
233
234 impl SendMockTransport {
235 fn filled() -> Self {
236 let mut registers = [0u8; 256];
237 for (i, r) in registers.iter_mut().enumerate() {
238 *r = i as u8;
239 }
240 Self {
241 registers,
242 reads: AtomicU32::new(0),
243 fail_at: None,
244 }
245 }
246
247 fn reads(&self) -> u32 {
248 self.reads.load(Ordering::Relaxed)
249 }
250 }
251
252 impl SendScdcTransport for SendMockTransport {
253 type Error = u8;
254
255 async fn read(&self, reg: u8) -> Result<u8, Self::Error> {
256 if self.fail_at == Some(reg) {
257 return Err(reg);
258 }
259 self.reads.fetch_add(1, Ordering::Relaxed);
260 Ok(self.registers[reg as usize])
261 }
262
263 async fn write(&mut self, reg: u8, value: u8) -> Result<(), Self::Error> {
264 self.registers[reg as usize] = value;
265 Ok(())
266 }
267 }
268
269 struct BlockReadingTransport;
272
273 impl SendScdcTransport for BlockReadingTransport {
274 type Error = ();
275
276 async fn read(&self, _reg: u8) -> Result<u8, Self::Error> {
277 Err(())
278 }
279
280 async fn write(&mut self, _reg: u8, _value: u8) -> Result<(), Self::Error> {
281 Err(())
282 }
283
284 async fn read_block(&self, reg: u8, buf: &mut [u8]) -> Result<(), Self::Error> {
285 buf.fill(reg);
286 Ok(())
287 }
288 }
289
290 async fn round_trip_plain<T: ScdcTransport>(
293 t: &mut T,
294 buf: &mut [u8],
295 ) -> (
296 Result<(), T::Error>,
297 Result<u8, T::Error>,
298 Result<(), T::Error>,
299 ) {
300 let written = t.write(0x20, 0xAB).await;
301 let read = t.read(0x20).await;
302 let block = t.read_block(0x20, buf).await;
303 (written, read, block)
304 }
305
306 fn spawnable<'a, T: SendScdcTransport>(
309 t: &'a T,
310 buf: &'a mut [u8],
311 ) -> impl Future<Output = Result<(), T::Error>> + Send + 'a {
312 SendScdcTransport::read_block(t, 0x40, buf)
313 }
314
315 fn assert_send<T: Send>(value: T) -> T {
316 value
317 }
318
319 #[pollster::test]
320 async fn send_twin_is_usable_as_scdc_transport() {
321 let mut t = SendMockTransport::filled();
322 let mut buf = [0u8; 2];
323 let (written, read, block) = round_trip_plain(&mut t, &mut buf).await;
324 assert_eq!((written, read, block), (Ok(()), Ok(0xAB), Ok(())));
325 assert_eq!(buf, [0xAB, 0x21]);
326 assert_eq!(t.reads(), 3);
327 }
328
329 #[pollster::test]
330 async fn send_twin_futures_are_send_in_generic_code() {
331 let t = SendMockTransport::filled();
332 let mut buf = [0u8; 3];
333 assert_send(spawnable(&t, &mut buf)).await.unwrap();
334 assert_eq!(buf, [0x40, 0x41, 0x42]);
335 }
336
337 #[pollster::test]
338 async fn send_twin_default_read_block_stops_at_first_error() {
339 let mut t = SendMockTransport::filled();
340 t.fail_at = Some(0x41);
341 let mut buf = [0u8; 3];
342 assert_eq!(
343 SendScdcTransport::read_block(&t, 0x40, &mut buf).await,
344 Err(0x41)
345 );
346 assert_eq!(buf, [0x40, 0x00, 0x00]);
347 assert_eq!(t.reads(), 1);
348 }
349
350 #[pollster::test]
351 async fn send_twin_default_read_block_wraps_past_0xff() {
352 let t = SendMockTransport::filled();
353 let mut buf = [0u8; 2];
354 SendScdcTransport::read_block(&t, 0xFF, &mut buf)
355 .await
356 .unwrap();
357 assert_eq!(buf, [0xFF, 0x00]);
358 }
359
360 #[pollster::test]
361 async fn send_twin_read_block_override_is_used_through_scdc_transport() {
362 let mut t = BlockReadingTransport;
363 let mut buf = [0u8; 2];
364 let (written, read, block) = round_trip_plain(&mut t, &mut buf).await;
365 assert_eq!((written, read, block), (Err(()), Err(()), Ok(())));
366 assert_eq!(buf, [0x20, 0x20]);
367 }
368}