platform: inhibit motor pins and remove output routes

This commit is contained in:
Onur Özkan committed 2026-08-09 13:57:49 +03:00
1 parent 5cb4b7df68
commit b0d22b61d8
19 files changed
+426 -1126

No files matched your search

+22 -81
View File
@@ -14,7 +14,6 @@ use core::marker::PhantomData;
pub use kaptan_board::BoardConfig;
use kaptan_board::BoardConfigError;
mod actuator;
mod f722;
/// Dependencies used only while the platform expands its private RTIC macro.
@@ -23,11 +22,12 @@ pub(crate) mod __platform_internal {
pub(crate) use cortex_m as cm;
pub(crate) use cortex_m_rt as cmrt;
pub(crate) use kaptan_dma as dma;
pub(crate) use kaptan_mavlink as mavlink;
pub(crate) use kaptan_spi as spi;
#[cfg(not(test))]
pub(crate) use panic_halt as panic;
pub(crate) use rtic as rtic_app;
pub(crate) use stm32f7 as pac;
#[cfg(test)]
pub(crate) mod panic {}
}
/// Construction or validation failure for a declarative F722 board.
@@ -103,48 +103,6 @@ pub struct Pa4;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Pc3;
/// Motor-output component selector.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MotorOutputs;
/// Kakute TIM3/TIM5 motor route before selecting a waveform protocol.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct KakuteTim3Tim5Motors;
/// GEPRC TIM3/TIM5 motor route before selecting a waveform protocol.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct GeprcTim3Tim5Motors;
/// Validated Kakute TIM3/TIM5 DShot600 motor route.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct KakuteTim3Tim5Dshot600;
/// Validated GEPRC TIM3/TIM5 DShot600 motor route.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct GeprcTim3Tim5Dshot600;
impl MotorOutputs {
/// Selects Kakute's M1–M4 mapping: PB0, PB1, PB4, PB5.
pub const fn kakute_tim3_tim5() -> KakuteTim3Tim5Motors {
KakuteTim3Tim5Motors
}
/// Selects GEPRC's M1–M4 mapping: PB4, PB5, PB0, PB1.
pub const fn geprc_tim3_tim5() -> GeprcTim3Tim5Motors {
GeprcTim3Tim5Motors
}
}
impl KakuteTim3Tim5Motors {
/// Selects the platform-validated DShot600 waveform configuration.
pub const fn dshot600(self) -> KakuteTim3Tim5Dshot600 {
KakuteTim3Tim5Dshot600
}
}
impl GeprcTim3Tim5Motors {
/// Selects the platform-validated DShot600 waveform configuration.
pub const fn dshot600(self) -> GeprcTim3Tim5Dshot600 {
GeprcTim3Tim5Dshot600
}
}
/// MAVLink component selector.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Mavlink;
@@ -208,13 +166,8 @@ pub struct Missing;
/// typestate. A final `build()` exists only for complete supported route
/// combinations, so omitted or cross-wired essential routes fail to compile at
/// the board declaration.
pub struct F7BoardBuilder<
Imu = Missing,
Motors = Missing,
MavlinkRoute = Missing,
Vertical = Missing,
> {
_state: PhantomData<(Imu, Motors, MavlinkRoute, Vertical)>,
pub struct F7BoardBuilder<Imu = Missing, MavlinkRoute = Missing, Vertical = Missing> {
_state: PhantomData<(Imu, MavlinkRoute, Vertical)>,
}
impl F7BoardBuilder {
@@ -232,21 +185,14 @@ impl Default for F7BoardBuilder {
}
}
impl<I, M, T, V> F7BoardBuilder<I, M, T, V> {
impl<I, T, V> F7BoardBuilder<I, T, V> {
/// Selects an IMU route descriptor.
///
/// Only a complete, profile-compatible descriptor has a final
/// [`F7BoardBuilder::build`] implementation. Keeping this one selection
/// operation uniform avoids teaching a board author platform profile
/// mechanics merely because the selected IMU model differs.
pub fn imu<Selected>(self, _: Selected) -> F7BoardBuilder<Selected, M, T, V> {
F7BoardBuilder {
_state: PhantomData,
}
}
/// Selects the TIM3/TIM5 DShot600 output route.
pub fn motors<Selected>(self, _: Selected) -> F7BoardBuilder<I, Selected, T, V> {
pub fn imu<Selected>(self, _: Selected) -> F7BoardBuilder<Selected, T, V> {
F7BoardBuilder {
_state: PhantomData,
}
@@ -254,7 +200,7 @@ impl<I, M, T, V> F7BoardBuilder<I, M, T, V> {
/// Selects a validated MAVLink route. Only profile-compatible route types
/// have a final [`F7BoardBuilder::build`] implementation.
pub fn mavlink<Selected>(self, _: Selected) -> F7BoardBuilder<I, M, Selected, V> {
pub fn mavlink<Selected>(self, _: Selected) -> F7BoardBuilder<I, Selected, V> {
F7BoardBuilder {
_state: PhantomData,
}
@@ -262,7 +208,7 @@ impl<I, M, T, V> F7BoardBuilder<I, M, T, V> {
/// Selects a validated vertical-sensor route. Its capability is checked
/// against [`F7Board::CONFIG`] before any peripheral is initialized.
pub fn vertical_sensor<Selected>(self, _: Selected) -> F7BoardBuilder<I, M, T, Selected> {
pub fn vertical_sensor<Selected>(self, _: Selected) -> F7BoardBuilder<I, T, Selected> {
F7BoardBuilder {
_state: PhantomData,
}
@@ -285,7 +231,6 @@ pub(crate) enum F722Profile {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct F722BoardRoutes {
profile: F722Profile,
motors: f722::MotorRoute,
vertical: f722::VerticalRoute,
}
@@ -297,12 +242,11 @@ impl F722BoardRoutes {
macro_rules! impl_mpu6000_routes {
($vertical:ty, $route:expr) => {
impl F7BoardBuilder<Mpu6000Spi1Exti4, KakuteTim3Tim5Dshot600, MavlinkUsart1, $vertical> {
impl F7BoardBuilder<Mpu6000Spi1Exti4, MavlinkUsart1, $vertical> {
/// Finishes a complete supported MPU6000 F722 declaration.
pub const fn build(self) -> Result<F722BoardRoutes, BoardError> {
Ok(F722BoardRoutes {
profile: F722Profile::Mpu6000Spi1Usart1,
motors: f722::MotorRoute::KakuteTim3Tim5,
vertical: $route,
})
}
@@ -316,12 +260,11 @@ impl_mpu6000_routes!(NoVerticalSensor, f722::VerticalRoute::None);
macro_rules! impl_icm42688_routes {
($vertical:ty, $route:expr) => {
impl F7BoardBuilder<Icm42688Spi3Exti3, GeprcTim3Tim5Dshot600, MavlinkUsart2, $vertical> {
impl F7BoardBuilder<Icm42688Spi3Exti3, MavlinkUsart2, $vertical> {
/// Finishes a complete supported ICM-42688-P F722 declaration.
pub const fn build(self) -> Result<F722BoardRoutes, BoardError> {
Ok(F722BoardRoutes {
profile: F722Profile::Icm42688Spi3Usart2,
motors: f722::MotorRoute::GeprcTim3Tim5,
vertical: $route,
})
}
@@ -333,30 +276,28 @@ impl_icm42688_routes!(NoVerticalSensor, f722::VerticalRoute::None);
impl_icm42688_routes!(Mtf01Uart4, f722::VerticalRoute::Mtf01);
impl_icm42688_routes!(LidarLiteV3I2c1, f722::VerticalRoute::LidarLiteV3);
/// Missing and cross-profile route selections are rejected before firmware is
/// Missing and cross-profile route selections are rejected before board I/O is
/// linked, because no matching `build` implementation exists.
///
/// ```compile_fail
/// use platform_stm32f7::{
/// F7BoardBuilder, Mavlink, MotorOutputs, Mpu6000, Pa4,
/// F7BoardBuilder, Mavlink, Mpu6000, Pa4,
/// };
///
/// let _ = F7BoardBuilder::new()
/// .imu(Mpu6000::on_spi1().with_drdy(Pa4))
/// .motors(MotorOutputs::kakute_tim3_tim5().dshot600())
/// .mavlink(Mavlink::on_usart1())
/// .build(); // vertical route is missing
/// ```
///
/// ```compile_fail
/// use platform_stm32f7::{
/// F7BoardBuilder, Icm42688, Mavlink, MotorOutputs, Pc3,
/// F7BoardBuilder, Icm42688, Mavlink, Pc3,
/// VerticalSensor,
/// };
///
/// let _ = F7BoardBuilder::new()
/// .imu(Icm42688::on_spi3().with_drdy(Pc3))
/// .motors(MotorOutputs::geprc_tim3_tim5().dshot600())
/// .mavlink(Mavlink::on_usart1()) // ICM route requires USART2
/// .vertical_sensor(VerticalSensor::none())
/// .build();
@@ -364,15 +305,14 @@ impl_icm42688_routes!(LidarLiteV3I2c1, f722::VerticalRoute::LidarLiteV3);
///
/// ```compile_fail
/// use platform_stm32f7::{
/// F7BoardBuilder, Icm42688, Mavlink, MotorOutputs, Pc3, VerticalSensor,
/// F7BoardBuilder, Icm42688, Mavlink, Pc3, VerticalSensor,
/// };
///
/// let _ = F7BoardBuilder::new()
/// .imu(Icm42688::on_spi3().with_drdy(Pc3))
/// .motors(MotorOutputs::kakute_tim3_tim5().dshot600())
/// .mavlink(Mavlink::on_usart2())
/// .vertical_sensor(VerticalSensor::none())
/// .build(); // ICM/USART2 uses the GEPRC logical motor order.
/// .build(); // MPU6000/USART1 is the only other supported profile.
/// ```
/// Contract implemented by a declarative STM32F722 board crate.
pub trait F7Board {
@@ -394,7 +334,10 @@ macro_rules! enforce_f7_board_contract {
};
}
/// Installs the platform-owned RTIC flight firmware for a declarative board.
/// Installs the one platform-owned RTIC application for a declarative board.
///
/// Board crates can only select one of the reviewed physical-sensor telemetry
/// route descriptors; RTIC ownership stays platform-private.
///
/// The application binds the finite superset of interrupt roles needed by the
/// currently supported F722 profiles. The route declaration selects which
@@ -416,11 +359,11 @@ macro_rules! flight_firmware {
<$board as $crate::F7Board>::build($crate::F7BoardBuilder::new())
}
#[used]
static KAPTAN_F722_PLATFORM_FIRMWARE: fn() = $crate::firmware_anchor;
static KAPTAN_F722_PLATFORM_FLIGHT: fn() = $crate::firmware_anchor;
};
}
/// Link anchor for the platform-owned F722 RTIC application.
/// Link anchor for the platform-owned F722 board-I/O application.
#[doc(hidden)]
pub fn firmware_anchor() {}
@@ -432,7 +375,6 @@ mod tests {
fn route_descriptors_select_the_mpu6000_profile() {
let routes = F7BoardBuilder::new()
.imu(Mpu6000::on_spi1().with_drdy(Pa4))
.motors(MotorOutputs::kakute_tim3_tim5().dshot600())
.mavlink(Mavlink::on_usart1())
.vertical_sensor(VerticalSensor::mtf01_on_uart4())
.build()
@@ -444,7 +386,6 @@ mod tests {
fn route_descriptors_select_the_icm42688_profile() {
let routes = F7BoardBuilder::new()
.imu(Icm42688::on_spi3().with_drdy(Pc3))
.motors(MotorOutputs::geprc_tim3_tim5().dshot600())
.mavlink(Mavlink::on_usart2())
.vertical_sensor(VerticalSensor::none())
.build()