feat(firmware): validate configuration and migrate sensor-driven flight APIs
Validate configuration through its owning schemas and keep board declarations separate from shared F722 resource ownership. Bound USB transitions, isolate transport failures and retain restart-only activation. Migrate navigation and flight consumers with the sensor and schema contracts. Require explicit installation data and synchronous output authority; board motor outputs remain inhibited. Validation: assembled-prefix host tests, strict Clippy, platform/USB tests and both ARM release builds. Final-source coverage and scoped Miri/Kani evidence are retained separately from hardware qualification.
This commit is contained in:
1 parent
fb1b8af2d1
commit
f9a61a086f
211 files changed
+45657
-12740
No files matched your search
@@ -1,13 +1,13 @@
|
||||
//! Common former-motor-pin interlock for every F722 image.
|
||||
//!
|
||||
//! This is intentionally independent of profile initialization and is called
|
||||
//! as the first PAC access. The GPIO-low interlock is a separate electrical
|
||||
//! boundary from all telemetry initialization.
|
||||
//! Motor GPIO-low interlock, called before all fallible initialization.
|
||||
|
||||
use crate::MotorPins;
|
||||
use stm32f7::stm32f722;
|
||||
|
||||
/// Drives PB0/PB1/PB4/PB5 low before selecting push-pull GPIO output mode.
|
||||
pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GPIOB) {
|
||||
pub(crate) fn inhibit(
|
||||
rcc: &stm32f722::rcc::RegisterBlock,
|
||||
port: &stm32f722::gpiob::RegisterBlock,
|
||||
pins: MotorPins,
|
||||
) {
|
||||
rcc.ahb1enr().modify(|_, write| write.gpioben().set_bit());
|
||||
// RM0431 section 5.2.12 requires two peripheral clock cycles before the
|
||||
// first access. The volatile enable-register read supplies the standard
|
||||
@@ -15,7 +15,7 @@ pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GP
|
||||
// ahead of the clock enable.
|
||||
let _ = rcc.ahb1enr().read().gpioben().bit_is_set();
|
||||
port.bsrr().write(|write| {
|
||||
write
|
||||
let write = write
|
||||
.br0()
|
||||
.set_bit()
|
||||
.br1()
|
||||
@@ -23,10 +23,15 @@ pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GP
|
||||
.br4()
|
||||
.set_bit()
|
||||
.br5()
|
||||
.set_bit()
|
||||
.set_bit();
|
||||
if pins == MotorPins::Six {
|
||||
write.br6().set_bit().br7().set_bit()
|
||||
} else {
|
||||
write
|
||||
}
|
||||
});
|
||||
port.otyper().modify(|_, write| {
|
||||
write
|
||||
let write = write
|
||||
.ot0()
|
||||
.push_pull()
|
||||
.ot1()
|
||||
@@ -34,10 +39,15 @@ pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GP
|
||||
.ot4()
|
||||
.push_pull()
|
||||
.ot5()
|
||||
.push_pull()
|
||||
.push_pull();
|
||||
if pins == MotorPins::Six {
|
||||
write.ot6().push_pull().ot7().push_pull()
|
||||
} else {
|
||||
write
|
||||
}
|
||||
});
|
||||
port.ospeedr().modify(|_, write| {
|
||||
write
|
||||
let write = write
|
||||
.ospeedr0()
|
||||
.low_speed()
|
||||
.ospeedr1()
|
||||
@@ -45,10 +55,15 @@ pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GP
|
||||
.ospeedr4()
|
||||
.low_speed()
|
||||
.ospeedr5()
|
||||
.low_speed()
|
||||
.low_speed();
|
||||
if pins == MotorPins::Six {
|
||||
write.ospeedr6().low_speed().ospeedr7().low_speed()
|
||||
} else {
|
||||
write
|
||||
}
|
||||
});
|
||||
port.pupdr().modify(|_, write| {
|
||||
write
|
||||
let write = write
|
||||
.pupdr0()
|
||||
.floating()
|
||||
.pupdr1()
|
||||
@@ -56,10 +71,15 @@ pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GP
|
||||
.pupdr4()
|
||||
.floating()
|
||||
.pupdr5()
|
||||
.floating()
|
||||
.floating();
|
||||
if pins == MotorPins::Six {
|
||||
write.pupdr6().floating().pupdr7().floating()
|
||||
} else {
|
||||
write
|
||||
}
|
||||
});
|
||||
port.moder().modify(|_, write| {
|
||||
write
|
||||
let write = write
|
||||
.moder0()
|
||||
.output()
|
||||
.moder1()
|
||||
@@ -67,6 +87,51 @@ pub(crate) fn inhibit_pb0_pb1_pb4_pb5(rcc: &stm32f722::RCC, port: &stm32f722::GP
|
||||
.moder4()
|
||||
.output()
|
||||
.moder5()
|
||||
.output()
|
||||
.output();
|
||||
if pins == MotorPins::Six {
|
||||
write.moder6().output().moder7().output()
|
||||
} else {
|
||||
write
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
#[test]
|
||||
fn inhibits_only_board_motor_pins() {
|
||||
for (pins, pin_mask, field_mask, output_mode) in [
|
||||
(MotorPins::Four, 0x0033, 0x0f0f, 0x0505),
|
||||
(MotorPins::Six, 0x00f3, 0xff0f, 0x5505),
|
||||
] {
|
||||
// SAFETY: these PAC blocks contain u32 volatile cells and reserved
|
||||
// bytes. Zero is valid, and this test owns their ordinary RAM storage.
|
||||
let (rcc, port) = unsafe {
|
||||
(
|
||||
MaybeUninit::<stm32f722::rcc::RegisterBlock>::zeroed().assume_init(),
|
||||
MaybeUninit::<stm32f722::gpiob::RegisterBlock>::zeroed().assume_init(),
|
||||
)
|
||||
};
|
||||
// SAFETY: writes initialize only the test's local register storage.
|
||||
unsafe {
|
||||
rcc.ahb1enr().write(|write| write.bits(1));
|
||||
port.moder().write(|write| write.bits(u32::MAX));
|
||||
port.otyper().write(|write| write.bits(0xffff));
|
||||
port.ospeedr().write(|write| write.bits(u32::MAX));
|
||||
port.pupdr().write(|write| write.bits(0xaaaa_aaaa));
|
||||
}
|
||||
inhibit(&rcc, &port, pins);
|
||||
assert_eq!(rcc.ahb1enr().read().bits(), 3);
|
||||
// SAFETY: this reads the local backing cell, not a hardware write-only register.
|
||||
let reset = unsafe { port.bsrr().as_ptr().read_volatile() };
|
||||
assert_eq!(reset, pin_mask << 16);
|
||||
assert_eq!(port.moder().read().bits(), !field_mask | output_mode);
|
||||
assert_eq!(port.otyper().read().bits(), 0xffff & !pin_mask);
|
||||
assert_eq!(port.ospeedr().read().bits(), !field_mask);
|
||||
assert_eq!(port.pupdr().read().bits(), 0xaaaa_aaaa & !field_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user