Drain bounded MPU6000 and ICM-42688 FIFO batches. Publish the latest validated sample only after overflow checks. Reject invalid drains. Validation: driver, sensor and platform tests plus both ARM release builds from a fresh build directory.
98 lines
2.8 KiB
Rust
98 lines
2.8 KiB
Rust
//! Test transport with owned pending bytes, never retained caller pointers.
|
|
|
|
use kaptan_spi::{CompletionError, SpiCompletion, SpiDevice};
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub(crate) enum FakeError {
|
|
Start,
|
|
Busy,
|
|
InvalidLength,
|
|
Quarantined,
|
|
}
|
|
|
|
pub(crate) struct FakeBus {
|
|
pub response: [u8; 32],
|
|
pub fail_start: bool,
|
|
pub fail_completion: Option<CompletionError>,
|
|
pub busy: bool,
|
|
pub starts: usize,
|
|
pub cancellations: usize,
|
|
pub transmitted: [u8; 32],
|
|
pending: Option<([u8; 32], usize)>,
|
|
quarantined: bool,
|
|
}
|
|
|
|
impl FakeBus {
|
|
pub fn ready() -> Self {
|
|
Self {
|
|
response: [0; 32],
|
|
fail_start: false,
|
|
fail_completion: None,
|
|
busy: false,
|
|
starts: 0,
|
|
cancellations: 0,
|
|
transmitted: [0; 32],
|
|
pending: None,
|
|
quarantined: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SpiDevice for FakeBus {
|
|
type StartError = FakeError;
|
|
|
|
fn is_busy(error: &Self::StartError) -> bool {
|
|
*error == FakeError::Busy
|
|
}
|
|
|
|
fn start_transfer(&mut self, transmit: &[u8]) -> Result<(), Self::StartError> {
|
|
if self.quarantined {
|
|
return Err(FakeError::Quarantined);
|
|
}
|
|
if self.pending.is_some() || self.busy {
|
|
return Err(FakeError::Busy);
|
|
}
|
|
if self.fail_start {
|
|
return Err(FakeError::Start);
|
|
}
|
|
if transmit.is_empty() || transmit.len() > self.response.len() {
|
|
return Err(FakeError::InvalidLength);
|
|
}
|
|
// Simulated hardware computes its response at submission, but only the
|
|
// accepted completion is allowed to copy those owned bytes to a caller.
|
|
self.pending = Some((self.response, transmit.len()));
|
|
self.transmitted[..transmit.len()].copy_from_slice(transmit);
|
|
self.starts += 1;
|
|
Ok(())
|
|
}
|
|
|
|
fn complete_transfer(
|
|
&mut self,
|
|
completion: SpiCompletion,
|
|
receive: &mut [u8],
|
|
) -> Result<(), CompletionError> {
|
|
if completion == SpiCompletion::NotPending {
|
|
return Err(CompletionError::NotPending);
|
|
}
|
|
if self.quarantined {
|
|
return Err(CompletionError::Quarantined);
|
|
}
|
|
if completion == SpiCompletion::TransferFault {
|
|
self.cancellations += 1;
|
|
}
|
|
let (pending, length) = self.pending.take().ok_or(CompletionError::NotActive)?;
|
|
if let Some(error) = self.fail_completion.take() {
|
|
self.quarantined = error == CompletionError::Quarantined;
|
|
return Err(error);
|
|
}
|
|
if completion == SpiCompletion::TransferFault {
|
|
return Err(CompletionError::TransferFault);
|
|
}
|
|
if receive.len() != length {
|
|
return Err(CompletionError::InvalidLength);
|
|
}
|
|
receive.copy_from_slice(&pending[..length]);
|
|
Ok(())
|
|
}
|
|
}
|