Skip to content

Commit c827e70

Browse files
authored
Merge pull request #131 from 2bndy5/spi-err
add: Mock SPI errors
2 parents 9361c5f + 781aa0a commit c827e70

2 files changed

Lines changed: 149 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010

1111
### Added
1212

13+
- Support mocked SPI transaction errors (#131)
14+
1315
### Fixed
1416

1517
### Changed

src/eh1/spi.rs

Lines changed: 147 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,37 @@
3838
//! spi.transfer_in_place(&mut buf).unwrap();
3939
//! assert_eq!(buf, vec![5, 6]);
4040
//!
41-
//! // Finalise expectations
41+
//! // Finalize expectations
42+
//! spi.done();
43+
//! ```
44+
//!
45+
//! ## Mocking Errors
46+
//!
47+
//! ```
48+
//! # use eh1 as embedded_hal;
49+
//! use embedded_hal::spi::{SpiBus, SpiDevice, ErrorKind};
50+
//! use embedded_hal_mock::eh1::spi::{Mock as SpiMock, Transaction as SpiTransaction};
51+
//! use embedded_hal_nb::{nb::Error, spi::FullDuplex};
52+
//!
53+
//! // Configure expectations
54+
//! let expectations = [
55+
//! SpiTransaction::write(0x09).with_error(ErrorKind::Other),
56+
//! SpiTransaction::transfer_in_place(vec![3, 4], vec![5, 6]).with_error(ErrorKind::Other),
57+
//! SpiTransaction::transaction_start().with_error(ErrorKind::Other),
58+
//! ];
59+
//!
60+
//! let mut spi = SpiMock::new(&expectations);
61+
//! // FullDuplex transfers
62+
//! assert_eq!(FullDuplex::write(&mut spi, 0x09), Err(Error::Other(ErrorKind::Other)));
63+
//!
64+
//! // Transferring
65+
//! let mut buf = vec![3, 4];
66+
//! assert_eq!(SpiBus::transfer_in_place(&mut spi, &mut buf), Err(ErrorKind::Other));
67+
//!
68+
//! // SpiDevice transfer that fails to start
69+
//! assert_eq!(SpiDevice::write(&mut spi, &vec![7, 8]), Err(ErrorKind::Other));
70+
//!
71+
//! // Finalize expectations
4272
//! spi.done();
4373
//! ```
4474
use core::fmt::Debug;
@@ -77,6 +107,7 @@ pub struct Transaction<W> {
77107
expected_mode: Mode,
78108
expected_data: Vec<W>,
79109
response: Vec<W>,
110+
err: Option<spi::ErrorKind>,
80111
}
81112

82113
impl<W> Transaction<W>
@@ -89,6 +120,7 @@ where
89120
expected_mode: Mode::Write,
90121
expected_data: expected,
91122
response: Vec::new(),
123+
err: None,
92124
}
93125
}
94126

@@ -98,6 +130,7 @@ where
98130
expected_mode: Mode::Transfer,
99131
expected_data: expected,
100132
response,
133+
err: None,
101134
}
102135
}
103136

@@ -107,6 +140,7 @@ where
107140
expected_mode: Mode::TransferInplace,
108141
expected_data: expected,
109142
response,
143+
err: None,
110144
}
111145
}
112146

@@ -116,6 +150,7 @@ where
116150
expected_mode: Mode::Write,
117151
expected_data: [expected].to_vec(),
118152
response: Vec::new(),
153+
err: None,
119154
}
120155
}
121156

@@ -125,6 +160,7 @@ where
125160
expected_mode: Mode::Read,
126161
expected_data: Vec::new(),
127162
response: [response].to_vec(),
163+
err: None,
128164
}
129165
}
130166

@@ -134,6 +170,7 @@ where
134170
expected_mode: Mode::Read,
135171
expected_data: Vec::new(),
136172
response,
173+
err: None,
137174
}
138175
}
139176

@@ -143,6 +180,7 @@ where
143180
expected_mode: Mode::Flush,
144181
expected_data: Vec::new(),
145182
response: Vec::new(),
183+
err: None,
146184
}
147185
}
148186

@@ -152,6 +190,7 @@ where
152190
expected_mode: Mode::TransactionStart,
153191
expected_data: Vec::new(),
154192
response: Vec::new(),
193+
err: None,
155194
}
156195
}
157196

@@ -161,6 +200,7 @@ where
161200
expected_mode: Mode::TransactionEnd,
162201
expected_data: Vec::new(),
163202
response: Vec::new(),
203+
err: None,
164204
}
165205
}
166206

@@ -170,6 +210,17 @@ where
170210
expected_mode: Mode::Delay(delay),
171211
expected_data: Vec::new(),
172212
response: Vec::new(),
213+
err: None,
214+
}
215+
}
216+
217+
/// Add an error return to a transaction
218+
///
219+
/// This is used to mock hardware failures.
220+
pub fn with_error(self, error: spi::ErrorKind) -> Self {
221+
Self {
222+
err: Some(error),
223+
..self
173224
}
174225
}
175226
}
@@ -207,7 +258,10 @@ where
207258
"spi:read mismatched response length"
208259
);
209260
buffer.copy_from_slice(&w.response);
210-
Ok(())
261+
match w.err {
262+
Some(err) => Err(err),
263+
None => Ok(()),
264+
}
211265
}
212266

