feat(board): declare immutable telemetry policy
This commit is contained in:
1 parent
2b224f8eb9
commit
a4ef0f0740
4 files changed
+103
-13
No files matched your search
@@ -1,8 +1,8 @@
|
|||||||
//! Declarative support for the GEPRC TAKER F722 BLS 60A V2 stack.
|
//! Declarative support for the GEPRC TAKER F722 BLS 60A V2 stack.
|
||||||
|
|
||||||
use kaptan_board::{
|
use kaptan_board::{
|
||||||
BoardConfig, BoardProfile, DataChannelRates, MavlinkEndpoint, TelemetryProfile,
|
BoardConfig, BoardProfile, DataChannelRates, ImuDevice, ImuMount, MavlinkEndpoint, MavlinkPort,
|
||||||
VerticalSensingKind,
|
Severity, TelemetryProfile, VerticalSensingKind,
|
||||||
};
|
};
|
||||||
use platform_stm32f7::{
|
use platform_stm32f7::{
|
||||||
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Icm42688, Mavlink, Pc3, VerticalSensor,
|
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Icm42688, Mavlink, Pc3, VerticalSensor,
|
||||||
@@ -17,8 +17,12 @@ impl F7Board for GeprcF722V2 {
|
|||||||
mavlink: MavlinkEndpoint {
|
mavlink: MavlinkEndpoint {
|
||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
|
port: MavlinkPort::Serial2,
|
||||||
|
baud: 115_200,
|
||||||
},
|
},
|
||||||
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
||||||
|
imu: ImuDevice::Icm42688,
|
||||||
|
imu_mount: ImuMount::Yaw180,
|
||||||
vertical_sensing: VerticalSensingKind::None,
|
vertical_sensing: VerticalSensingKind::None,
|
||||||
data_channel: DataChannelRates {
|
data_channel: DataChannelRates {
|
||||||
service_hz: 100,
|
service_hz: 100,
|
||||||
@@ -27,6 +31,7 @@ impl F7Board for GeprcF722V2 {
|
|||||||
optical_flow_hz: None,
|
optical_flow_hz: None,
|
||||||
heartbeat_hz: 2,
|
heartbeat_hz: 2,
|
||||||
},
|
},
|
||||||
|
maximum_log_level: Severity::Info,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
//! belong to the STM32F7 platform crate.
|
//! belong to the STM32F7 platform crate.
|
||||||
|
|
||||||
use kaptan_board::{
|
use kaptan_board::{
|
||||||
BoardConfig, BoardProfile, DataChannelRates, MavlinkEndpoint, TelemetryProfile,
|
BoardConfig, BoardProfile, DataChannelRates, ImuDevice, ImuMount, MavlinkEndpoint, MavlinkPort,
|
||||||
VerticalSensingKind,
|
Severity, TelemetryProfile, VerticalSensingKind,
|
||||||
};
|
};
|
||||||
use platform_stm32f7::{
|
use platform_stm32f7::{
|
||||||
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Mavlink, Mpu6000, Pa4, VerticalSensor,
|
BoardError, F7Board, F7BoardBuilder, F722BoardRoutes, Mavlink, Mpu6000, Pa4, VerticalSensor,
|
||||||
@@ -20,8 +20,12 @@ const CONFIG: BoardConfig = BoardConfig {
|
|||||||
mavlink: MavlinkEndpoint {
|
mavlink: MavlinkEndpoint {
|
||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
|
port: MavlinkPort::Serial1,
|
||||||
|
baud: 115_200,
|
||||||
},
|
},
|
||||||
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
||||||
|
imu: ImuDevice::Mpu6000,
|
||||||
|
imu_mount: ImuMount::BodyAligned,
|
||||||
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
||||||
data_channel: DataChannelRates {
|
data_channel: DataChannelRates {
|
||||||
service_hz: 100,
|
service_hz: 100,
|
||||||
@@ -30,6 +34,7 @@ const CONFIG: BoardConfig = BoardConfig {
|
|||||||
optical_flow_hz: Some(20),
|
optical_flow_hz: Some(20),
|
||||||
heartbeat_hz: 2,
|
heartbeat_hz: 2,
|
||||||
},
|
},
|
||||||
|
maximum_log_level: Severity::Info,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ version.workspace = true
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
kaptan-log = { path = "../kaptan-log" }
|
||||||
@@ -6,6 +6,43 @@
|
|||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
use kaptan_log::KaptanError;
|
||||||
|
pub use kaptan_log::Severity;
|
||||||
|
|
||||||
|
/// Physical IMU device selected by a board declaration.
|
||||||
|
///
|
||||||
|
/// This is immutable board topology, not a runtime-selectable sensor driver.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ImuDevice {
|
||||||
|
/// InvenSense MPU-6000 on the board's selected SPI route.
|
||||||
|
Mpu6000,
|
||||||
|
/// TDK ICM-42688-P on the board's selected SPI route.
|
||||||
|
Icm42688,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fixed board-to-body IMU mounting transform.
|
||||||
|
///
|
||||||
|
/// Calibration remains a separate, safety-gated workflow. This declaration
|
||||||
|
/// only selects the compiled transform for the physical board route.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum ImuMount {
|
||||||
|
/// Sensor axes already match the controller body axes.
|
||||||
|
BodyAligned,
|
||||||
|
/// Sensor is yawed 180° relative to the controller body axes.
|
||||||
|
Yaw180,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Logical outbound MAVLink serial endpoint selected by a board declaration.
|
||||||
|
///
|
||||||
|
/// The platform maps these logical names to its checked pin/DMA routes.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum MavlinkPort {
|
||||||
|
/// First supported board serial endpoint.
|
||||||
|
Serial1,
|
||||||
|
/// Second supported board serial endpoint.
|
||||||
|
Serial2,
|
||||||
|
}
|
||||||
|
|
||||||
/// The vertical-sensing data a board support package makes available.
|
/// The vertical-sensing data a board support package makes available.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@@ -25,6 +62,10 @@ pub struct MavlinkEndpoint {
|
|||||||
pub system_id: u8,
|
pub system_id: u8,
|
||||||
/// MAVLink component identifier.
|
/// MAVLink component identifier.
|
||||||
pub component_id: u8,
|
pub component_id: u8,
|
||||||
|
/// Immutable physical serial endpoint selected for this board image.
|
||||||
|
pub port: MavlinkPort,
|
||||||
|
/// UART line rate used by that physical endpoint.
|
||||||
|
pub baud: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fixed outbound data-channel rates driven by a platform service timer.
|
/// Fixed outbound data-channel rates driven by a platform service timer.
|
||||||
@@ -45,10 +86,20 @@ pub struct DataChannelRates {
|
|||||||
/// Telemetry-only physical-sensor and outbound-data policy.
|
/// Telemetry-only physical-sensor and outbound-data policy.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct TelemetryProfile {
|
pub struct TelemetryProfile {
|
||||||
|
/// Immutable physical IMU driver selected by this board image.
|
||||||
|
pub imu: ImuDevice,
|
||||||
|
/// Immutable board-to-body transform applied to that IMU's samples.
|
||||||
|
pub imu_mount: ImuMount,
|
||||||
/// Supported physical vertical-sensing capability.
|
/// Supported physical vertical-sensing capability.
|
||||||
pub vertical_sensing: VerticalSensingKind,
|
pub vertical_sensing: VerticalSensingKind,
|
||||||
/// Data-channel timer and publication rates.
|
/// Data-channel timer and publication rates.
|
||||||
pub data_channel: DataChannelRates,
|
pub data_channel: DataChannelRates,
|
||||||
|
/// Highest optional diagnostic severity forwarded to MAVLink.
|
||||||
|
///
|
||||||
|
/// Errors remain observable even when optional debug/info diagnostics are
|
||||||
|
/// filtered. This setting is compile-time board policy until the target
|
||||||
|
/// has the reviewed configuration activation path.
|
||||||
|
pub maximum_log_level: Severity,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exclusive build-time image selection.
|
/// Exclusive build-time image selection.
|
||||||
@@ -68,12 +119,10 @@ pub enum BoardProfile {
|
|||||||
/// The selected platform trait determines the MCU family. Keeping a free-form
|
/// The selected platform trait determines the MCU family. Keeping a free-form
|
||||||
/// MCU string here would duplicate that type-level fact without validating it.
|
/// MCU string here would duplicate that type-level fact without validating it.
|
||||||
///
|
///
|
||||||
/// TODO(configuration): board images currently receive this complete profile
|
/// Board policy is compiled and non-deserializable. The current F722 platform
|
||||||
/// at build time. Ground-station configuration must stage and validate a
|
/// validates it against typestate-selected electrical routes before it touches
|
||||||
/// whole profile (identity, sensor topology, link rates, actuator profile,
|
/// hardware. Target-side runtime configuration remains disabled until its
|
||||||
/// and calibration revision) before it is persisted. It must never apply
|
/// separate authenticated, journalled, disarmed activation contract exists.
|
||||||
/// independent field updates or permit an active output while a profile is
|
|
||||||
/// staged, committed, or restored after power loss.
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct BoardConfig {
|
pub struct BoardConfig {
|
||||||
/// Stable board name used in build and diagnostic tooling.
|
/// Stable board name used in build and diagnostic tooling.
|
||||||
@@ -95,6 +144,12 @@ impl BoardConfig {
|
|||||||
|
|
||||||
/// Validates the selected exclusive profile.
|
/// Validates the selected exclusive profile.
|
||||||
pub const fn validate(self) -> Result<(), BoardConfigError> {
|
pub const fn validate(self) -> Result<(), BoardConfigError> {
|
||||||
|
if self.mavlink.system_id == 0 || self.mavlink.component_id == 0 {
|
||||||
|
return Err(BoardConfigError::InvalidMavlinkEndpoint);
|
||||||
|
}
|
||||||
|
if self.mavlink.baud == 0 {
|
||||||
|
return Err(BoardConfigError::ZeroMavlinkBaud);
|
||||||
|
}
|
||||||
match self.profile {
|
match self.profile {
|
||||||
BoardProfile::TelemetryOnly(profile) => Self::validate_telemetry(profile),
|
BoardProfile::TelemetryOnly(profile) => Self::validate_telemetry(profile),
|
||||||
BoardProfile::ExternalControlOnly => {
|
BoardProfile::ExternalControlOnly => {
|
||||||
@@ -173,8 +228,12 @@ impl BoardConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Invalid board-support configuration.
|
/// Invalid board-support configuration.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
|
||||||
pub enum BoardConfigError {
|
pub enum BoardConfigError {
|
||||||
|
/// MAVLink system/component identifiers must be exact nonzero values.
|
||||||
|
InvalidMavlinkEndpoint,
|
||||||
|
/// A physical MAVLink endpoint needs a nonzero UART rate.
|
||||||
|
ZeroMavlinkBaud,
|
||||||
/// A data-channel schedule needs a nonzero service frequency.
|
/// A data-channel schedule needs a nonzero service frequency.
|
||||||
ZeroServiceFrequency,
|
ZeroServiceFrequency,
|
||||||
/// Raw IMU and heartbeat are mandatory on every flight board.
|
/// Raw IMU and heartbeat are mandatory on every flight board.
|
||||||
@@ -192,17 +251,22 @@ pub enum BoardConfigError {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
BoardConfig, BoardConfigError, BoardProfile, DataChannelRates, MavlinkEndpoint,
|
BoardConfig, BoardConfigError, BoardProfile, DataChannelRates, ImuDevice, ImuMount,
|
||||||
TelemetryProfile, VerticalSensingKind,
|
MavlinkEndpoint, MavlinkPort, TelemetryProfile, VerticalSensingKind,
|
||||||
};
|
};
|
||||||
|
use kaptan_log::Severity;
|
||||||
|
|
||||||
const BASE: BoardConfig = BoardConfig {
|
const BASE: BoardConfig = BoardConfig {
|
||||||
name: "test",
|
name: "test",
|
||||||
mavlink: MavlinkEndpoint {
|
mavlink: MavlinkEndpoint {
|
||||||
system_id: 1,
|
system_id: 1,
|
||||||
component_id: 1,
|
component_id: 1,
|
||||||
|
port: MavlinkPort::Serial1,
|
||||||
|
baud: 115_200,
|
||||||
},
|
},
|
||||||
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
profile: BoardProfile::TelemetryOnly(TelemetryProfile {
|
||||||
|
imu: ImuDevice::Mpu6000,
|
||||||
|
imu_mount: ImuMount::BodyAligned,
|
||||||
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
|
||||||
data_channel: DataChannelRates {
|
data_channel: DataChannelRates {
|
||||||
service_hz: 100,
|
service_hz: 100,
|
||||||
@@ -211,6 +275,7 @@ mod tests {
|
|||||||
optical_flow_hz: Some(20),
|
optical_flow_hz: Some(20),
|
||||||
heartbeat_hz: 2,
|
heartbeat_hz: 2,
|
||||||
},
|
},
|
||||||
|
maximum_log_level: Severity::Info,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -257,4 +322,18 @@ mod tests {
|
|||||||
Err(BoardConfigError::UnsupportedFlightProfile)
|
Err(BoardConfigError::UnsupportedFlightProfile)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_invalid_immutable_link_policy() {
|
||||||
|
let mut config = BASE;
|
||||||
|
config.mavlink.baud = 0;
|
||||||
|
assert_eq!(config.validate(), Err(BoardConfigError::ZeroMavlinkBaud));
|
||||||
|
|
||||||
|
let mut config = BASE;
|
||||||
|
config.mavlink.component_id = 0;
|
||||||
|
assert_eq!(
|
||||||
|
config.validate(),
|
||||||
|
Err(BoardConfigError::InvalidMavlinkEndpoint)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user