feat(drivers): validate bounded IMU FIFO acquisition
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.
This commit is contained in:
1 parent
f9a61a086f
commit
d32b03c87f
13 files changed
+1303
-833
No files matched your search
@@ -2,6 +2,7 @@
|
||||
|
||||
use super::peripherals::{Spi1, Spi1Error, Spi3, Spi3Error, TimerClock};
|
||||
use kaptan_drivers::{
|
||||
ImuBatch,
|
||||
icm42688::{Icm42688, Icm42688Service, Icm42688ServiceEvent},
|
||||
mpu6000::{Mpu6000, Mpu6000Config, Mpu6000Service, Mpu6000ServiceEvent},
|
||||
};
|
||||
@@ -14,8 +15,7 @@ use crate::ImuMount;
|
||||
|
||||
use super::routes::{Icm42688Spi3Route, Mpu6000Spi1Route};
|
||||
|
||||
/// A profile-neutral IMU worker result. Device protocol errors are consumed
|
||||
/// here because flight policy only needs the terminal healthy/fault outcome.
|
||||
/// IMU worker result with device errors mapped to reportable IDs.
|
||||
pub enum ImuEvent {
|
||||
Idle,
|
||||
Initialized,
|
||||
@@ -23,8 +23,7 @@ pub enum ImuEvent {
|
||||
Fault(ErrorId),
|
||||
}
|
||||
|
||||
/// Operations used by the deferred IMU worker, statically dispatched to the
|
||||
/// route's concrete service. No peripheral ownership crosses this interface.
|
||||
/// Sensor operations invoked by the deferred IMU worker.
|
||||
pub trait ImuService: Send + 'static {
|
||||
fn begin(&mut self) -> ImuEvent;
|
||||
fn on_periodic_tick(&mut self) -> ImuEvent;
|
||||
@@ -82,7 +81,6 @@ impl ImuService for Mpu6000Imu {
|
||||
}
|
||||
}
|
||||
|
||||
/// Concrete ICM owner, including its board-declared mounting transform.
|
||||
pub struct Icm42688Imu {
|
||||
inner: Icm42688Service<TimerClock, Icm42688Spi3Route>,
|
||||
mount: ImuMount,
|
||||
@@ -136,7 +134,7 @@ fn mpu_event(event: Mpu6000ServiceEvent<Spi1Error>, mount: ImuMount) -> ImuEvent
|
||||
match event {
|
||||
Mpu6000ServiceEvent::Idle => ImuEvent::Idle,
|
||||
Mpu6000ServiceEvent::Initialized => ImuEvent::Initialized,
|
||||
Mpu6000ServiceEvent::Sample(sample) => ImuEvent::Sample(align_mount(sample, mount)),
|
||||
Mpu6000ServiceEvent::Samples(samples) => latest_sample(samples, mount),
|
||||
Mpu6000ServiceEvent::Fault(error) => ImuEvent::Fault(error.error_id()),
|
||||
}
|
||||
}
|
||||
@@ -145,14 +143,21 @@ fn icm_event(event: Icm42688ServiceEvent<Spi3Error>, mount: ImuMount) -> ImuEven
|
||||
match event {
|
||||
Icm42688ServiceEvent::Idle => ImuEvent::Idle,
|
||||
Icm42688ServiceEvent::Initialized => ImuEvent::Initialized,
|
||||
Icm42688ServiceEvent::Sample(sample) => ImuEvent::Sample(align_mount(sample, mount)),
|
||||
Icm42688ServiceEvent::Samples(samples) => latest_sample(samples, mount),
|
||||
Icm42688ServiceEvent::Fault(error) => ImuEvent::Fault(error.error_id()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the board-declared fixed IMU-to-body transform.
|
||||
///
|
||||
/// This is immutable board metadata, not an airframe calibration setting.
|
||||
fn latest_sample(samples: ImuBatch, mount: ImuMount) -> ImuEvent {
|
||||
// Scheduled MAVLink publication retains only the newest validated record.
|
||||
let sample = samples
|
||||
.as_slice()
|
||||
.last()
|
||||
.expect("driver batches are nonempty");
|
||||
ImuEvent::Sample(align_mount(*sample, mount))
|
||||
}
|
||||
|
||||
/// Applies the fixed IMU-to-body transform from the board wiring.
|
||||
fn align_mount(mut sample: ImuSnapshot, mount: ImuMount) -> ImuSnapshot {
|
||||
match mount {
|
||||
ImuMount::BodyAligned => sample,
|
||||
@@ -183,6 +188,7 @@ mod tests {
|
||||
use crate::ImuMount;
|
||||
use crate::f722::peripherals::{Spi1Error, Spi3Error};
|
||||
use kaptan_drivers::{
|
||||
ImuBatch,
|
||||
icm42688::{Error as Icm42688Error, Icm42688ServiceEvent},
|
||||
mpu6000::{Error as Mpu6000Error, Mpu6000ServiceEvent},
|
||||
};
|
||||
@@ -208,7 +214,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mpu_samples_apply_declared_mount_without_changing_timestamp_or_temperature() {
|
||||
fn aligns_latest_fifo_sample() {
|
||||
let sample = ImuSnapshot::new(
|
||||
Timestamp::from_microseconds(123),
|
||||
[10, 20, 30],
|
||||
@@ -220,18 +226,23 @@ mod tests {
|
||||
(ImuMount::Yaw180, [-10, -20, 30], [-40, -50, 60]),
|
||||
(ImuMount::Yaw270, [-20, 10, 30], [-50, 40, 60]),
|
||||
] {
|
||||
let ImuEvent::Sample(aligned) = mpu_event(Mpu6000ServiceEvent::Sample(sample), mount)
|
||||
let mut samples = ImuBatch::new(sample);
|
||||
let later = ImuSnapshot {
|
||||
timestamp: Timestamp::from_microseconds(456),
|
||||
..sample
|
||||
};
|
||||
samples.push(later).unwrap();
|
||||
let ImuEvent::Sample(aligned) = mpu_event(Mpu6000ServiceEvent::Samples(samples), mount)
|
||||
else {
|
||||
panic!("sample event must stay a sample");
|
||||
panic!("validated batch must produce a sample");
|
||||
};
|
||||
assert_eq!(
|
||||
aligned,
|
||||
ImuSnapshot::new(
|
||||
Timestamp::from_microseconds(123),
|
||||
acceleration,
|
||||
angular_rate,
|
||||
25,
|
||||
)
|
||||
ImuSnapshot {
|
||||
acceleration_milligravity: acceleration,
|
||||
angular_rate_milliradians_per_second: angular_rate,
|
||||
..later
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user