1use 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#[derive(Clone, Debug, PartialEq, Eq)]
53pub enum Mode {
54 Write,
56 Transfer,
58 TransferInplace,
60 Read,
62 Flush,
64 TransactionStart,
66 TransactionEnd,
68 Delay(u32),
70}
71
72#[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 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 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 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 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 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 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 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 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 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 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
177pub 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 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 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 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 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 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 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 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 #[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 let mut buf = vec![0u8; 1];
771 SpiBus::read(&mut spi, &mut buf).await.unwrap();
772 assert_eq!(buf, vec![1]);
773
774 SpiBus::write(&mut spi, &[2]).await.unwrap();
776
777 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 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 SpiBus::flush(&mut spi).await.unwrap();
789
790 SpiDevice::transaction(
792 &mut spi,
793 &mut [Operation::DelayNs(100), Operation::Write(&[10])],
794 )
795 .await
796 .unwrap();
797
798 spi.done();
799 }
800}