213267
/// spi::Write implementation for Mock
@@ -220,7 +274,10 @@ where
220274
&w.expected_data, &buffer,
221275
"spi::write data does not match expectation"
222276
);
223-
Ok(())
277+
match w.err {
278+
Some(err) => Err(err),
279+
None => Ok(()),
280+
}
224281
}
225282

226283
fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
@@ -240,7 +297,10 @@ where
240297
"mismatched response length for spi::transfer"
241298
);
242299
read.copy_from_slice(&w.response);
243-
Ok(())
300+
match w.err {
301+
Some(err) => Err(err),
302+
None => Ok(()),
303+
}
244304
}
245305

246306
/// spi::TransferInplace implementation for Mock
@@ -265,7 +325,10 @@ where
265325
"mismatched response length for spi::transfer_in_place"
266326
);
267327
buffer.copy_from_slice(&w.response);
268-
Ok(())
328+
match w.err {
329+
Some(err) => Err(err),
330+
None => Ok(()),
331+
}
269332
}
270333

271334
fn flush(&mut self) -> Result<(), Self::Error> {
@@ -322,7 +385,10 @@ where
322385
data.expected_data[0], buffer,
323386
"spi::write data does not match expectation"
324387
);
325-
Ok(())
388+
match data.err {
389+
Some(err) => Err(nb::Error::Other(err)),
390+
None => Ok(()),
391+
}
326392
}
327393

328394
/// spi::FullDuplex implementation for Mock
@@ -337,7 +403,10 @@ where
337403
"mismatched response length for spi::read"
338404
);
339405
let buffer: W = w.response[0];
340-
Ok(buffer)
406+
match w.err {
407+
Some(err) => Err(nb::Error::Other(err)),
408+
None => Ok(buffer),
409+
}
341410
}
342411
}
343412

@@ -357,7 +426,9 @@ where
357426
Mode::TransactionStart,
358427
"spi::transaction unexpected mode"
359428
);
360-
429+
if let Some(err) = w.err {
430+
return Err(err);
431+
}
361432
for op in operations {
362433
match op {
363434
Operation::Read(buffer) => {
@@ -392,7 +463,10 @@ where
392463
"spi::transaction unexpected mode"
393464
);
394465

395-
Ok(())
466+
match w.err {
467+
Some(err) => Err(err),
468+
None => Ok(()),
469+
}
396470
}
397471
}
398472

@@ -538,6 +612,70 @@ mod test {
538612
spi.done();
539613
}
540614

615+
#[test]
616+
fn test_spi_mock_bus_error() {
617+
use eh1::spi::SpiBus;
618+
619+
let expectations = [
620+
Transaction::write_vec(vec![1, 2]).with_error(spi::ErrorKind::Other),
621+
Transaction::write(9).with_error(spi::ErrorKind::Other),
622+
Transaction::read(10).with_error(spi::ErrorKind::Other),
623+
Transaction::write(0xFE).with_error(spi::ErrorKind::Other),
624+
Transaction::read(0xFF).with_error(spi::ErrorKind::Other),
625+
Transaction::transfer_in_place(vec![3, 4], vec![5, 6])
626+
.with_error(spi::ErrorKind::Other),
627+
];
628+
let mut spi = Mock::new(&expectations);
629+
630+
assert_eq!(SpiBus::write(&mut spi, &[1, 2]), Err(spi::ErrorKind::Other));
631+
assert_eq!(SpiBus::write(&mut spi, &[0x09]), Err(spi::ErrorKind::Other));
632+
assert_eq!(
633+
FullDuplex::read(&mut spi),
634+
Err(nb::Error::Other(spi::ErrorKind::Other))
635+
);
636+
assert_eq!(SpiBus::write(&mut spi, &[0xfe]), Err(spi::ErrorKind::Other));
637+
assert_eq!(
638+
FullDuplex::read(&mut spi),
639+
Err(nb::Error::Other(spi::ErrorKind::Other))
640+
);
641+
let mut v = vec![3, 4];
642+
assert_eq!(
643+
SpiBus::transfer_in_place(&mut spi, &mut v),
644+
Err(spi::ErrorKind::Other)
645+
);
646+
647+
spi.done();
648+
}
649+
650+
#[test]
651+
fn test_spi_mock_device_error() {
652+
use eh1::spi::SpiDevice;
653+
654+
let expectations = [
655+
Transaction::transaction_start().with_error(spi::ErrorKind::Other),
656+
Transaction::transaction_start(),
657+
Transaction::transfer_in_place(vec![3, 4], vec![5, 6]),
658+
Transaction::transaction_end().with_error(spi::ErrorKind::Other),
659+
];
660+
let mut spi = Mock::new(&expectations);
661+
662+
let mut v = vec![3, 4];
663+
664+
// exits early due to returned error on transaction start
665+
assert_eq!(
666+
SpiDevice::transfer_in_place(&mut spi, &mut v),
667+
Err(spi::ErrorKind::Other)
668+
);
669+
// transfers successfully, but transaction_end() results in error
670+
assert_eq!(
671+
SpiDevice::transfer_in_place(&mut spi, &mut v),
672+
Err(spi::ErrorKind::Other)
673+
);
674+
assert_eq!(v, vec![5, 6]);
675+
676+
spi.done();
677+
}
678+
541679
#[test]
542680
fn test_spi_mock_multiple1() {
543681
use eh1::spi::SpiBus;

0 commit comments

Comments
 (0)