embedded_hal_mock/eh1/
spi.rs

1//! SPI mock implementations.
2//!
3//! This mock supports the specification and checking of expectations to allow
4//! automated testing of SPI based drivers. Mismatches between expected and
5//! real SPI transactions will cause runtime assertions to assist with locating
6//! faults.
7//!
8//! ## Usage
9//!
10//! ```
11//! # use eh1 as embedded_hal;
12//! use embedded_hal::spi::SpiBus;
13//! use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
14//! use embedded_hal_nb::spi::FullDuplex;
15//!
16//! // Configure expectations
17//! let expectations = [
18//!     SpiTransaction::write(0x09),
19//!     SpiTransaction::read(0x0A),
20//!     SpiTransaction::write(0xFE),
21//!     SpiTransaction::read(0xFF),
22//!     SpiTransaction::write_vec(vec![1, 2]),
23//!     SpiTransaction::transfer_in_place(vec![3, 4], vec![5, 6]),
24//! ];
25//!
26//! let mut spi = SpiMock::new(&expectations);
27//! // FullDuplex transfers
28//! FullDuplex::write(&mut spi, 0x09).unwrap();
29//! assert_eq!(FullDuplex::read(&mut spi).unwrap(), 0x0A);
30//! FullDuplex::write(&mut spi, 0xFE).unwrap();
31//! assert_eq!(FullDuplex::read(&mut spi).unwrap(), 0xFF);
32//!
33//! // Writing
34//! SpiBus::write(&mut spi, &vec![1, 2]).unwrap();
35//!
36//! // Transferring
37//! let mut buf = vec![3, 4];
38//! spi.transfer_in_place(&mut buf).unwrap();
39//! assert_eq!(buf, vec![5, 6]);
40//!
41//! // Finalise expectations
42//! spi.done();
43//! ```
44use core::fmt::Debug;
45
46use eh1::spi::{self, Operation, SpiBus, SpiDevice};
47use embedded_hal_nb::{nb, spi::FullDuplex};
48
49use crate::common::Generic;
50
51/// SPI Transaction mode
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub enum Mode {
54    /// Write transaction
55    Write,
56    /// Write and read transaction
57    Transfer,
58    /// Write and read in-place transaction
59    TransferInplace,
60    /// After a write transaction in real HW a Read is available
61    Read,
62    /// Flush transaction
63    Flush,
64    /// Mark the start of a group of transactions
65    TransactionStart,
66    /// Mark the end of a group of transactions
67    TransactionEnd,
68    /// A delay in the SPI transaction with the specified delay in microseconds
69    Delay(u32),
70}
71
72/// SPI transaction type
73///
74/// Models an SPI write or transfer (with response)
75#[derive(Clone, Debug, PartialEq, Eq)]
76pub struct Transaction<W> {
77    expected_mode: Mode,
78    expected_data: Vec<W>,
79    response: Vec<W>,
80}
81
82impl<W> Transaction<W>
83where
84    W: Copy + Debug + PartialEq,
85{
86    /// Create a write transaction
87    pub fn write_vec(expected: Vec<W>) -> Transaction<W> {
88        Transaction {
89            expected_mode: Mode::Write,
90            expected_data: expected,
91            response: Vec::new(),
92        }
93    }
94
95    /// Create a transfer transaction
96    pub fn transfer(expected: Vec<W>, response: Vec<W>) -> Transaction<W> {
97        Transaction {
98            expected_mode: Mode::Transfer,
99            expected_data: expected,
100            response,
101        }
102    }
103
104    /// Create a transfer in-place transaction
105    pub fn transfer_in_place(expected: Vec<W>, response: Vec<W>) -> Transaction<W> {
106        Transaction {
107            expected_mode: Mode::TransferInplace,
108            expected_data: expected,
109            response,
110        }
111    }
112
113    /// Create a write transaction
114    pub fn write(expected: W) -> Transaction<W> {
115        Transaction {
116            expected_mode: Mode::Write,
117            expected_data: [expected].to_vec(),
118            response: Vec::new(),
119        }
120    }
121
122    /// Create a read transaction
123    pub fn read(response: W) -> Transaction<W> {
124        Transaction {
125            expected_mode: Mode::Read,
126            expected_data: Vec::new(),
127            response: [response].to_vec(),
128        }
129    }
130
131    /// Create a read transaction
132    pub fn read_vec(response: Vec<W>) -> Transaction<W> {
133        Transaction {
134            expected_mode: Mode::Read,
135            expected_data: Vec::new(),
136            response,
137        }
138    }
139
140    /// Create flush transaction
141    pub fn flush() -> Transaction<W> {
142        Transaction {
143            expected_mode: Mode::Flush,
144            expected_data: Vec::new(),
145            response: Vec::new(),
146        }
147    }
148
149    /// Create nested transactions
150    pub fn transaction_start() -> Transaction<W> {
151        Transaction {
152            expected_mode: Mode::TransactionStart,
153            expected_data: Vec::new(),
154            response: Vec::new(),
155        }
156    }
157
158    /// Create nested transactions
159    pub fn transaction_end() -> Transaction<W> {
160        Transaction {
161            expected_mode: Mode::TransactionEnd,
162            expected_data: Vec::new(),
163            response: Vec::new(),
164        }
165    }
166
167    /// Create a delay transaction
168    pub fn delay(delay: u32) -> Transaction<W> {
169        Transaction {
170            expected_mode: Mode::Delay(delay),
171            expected_data: Vec::new(),
172            response: Vec::new(),
173        }
174    }
175}
176
177/// Mock SPI implementation
178///
179/// This supports the specification and checking of expectations to allow
180/// automated testing of SPI based drivers. Mismatches between expected and
181/// real SPI transactions will cause runtime assertions to assist with locating
182/// faults.
183///
184/// See the usage section in the module level docs for an example.
185pub type Mock<W> = Generic<Transaction<W>>;
186
187impl<W> spi::ErrorType for Mock<W>
188where
189    W: Copy + Debug + PartialEq,
190{
191    type Error = spi::ErrorKind;
192}
193
194#[derive(Default)]
195struct SpiBusFuture {
196    awaited: bool,
197}
198
199impl std::future::Future for SpiBusFuture {
200    type Output = Result<(), spi::ErrorKind>;
201
202    fn poll(
203        mut self: std::pin::Pin<&mut Self>,
204        _cx: &mut std::task::Context<'_>,
205    ) -> std::task::Poll<Self::Output> {
206        self.awaited = true;
207        std::task::Poll::Ready(Ok(()))
208    }
209}
210
211impl Drop for SpiBusFuture {
212    fn drop(&mut self) {
213        assert!(self.awaited, "spi::flush call was not awaited");
214    }
215}
216
217impl<W> SpiBus<W> for Mock<W>
218where
219    W: Copy + 'static + Debug + PartialEq,
220{
221    /// spi::Read implementation for Mock
222    ///
223    /// This will cause an assertion if the read call does not match the next expectation
224    fn read(&mut self, buffer: &mut [W]) -> Result<(), Self::Error> {
225        let w = self.next().expect("no expectation for spi::read call");
226        assert_eq!(w.expected_mode, Mode::Read, "spi::read unexpected mode");
227        assert_eq!(
228            buffer.len(),
229            w.response.len(),
230            "spi:read mismatched response length"
231        );
232        buffer.copy_from_slice(&w.response);
233        Ok(())
234    }
235
236    /// spi::Write implementation for Mock
237    ///
238    /// This will cause an assertion if the write call does not match the next expectation
239    fn write(&mut self, buffer: &[W]) -> Result<(), Self::Error> {
240        let w = self.next().expect("no expectation for spi::write call");
241        assert_eq!(w.expected_mode, Mode::Write, "spi::write unexpected mode");
242        assert_eq!(
243            &w.expected_data, &buffer,
244            "spi::write data does not match expectation"
245        );
246        Ok(())
247    }
248
249    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
250        let w = self.next().expect("no expectation for spi::transfer call");
251        assert_eq!(
252            w.expected_mode,
253            Mode::Transfer,
254            "spi::transfer unexpected mode"
255        );
256        assert_eq!(
257            &w.expected_data, &write,
258            "spi::write data does not match expectation"
259        );
260        assert_eq!(
261            read.len(),
262            w.response.len(),
263            "mismatched response length for spi::transfer"
264        );
265        read.copy_from_slice(&w.response);
266        Ok(())
267    }
268
269    /// spi::TransferInplace implementation for Mock
270    ///
271    /// This writes the provided response to the buffer and will cause an assertion if the written data does not match the next expectation
272    fn transfer_in_place(&mut self, buffer: &mut [W]) -> Result<(), Self::Error> {
273        let w = self
274            .next()
275            .expect("no expectation for spi::transfer_in_place call");
276        assert_eq!(
277            w.expected_mode,
278            Mode::TransferInplace,
279            "spi::transfer_in_place unexpected mode"
280        );
281        assert_eq!(
282            &w.expected_data, &buffer,
283            "spi::transfer_in_place write data does not match expectation"
284        );
285        assert_eq!(
286            buffer.len(),
287            w.response.len(),
288            "mismatched response length for spi::transfer_in_place"
289        );
290        buffer.copy_from_slice(&w.response);
291        Ok(())
292    }
293
294    fn flush(&mut self) -> Result<(), Self::Error> {
295        let w = self.next().expect("no expectation for spi::flush call");
296        assert_eq!(w.expected_mode, Mode::Flush, "spi::flush unexpected mode");
297        Ok(())
298    }
299}
300
301#[cfg(feature = "embedded-hal-async")]
302impl<W> embedded_hal_async::spi::SpiBus<W> for Mock<W>
303where
304    W: Copy + 'static + Debug + PartialEq,
305{
306    async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
307        eh1::spi::SpiBus::<W>::read(self, words)
308    }
309
310    async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
311        eh1::spi::SpiBus::<W>::write(self, words)
312    }
313
314    async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
315        eh1::spi::SpiBus::<W>::transfer(self, read, write)
316    }
317
318    /// spi::TransferInplace implementation for Mock
319    ///
320    /// This writes the provided response to the buffer and will cause an assertion if the written data does not match the next expectation
321    async fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
322        eh1::spi::SpiBus::<W>::transfer_in_place(self, words)
323    }
324
325    async fn flush(&mut self) -> Result<(), Self::Error> {
326        eh1::spi::SpiBus::flush(self)
327    }
328}
329
330impl<W> FullDuplex<W> for Mock<W>
331where
332    W: Copy + Debug + PartialEq,
333{
334    /// spi::FullDuplex implementation for Mock
335    ///
336    /// This will call the nonblocking read/write primitives.
337    fn write(&mut self, buffer: W) -> nb::Result<(), Self::Error> {
338        let data = self.next().expect("no expectation for spi::write call");
339        assert_eq!(
340            data.expected_mode,
341            Mode::Write,
342            "spi::write unexpected mode"
343        );
344        assert_eq!(
345            data.expected_data[0], buffer,
346            "spi::write data does not match expectation"
347        );
348        Ok(())
349    }
350
351    /// spi::FullDuplex implementation for Mock
352    ///
353    /// This will call the nonblocking read/write primitives.
354    fn read(&mut self) -> nb::Result<W, Self::Error> {
355        let w = self.next().expect("no expectation for spi::read call");
356        assert_eq!(w.expected_mode, Mode::Read, "spi::Read unexpected mode");
357        assert_eq!(
358            1,
359            w.response.len(),
360            "mismatched response length for spi::read"
361        );
362        let buffer: W = w.response[0];
363        Ok(buffer)
364    }
365}
366
367impl<W> SpiDevice<W> for Mock<W>
368where
369    W: Copy + 'static + Debug + PartialEq,
370{
371    /// spi::SpiDevice implementation for Mock
372    ///
373    /// This writes the provided response to the buffer and will cause an assertion if the written data does not match the next expectation
374    fn transaction(&mut self, operations: &mut [Operation<'_, W>]) -> Result<(), Self::Error> {
375        let w = self
376            .next()
377            .expect("no expectation for spi::transaction call");
378        assert_eq!(
379            w.expected_mode,
380            Mode::TransactionStart,
381            "spi::transaction unexpected mode"
382        );
383
384        for op in operations {
385            match op {
386                Operation::Read(buffer) => {
387                    SpiBus::read(self, buffer)?;
388                }
389                Operation::Write(buffer) => {
390                    SpiBus::write(self, buffer)?;
391                }
392                Operation::Transfer(read, write) => {
393                    SpiBus::transfer(self, read, write)?;
394                }
395                Operation::TransferInPlace(buffer) => {
396                    SpiBus::transfer_in_place(self, buffer)?;
397                }
398                Operation::DelayNs(delay) => {
399                    let w = self.next().expect("no expectation for spi::delay call");
400                    assert_eq!(
401                        w.expected_mode,
402                        Mode::Delay(*delay),
403                        "spi::transaction unexpected mode"
404                    );
405                }
406            }
407        }
408
409        let w = self
410            .next()
411            .expect("no expectation for spi::transaction call");
412        assert_eq!(
413            w.expected_mode,
414            Mode::TransactionEnd,
415            "spi::transaction unexpected mode"
416        );
417
418        Ok(())
419    }
420}
421
422#[cfg(feature = "embedded-hal-async")]
423impl<W> embedded_hal_async::spi::SpiDevice<W> for Mock<W>
424where
425    W: Copy + 'static + Debug + PartialEq,
426{
427    async fn transaction(
428        &mut self,
429        operations: &mut [Operation<'_, W>],
430    ) -> Result<(), Self::Error> {
431        let w = self
432            .next()
433            .expect("no expectation for spi::transaction call");
434        assert_eq!(
435            w.expected_mode,
436            Mode::TransactionStart,
437            "spi::transaction unexpected mode"
438        );
439        for op in operations {
440            match op {
441                Operation::Read(buffer) => {
442                    SpiBus::read(self, buffer)?;
443                }
444                Operation::Write(buffer) => {
445                    SpiBus::write(self, buffer)?;
446                }
447                Operation::Transfer(read, write) => {
448                    SpiBus::transfer(self, read, write)?;
449                }
450                Operation::TransferInPlace(buffer) => {
451                    SpiBus::transfer_in_place(self, buffer)?;
452                }
453                Operation::DelayNs(delay) => {
454                    let w = self.next().expect("no expectation for spi::delay call");
455                    assert_eq!(
456                        w.expected_mode,
457                        Mode::Delay(*delay),
458                        "spi::transaction unexpected mode"
459                    );
460                }
461            }
462        }
463
464        let w = self
465            .next()
466            .expect("no expectation for spi::transaction call");
467        assert_eq!(
468            w.expected_mode,
469            Mode::TransactionEnd,
470            "spi::transaction unexpected mode"
471        );
472
473        Ok(())
474    }
475}
476
477#[cfg(test)]
478mod test {
479    use super::*;
480
481    #[test]
482    fn test_spi_mock_write() {
483        use eh1::spi::SpiBus;
484
485        let mut spi = Mock::new(&[Transaction::write(10)]);
486
487        let _ = SpiBus::write(&mut spi, &[10]).unwrap();
488
489        spi.done();
490    }
491
492    #[test]
493    fn test_spi_mock_write_u16() {
494        let mut spi = Mock::new(&[Transaction::write(0xFFFF_u16)]);
495
496        let _ = SpiBus::write(&mut spi, &[0xFFFF_u16]).unwrap();
497
498        spi.done();
499    }
500
501    #[test]
502    fn test_spi_mock_read_duplex() {
503        use embedded_hal_nb::spi::FullDuplex;
504
505        let mut spi = Mock::new(&[Transaction::read(10)]);
506
507        let ans = FullDuplex::read(&mut spi).unwrap();
508
509        assert_eq!(ans, 10);
510
511        spi.done();
512    }
513
514    #[test]
515    fn test_spi_mock_read_duplex_u16() {
516        use embedded_hal_nb::spi::FullDuplex;
517
518        let mut spi = Mock::new(&[Transaction::read(0xFFFF_u16)]);
519
520        let ans = FullDuplex::read(&mut spi).unwrap();
521
522        assert_eq!(ans, 0xFFFF_u16);
523
524        spi.done();
525    }
526
527    #[test]
528    fn test_spi_mock_read_bus() {
529        use eh1::spi::SpiBus;
530
531        let mut spi = Mock::new(&[Transaction::read(10)]);
532
533        let mut buf = vec![0u8; 1];
534        SpiBus::read(&mut spi, &mut buf).unwrap();
535
536        assert_eq!(buf, [10]);
537
538        spi.done();
539    }
540
541    #[test]
542    fn test_spi_mock_read_bus_u16() {
543        use eh1::spi::SpiBus;
544
545        let mut spi = Mock::new(&[Transaction::read(0xFFFF_u16)]);
546
547        let mut buf = vec![0u16; 1];
548        SpiBus::read(&mut spi, &mut buf).unwrap();
549
550        assert_eq!(buf, [0xFFFF_u16]);
551
552        spi.done();
553    }
554
555    #[test]
556    fn test_spi_mock_flush() {
557        use eh1::spi::SpiBus;
558
559        let mut spi = Mock::new(&[Transaction::<u8>::flush()]);
560        spi.flush().unwrap();
561        spi.done();
562    }
563
564    #[test]
565    fn test_spi_mock_multiple1() {
566        use eh1::spi::SpiBus;
567
568        let expectations = [
569            Transaction::write_vec(vec![1, 2]),
570            Transaction::write(9),
571            Transaction::read(10),
572            Transaction::write(0xFE),
573            Transaction::read(0xFF),
574            Transaction::transfer_in_place(vec![3, 4], vec![5, 6]),
575        ];
576        let mut spi = Mock::new(&expectations);
577
578        SpiBus::write(&mut spi, &[1, 2]).unwrap();
579
580        let _ = SpiBus::write(&mut spi, &[0x09]);
581        assert_eq!(FullDuplex::read(&mut spi).unwrap(), 0x0a);
582        let _ = SpiBus::write(&mut spi, &[0xfe]);
583        assert_eq!(FullDuplex::read(&mut spi).unwrap(), 0xFF);
584        let mut v = vec![3, 4];
585        SpiBus::transfer_in_place(&mut spi, &mut v).unwrap();
586
587        assert_eq!(v, vec![5, 6]);
588
589        spi.done();
590    }
591
592    #[test]
593    fn test_spi_mock_multiple_transaction() {
594        use eh1::spi::SpiDevice;
595
596        let expectations = [
597            Transaction::transaction_start(),
598            Transaction::write_vec(vec![1, 2]),
599            Transaction::write(9),
600            Transaction::delay(100),
601            Transaction::read(10),
602            Transaction::transaction_end(),
603        ];
604        let mut spi = Mock::new(&expectations);
605        let mut ans = [0u8; 1];
606        spi.transaction(&mut [
607            Operation::Write(&[1, 2]),
608            Operation::Write(&[0x09]),
609            Operation::DelayNs(100),
610            Operation::Read(&mut ans),
611        ])
612        .unwrap();
613
614        assert_eq!(ans, [10]);
615
616        spi.done();
617    }
618
619    #[test]
620    fn test_spi_mock_write_vec() {
621        use eh1::spi::SpiBus;
622
623        let expectations = [Transaction::write_vec(vec![10, 12])];
624        let mut spi = Mock::new(&expectations);
625
626        SpiBus::write(&mut spi, &[10, 12]).unwrap();
627
628        spi.done();
629    }
630
631    #[test]
632    fn test_spi_mock_write_vec_u32() {
633        use eh1::spi::SpiBus;
634
635        let expectations = [Transaction::write_vec(vec![0xFFAABBCC_u32, 12])];
636        let mut spi = Mock::new(&expectations);
637
638        SpiBus::write(&mut spi, &[0xFFAABBCC_u32, 12]).unwrap();
639
640        spi.done();
641    }
642
643    #[test]
644    fn test_spi_mock_transfer_in_place() {
645        use eh1::spi::SpiBus;
646
647        let expectations = [Transaction::transfer_in_place(vec![10, 12], vec![12, 13])];
648        let mut spi = Mock::new(&expectations);
649
650        let mut v = vec![10, 12];
651        SpiBus::transfer_in_place(&mut spi, &mut v).unwrap();
652
653        assert_eq!(v, vec![12, 13]);
654
655        spi.done();
656    }
657
658    #[test]
659    fn test_spi_mock_transfer() {
660        use eh1::spi::SpiBus;
661
662        let expectations = [Transaction::transfer(vec![10, 12], vec![12, 13])];
663        let mut spi = Mock::new(&expectations);
664
665        let mut v = vec![10, 12];
666        SpiBus::transfer(&mut spi, &mut v, &[10, 12]).unwrap();
667
668        assert_eq!(v, vec![12, 13]);
669
670        spi.done();
671    }
672
673    #[test]
674    fn test_spi_mock_transfer_u32() {
675        use eh1::spi::SpiBus;
676
677        let expectations = [Transaction::transfer(
678            vec![0xFFAABBCC_u32, 12],
679            vec![0xAABBCCDD_u32, 13],
680        )];
681        let mut spi = Mock::new(&expectations);
682
683        let mut v = vec![0xFFAABBCC_u32, 12];
684        SpiBus::transfer(&mut spi, &mut v, &[0xFFAABBCC_u32, 12]).unwrap();
685
686        assert_eq!(v, vec![0xAABBCCDD_u32, 13]);
687
688        spi.done();
689    }
690
691    #[test]
692    fn test_spi_mock_multiple() {
693        use eh1::spi::SpiBus;
694
695        let expectations = [
696            Transaction::write_vec(vec![1, 2]),
697            Transaction::transfer_in_place(vec![3, 4], vec![5, 6]),
698        ];
699        let mut spi = Mock::new(&expectations);
700
701        SpiBus::write(&mut spi, &[1, 2]).unwrap();
702
703        let mut v = vec![3, 4];
704        SpiBus::transfer_in_place(&mut spi, &mut v).unwrap();
705
706        assert_eq!(v, vec![5, 6]);
707
708        spi.done();
709    }
710
711    #[test]
712    #[should_panic(expected = "spi::write data does not match expectation")]
713    fn test_spi_mock_write_err() {
714        use eh1::spi::SpiBus;
715        let expectations = [Transaction::write_vec(vec![10, 12])];
716        let mut spi = Mock::new(&expectations);
717        SpiBus::write(&mut spi, &[10, 12, 12]).unwrap();
718    }
719
720    #[test]
721    #[should_panic(expected = "spi::transfer_in_place write data does not match expectation")]
722    fn test_spi_mock_transfer_err() {
723        use eh1::spi::SpiBus;
724        let expectations = [Transaction::transfer_in_place(vec![10, 12], vec![12, 15])];
725        let mut spi = Mock::new(&expectations);
726        SpiBus::transfer_in_place(&mut spi, &mut vec![10, 13]).unwrap();
727    }
728
729    #[test]
730    #[should_panic(expected = "spi::write unexpected mode")]
731    fn test_spi_mock_mode_err() {
732        use eh1::spi::SpiBus;
733        let expectations = [Transaction::transfer_in_place(vec![10, 12], vec![])];
734        let mut spi = Mock::new(&expectations);
735        SpiBus::write(&mut spi, &[10, 12, 12]).unwrap();
736    }
737
738    #[test]
739    #[should_panic(expected = "spi::write data does not match expectation")]
740    fn test_spi_mock_multiple_transaction_err() {
741        use eh1::spi::SpiBus;
742
743        let expectations = [
744            Transaction::write_vec(vec![10, 12]),
745            Transaction::write_vec(vec![10, 12]),
746        ];
747        let mut spi = Mock::new(&expectations);
748        SpiBus::write(&mut spi, &[10, 12, 10]).unwrap();
749    }
750
751    /// Test that the async trait impls call the synchronous variants under the hood.
752    #[tokio::test]
753    #[cfg(feature = "embedded-hal-async")]
754    async fn async_impls() {
755        use embedded_hal_async::spi::{SpiBus, SpiDevice};
756
757        let mut spi = Mock::new(&[
758            Transaction::read(1),
759            Transaction::write(2),
760            Transaction::transfer(vec![3], vec![4, 5]),
761            Transaction::transfer_in_place(vec![6, 7], vec![8, 9]),
762            Transaction::flush(),
763            Transaction::transaction_start(),
764            Transaction::delay(100),
765            Transaction::write(10),
766            Transaction::transaction_end(),
767        ]);
768
769        // Test read
770        let mut buf = vec![0u8; 1];
771        SpiBus::read(&mut spi, &mut buf).await.unwrap();
772        assert_eq!(buf, vec![1]);
773
774        // Test write
775        SpiBus::write(&mut spi, &[2]).await.unwrap();
776
777        // Test transfer
778        let mut buf = vec![0u8; 2];
779        SpiBus::transfer(&mut spi, &mut buf, &[3]).await.unwrap();
780        assert_eq!(buf, vec![4, 5]);
781
782        // Test transfer_in_place
783        let mut buf = vec![6, 7];
784        SpiBus::transfer_in_place(&mut spi, &mut buf).await.unwrap();
785        assert_eq!(buf, vec![8, 9]);
786
787        // Test flush
788        SpiBus::flush(&mut spi).await.unwrap();
789
790        // Test transaction
791        SpiDevice::transaction(
792            &mut spi,
793            &mut [Operation::DelayNs(100), Operation::Write(&[10])],
794        )
795        .await
796        .unwrap();
797
798        spi.done();
799    }
800}