driver_pal/
mock.rs

1use std::sync::{Arc, Mutex};
2use std::vec;
3use std::vec::Vec;
4
5use crate::{Busy, PinState, Ready, Reset};
6
7use embedded_hal::spi::Operation as SpiOperation;
8
9#[derive(Clone, Debug)]
10pub struct PinError;
11
12impl embedded_hal::digital::Error for PinError {
13    fn kind(&self) -> embedded_hal::digital::ErrorKind {
14        embedded_hal::digital::ErrorKind::Other
15    }
16}
17
18#[derive(Clone, Debug)]
19pub struct SpiError;
20
21#[derive(Clone, Debug)]
22pub struct MockError {}
23impl embedded_hal::spi::Error for MockError {
24    fn kind(&self) -> embedded_hal::spi::ErrorKind {
25        embedded_hal::spi::ErrorKind::Other
26    }
27}
28
29/// Base mock type
30pub struct Mock {
31    inner: Arc<Mutex<Inner>>,
32    count: Id,
33}
34
35pub type Id = u32;
36
37/// Mock Transactional SPI implementation
38#[derive(Clone, Debug)]
39pub struct Spi {
40    id: Id,
41    inner: Arc<Mutex<Inner>>,
42}
43
44/// Mock Pin implementation
45#[derive(Clone, Debug)]
46pub struct Pin {
47    id: Id,
48    inner: Arc<Mutex<Inner>>,
49}
50
51/// Mock Delay implementation
52#[derive(Clone, Debug)]
53pub struct Delay {
54    id: Id,
55    inner: Arc<Mutex<Inner>>,
56}
57
58/// Mock transaction type for setting and checking expectations
59#[derive(Clone, Debug, PartialEq)]
60pub enum MockTransaction {
61    None,
62
63    SpiWrite(Id, Vec<u8>, Vec<u8>),
64    SpiRead(Id, Vec<u8>, Vec<u8>),
65
66    SpiExec(Id, Vec<MockExec>),
67
68    Busy(Id, PinState),
69    Ready(Id, PinState),
70    Reset(Id, PinState),
71
72    Write(Id, Vec<u8>),
73    Transfer(Id, Vec<u8>, Vec<u8>),
74
75    IsHigh(Id, bool),
76    IsLow(Id, bool),
77    SetHigh(Id),
78    SetLow(Id),
79
80    DelayNs(u32),
81}
82
83impl MockTransaction {
84    pub fn spi_write<A, B>(spi: &Spi, prefix: A, outgoing: B) -> Self
85    where
86        A: AsRef<[u8]>,
87        B: AsRef<[u8]>,
88    {
89        MockTransaction::SpiWrite(spi.id, prefix.as_ref().to_vec(), outgoing.as_ref().to_vec())
90    }
91
92    pub fn spi_read<A, B>(spi: &Spi, prefix: A, incoming: B) -> Self
93    where
94        A: AsRef<[u8]>,
95        B: AsRef<[u8]>,
96    {
97        MockTransaction::SpiRead(spi.id, prefix.as_ref().to_vec(), incoming.as_ref().to_vec())
98    }
99
100    pub fn spi_exec<O>(spi: &Spi, o: O) -> Self
101    where
102        O: AsRef<[MockExec]>,
103    {
104        MockTransaction::SpiExec(spi.id, o.as_ref().to_vec())
105    }
106
107    pub fn busy(spi: &Spi, value: PinState) -> Self {
108        MockTransaction::Busy(spi.id, value)
109    }
110
111    pub fn ready(spi: &Spi, value: PinState) -> Self {
112        MockTransaction::Ready(spi.id, value)
113    }
114
115    pub fn reset(spi: &Spi, value: PinState) -> Self {
116        MockTransaction::Reset(spi.id, value)
117    }
118
119    pub fn delay_ms(v: u32) -> Self {
120        MockTransaction::DelayNs(v * 1000)
121    }
122
123    pub fn write<B>(spi: &Spi, outgoing: B) -> Self
124    where
125        B: AsRef<[u8]>,
126    {
127        MockTransaction::Write(spi.id, outgoing.as_ref().to_vec())
128    }
129
130    pub fn transfer<B>(spi: &Spi, outgoing: B, incoming: B) -> Self
131    where
132        B: AsRef<[u8]>,
133    {
134        MockTransaction::Transfer(
135            spi.id,
136            outgoing.as_ref().to_vec(),
137            incoming.as_ref().to_vec(),
138        )
139    }
140
141    pub fn is_high(pin: &Pin, value: bool) -> Self {
142        MockTransaction::IsHigh(pin.id, value)
143    }
144
145    pub fn is_low(pin: &Pin, value: bool) -> Self {
146        MockTransaction::IsLow(pin.id, value)
147    }
148
149    pub fn set_high(pin: &Pin) -> Self {
150        MockTransaction::SetHigh(pin.id)
151    }
152
153    pub fn set_low(pin: &Pin) -> Self {
154        MockTransaction::SetLow(pin.id)
155    }
156}
157
158/// MockExec type for composing mock exec transactions
159#[derive(Clone, Debug, PartialEq)]
160pub enum MockExec {
161    SpiWrite(Vec<u8>),
162    SpiTransfer(Vec<u8>, Vec<u8>),
163}
164
165impl<'a> From<&SpiOperation<'a, u8>> for MockExec {
166    fn from(t: &SpiOperation<'a, u8>) -> Self {
167        match t {
168            SpiOperation::Write(ref d) => MockExec::SpiWrite(d.to_vec()),
169            SpiOperation::TransferInPlace(ref d) => {
170                MockExec::SpiTransfer(d.to_vec(), vec![0u8; d.len()])
171            }
172            _ => todo!(),
173        }
174    }
175}
176
177#[derive(Clone, Debug, PartialEq)]
178struct Inner {
179    index: usize,
180    expected: Vec<MockTransaction>,
181    actual: Vec<MockTransaction>,
182}
183
184impl Inner {
185    fn finalise(&mut self) {
186        assert_eq!(self.expected, self.actual);
187    }
188}
189
190impl Mock {
191    /// Create a new mock instance
192    pub fn new() -> Self {
193        Self {
194            inner: Arc::new(Mutex::new(Inner {
195                index: 0,
196                expected: Vec::new(),
197                actual: Vec::new(),
198            })),
199            count: 0,
200        }
201    }
202
203    /// Set expectations on the instance
204    pub fn expect<T>(&mut self, transactions: T)
205    where
206        T: AsRef<[MockTransaction]>,
207    {
208        let expected: Vec<_> = transactions.as_ref().to_vec();
209        let actual = vec![];
210
211        let i = Inner {
212            index: 0,
213            expected,
214            actual,
215        };
216
217        *self.inner.lock().unwrap() = i;
218    }
219
220    pub fn spi(&mut self) -> Spi {
221        let id = self.count;
222        self.count += 1;
223        Spi {
224            inner: self.inner.clone(),
225            id,
226        }
227    }
228
229    pub fn pin(&mut self) -> Pin {
230        let id = self.count;
231        self.count += 1;
232        Pin {
233            inner: self.inner.clone(),
234            id,
235        }
236    }
237
238    pub fn delay(&mut self) -> Delay {
239        let id = self.count;
240        self.count += 1;
241        Delay {
242            inner: self.inner.clone(),
243            id,
244        }
245    }
246
247    /// Finalise expectations
248    /// This will cause previous expectations to be evaluated
249    pub fn finalise(&self) {
250        let mut i = self.inner.lock().unwrap();
251        i.finalise();
252    }
253}
254
255impl Busy for Spi {
256    type Error = PinError;
257
258    /// Check peripheral busy status
259    fn get_busy(&mut self) -> Result<PinState, Self::Error> {
260        let mut i = self.inner.lock().unwrap();
261        let index = i.index;
262
263        let state = match &i.expected.get(index) {
264            Some(MockTransaction::Busy(_id, state)) => state.clone(),
265            _ => PinState::Low,
266        };
267
268        i.actual.push(MockTransaction::Busy(self.id, state.clone()));
269
270        i.index += 1;
271
272        Ok(state)
273    }
274}
275
276impl Ready for Spi {
277    type Error = PinError;
278
279    /// Check peripheral ready status
280    fn get_ready(&mut self) -> Result<PinState, Self::Error> {
281        let mut i = self.inner.lock().unwrap();
282        let index = i.index;
283
284        let state = match &i.expected.get(index) {
285            Some(MockTransaction::Ready(_id, state)) => state.clone(),
286            _ => PinState::Low,
287        };
288
289        i.actual
290            .push(MockTransaction::Ready(self.id, state.clone()));
291
292        i.index += 1;
293
294        Ok(state)
295    }
296}
297
298impl Reset for Spi {
299    type Error = PinError;
300
301    /// Check peripheral ready status
302    fn set_reset(&mut self, state: PinState) -> Result<(), Self::Error> {
303        let mut i = self.inner.lock().unwrap();
304
305        i.actual.push(MockTransaction::Reset(self.id, state));
306
307        i.index += 1;
308
309        Ok(())
310    }
311}
312
313impl embedded_hal::delay::DelayNs for Spi {
314    fn delay_ns(&mut self, t: u32) {
315        let mut i = self.inner.lock().unwrap();
316
317        // Save actual call
318        i.actual.push(MockTransaction::DelayNs(t));
319
320        // Update expectation index
321        i.index += 1;
322    }
323}
324
325impl embedded_hal::spi::SpiDevice<u8> for Spi {
326    fn transaction(&mut self, operations: &mut [SpiOperation<'_, u8>]) -> Result<(), Self::Error> {
327        let mut i = self.inner.lock().unwrap();
328        let index = i.index;
329
330        // Save actual calls
331        let t: Vec<MockExec> = operations
332            .as_mut()
333            .iter()
334            .map(|ref v| MockExec::from(*v))
335            .collect();
336        i.actual.push(MockTransaction::SpiExec(self.id, t));
337
338        let transactions = operations.as_mut();
339
340        // Load expected reads
341        if let MockTransaction::SpiExec(_id, e) = &i.expected[index] {
342            for i in 0..transactions.len() {
343                let t = &mut transactions[i];
344                let x = e.get(i);
345
346                match (t, x) {
347                    (
348                        SpiOperation::TransferInPlace(ref mut t_in),
349                        Some(MockExec::SpiTransfer(_x_out, x_in)),
350                    ) => t_in.copy_from_slice(&x_in),
351                    (SpiOperation::Write(ref _t_out), Some(MockExec::SpiWrite(ref _x_out))) => {
352                        //assert_eq!(t_out, x_out);
353                    }
354                    _ => (),
355                }
356            }
357        }
358
359        // Update expectation index
360        i.index += 1;
361
362        Ok(())
363    }
364
365    fn write<'w>(&mut self, data: &[u8]) -> Result<(), Self::Error> {
366        let mut i = self.inner.lock().unwrap();
367
368        // Save actual call
369        i.actual.push(MockTransaction::Write(self.id, data.into()));
370
371        // Update expectation index
372        i.index += 1;
373
374        Ok(())
375    }
376    fn transfer_in_place<'w>(&mut self, data: &'w mut [u8]) -> Result<(), Self::Error> {
377        let mut i = self.inner.lock().unwrap();
378        let index = i.index;
379
380        let incoming: Vec<_> = data.into();
381
382        // Copy read data from expectation
383        match &i.expected.get(index) {
384            Some(MockTransaction::Transfer(_id, _outgoing, incoming)) => {
385                if incoming.len() == data.len() {
386                    data.copy_from_slice(&incoming);
387                }
388            }
389            _ => (),
390        };
391
392        // Save actual call
393        i.actual
394            .push(MockTransaction::Transfer(self.id, incoming, data.into()));
395
396        // Update expectation index
397        i.index += 1;
398
399        Ok(())
400    }
401}
402
403impl embedded_hal::spi::ErrorType for Spi {
404    type Error = MockError;
405}
406
407impl embedded_hal::digital::InputPin for Pin {
408    fn is_high(&mut self) -> Result<bool, Self::Error> {
409        let mut i = self.inner.lock().unwrap();
410        let index = i.index;
411
412        // Fetch expectation if found
413        let v = match &i.expected.get(index) {
414            Some(MockTransaction::IsHigh(_id, v)) => *v,
415            _ => false,
416        };
417
418        // Save actual call
419        i.actual.push(MockTransaction::IsHigh(self.id, v));
420
421        // Update expectation index
422        i.index += 1;
423
424        Ok(v)
425    }
426
427    fn is_low(&mut self) -> Result<bool, Self::Error> {
428        let mut i = self.inner.lock().unwrap();
429        let index = i.index;
430
431        // Fetch expectation if found
432        let v = match &i.expected.get(index) {
433            Some(MockTransaction::IsLow(_id, v)) => *v,
434            _ => false,
435        };
436
437        // Save actual call
438        i.actual.push(MockTransaction::IsLow(self.id, v));
439
440        // Update expectation index
441        i.index += 1;
442
443        Ok(v)
444    }
445}
446
447impl embedded_hal::digital::OutputPin for Pin {
448    fn set_high(&mut self) -> Result<(), Self::Error> {
449        let mut i = self.inner.lock().unwrap();
450
451        // Save actual call
452        i.actual.push(MockTransaction::SetHigh(self.id));
453
454        // Update expectation index
455        i.index += 1;
456
457        Ok(())
458    }
459
460    fn set_low(&mut self) -> Result<(), Self::Error> {
461        let mut i = self.inner.lock().unwrap();
462
463        // Save actual call
464        i.actual.push(MockTransaction::SetLow(self.id));
465
466        // Update expectation index
467        i.index += 1;
468
469        Ok(())
470    }
471}
472
473impl embedded_hal::digital::ErrorType for Pin {
474    type Error = PinError;
475}
476
477impl embedded_hal::delay::DelayNs for Delay {
478    fn delay_ns(&mut self, t: u32) {
479        let mut i = self.inner.lock().unwrap();
480
481        // Save actual call
482        i.actual.push(MockTransaction::DelayNs(t));
483
484        // Update expectation index
485        i.index += 1;
486    }
487}
488
489#[cfg(test)]
490mod test {
491    use std::*;
492    use std::{panic, vec};
493
494    use embedded_hal::delay::*;
495    use embedded_hal::digital::*;
496    use embedded_hal::spi::*;
497
498    use super::*;
499    use crate::{PrefixRead, PrefixWrite};
500
501    // TODO: needs fixing
502    #[test]
503    #[ignore]
504    fn test_transactional_read() {
505        let mut m = Mock::new();
506        let mut s = m.spi();
507
508        let prefix = vec![0xFF];
509        let data = vec![0xAA, 0xBB];
510
511        m.expect(vec![MockTransaction::spi_exec(
512            &s,
513            &[
514                MockExec::SpiWrite(prefix.clone()),
515                MockExec::SpiTransfer(vec![0u8; 2], data.clone()),
516            ],
517        )]);
518
519        let mut d = [0u8; 2];
520        s.prefix_read(&prefix, &mut d).expect("read failure");
521
522        m.finalise();
523        assert_eq!(&data, &d);
524    }
525
526    #[test]
527    #[should_panic]
528    fn test_transactional_read_expect_write() {
529        let mut m = Mock::new();
530        let mut s = m.spi();
531
532        let prefix = vec![0xFF];
533        let data = vec![0xAA, 0xBB];
534
535        m.expect(vec![MockTransaction::spi_write(
536            &s,
537            prefix.clone(),
538            data.clone(),
539        )]);
540
541        let mut d = [0u8; 2];
542        s.prefix_read(&prefix, &mut d).expect("read failure");
543
544        m.finalise();
545        assert_eq!(&data, &d);
546    }
547
548    // TODO: needs fixing
549    #[test]
550    #[ignore]
551    fn test_transactional_write() {
552        let mut m = Mock::new();
553        let mut s = m.spi();
554
555        let prefix = vec![0xFF];
556        let data = vec![0xAA, 0xBB];
557
558        m.expect(vec![MockTransaction::spi_write(
559            &s,
560            prefix.clone(),
561            data.clone(),
562        )]);
563
564        s.prefix_write(&prefix, &data).expect("write failure");
565
566        m.finalise();
567    }
568
569    #[test]
570    #[should_panic]
571    fn test_transactional_write_expect_read() {
572        let mut m = Mock::new();
573        let mut s = m.spi();
574
575        let prefix = vec![0xFF];
576        let data = vec![0xAA, 0xBB];
577
578        m.expect(vec![MockTransaction::spi_read(
579            &s,
580            prefix.clone(),
581            data.clone(),
582        )]);
583
584        s.prefix_write(&prefix, &data).expect("write failure");
585
586        m.finalise();
587    }
588
589    #[test]
590    fn test_standard_write() {
591        let mut m = Mock::new();
592        let mut s = m.spi();
593
594        let data = vec![0xAA, 0xBB];
595
596        m.expect(vec![MockTransaction::write(&s, data.clone())]);
597
598        s.write(&data).expect("write failure");
599
600        m.finalise();
601    }
602
603    #[test]
604    fn test_standard_transfer() {
605        let mut m = Mock::new();
606        let mut s = m.spi();
607
608        let outgoing = vec![0xAA, 0xBB];
609        let incoming = vec![0xCC, 0xDD];
610
611        m.expect(vec![MockTransaction::transfer(
612            &s,
613            outgoing.clone(),
614            incoming.clone(),
615        )]);
616
617        let mut d = outgoing.clone();
618        s.transfer_in_place(&mut d).expect("read failure");
619
620        m.finalise();
621        assert_eq!(&incoming, &d);
622    }
623
624    #[test]
625    fn test_pins() {
626        let mut m = Mock::new();
627        let mut p = m.pin();
628
629        m.expect(vec![
630            MockTransaction::is_high(&p, true),
631            MockTransaction::is_low(&p, false),
632            MockTransaction::set_high(&p),
633            MockTransaction::set_low(&p),
634        ]);
635
636        assert_eq!(true, p.is_high().unwrap());
637        assert_eq!(false, p.is_low().unwrap());
638
639        p.set_high().unwrap();
640        p.set_low().unwrap();
641
642        m.finalise();
643    }
644
645    #[test]
646    #[should_panic]
647    fn test_incorrect_pin() {
648        let mut m = Mock::new();
649        let p1 = m.pin();
650        let mut p2 = m.pin();
651
652        m.expect(vec![MockTransaction::is_high(&p1, true)]);
653
654        p2.is_high().unwrap();
655
656        m.finalise();
657    }
658}