board: make telemetry profile selection explicit

This commit is contained in:
Onur Özkan committed 2026-08-09 13:57:06 +03:00
1 parent c44286bdcf
commit 01463fa878
5 files changed
+158 -96

No files matched your search

+22 -21
View File
@@ -2,7 +2,8 @@
//!
//! This crate owns fixed-rate scheduling, mailbox consumption, vertical-data
//! freshness, MAVLink encoding, and bounded queue classification. A platform
//! supplies only mailbox references, health/arming state, and a transport sink.
//! supplies only mailbox references, a declared MAVLink state, arming state,
//! and a transport sink.
#![no_std]
@@ -57,6 +58,8 @@ pub struct VerticalDataConfig {
/// Data-channel construction failure.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DataChannelError {
/// Rejected profiles must not construct a physical telemetry channel.
NotTelemetryProfile,
/// A configured channel must be due at least once per second.
ZeroRate,
/// A configured channel exceeds the service frequency.
@@ -92,7 +95,10 @@ where
vertical: VerticalDataConfig,
sources: DataSources<'a>,
) -> Result<Self, DataChannelError> {
let schedule = Schedule::from_rates(config.data_channel)?;
let telemetry = config
.telemetry()
.ok_or(DataChannelError::NotTelemetryProfile)?;
let schedule = Schedule::from_rates(telemetry.data_channel)?;
Ok(Self {
sink,
encoder: MavlinkEncoder::new(config.mavlink.system_id, config.mavlink.component_id),
@@ -114,7 +120,7 @@ where
/// No schedule token escapes this method. It refreshes cached vertical
/// observations, selects due data, encodes the MAVLink message, and admits
/// it with the correct bounded-queue class.
pub fn on_service_tick(&mut self, imu_healthy: bool, motors_armed: bool) {
pub fn on_service_tick(&mut self, system_status: MavState, motors_armed: bool) {
self.refresh_vertical_data();
match self.schedule.next_due() {
@@ -148,14 +154,7 @@ where
}
Some(DueData::Heartbeat) => self.sink.send(
FrameClass::Critical,
self.encoder.heartbeat(
if imu_healthy {
MavState::MAV_STATE_STANDBY
} else {
MavState::MAV_STATE_CRITICAL
},
motors_armed,
),
self.encoder.heartbeat(system_status, motors_armed),
),
Some(DueData::Distance | DueData::OpticalFlow) | None => {}
}
@@ -281,7 +280,7 @@ mod tests {
};
use kaptan_board::{BoardConfig, DataChannelRates, MavlinkEndpoint, VerticalSensingKind};
use kaptan_dma::TxCompletion;
use kaptan_mavlink::{MavlinkFrame, transmitter::FrameClass};
use kaptan_mavlink::{MavlinkFrame, message::MavState, transmitter::FrameClass};
use kaptan_sensor::{
imu::ImuSnapshot, optical_flow::OpticalFlowSnapshot, range::RangeSnapshot,
};
@@ -312,14 +311,16 @@ mod tests {
system_id: 1,
component_id: 1,
},
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
data_channel: DataChannelRates {
service_hz: 100,
raw_imu_hz: 20,
range_hz: Some(20),
optical_flow_hz: Some(20),
heartbeat_hz: 2,
},
profile: kaptan_board::BoardProfile::TelemetryOnly(kaptan_board::TelemetryProfile {
vertical_sensing: VerticalSensingKind::RangeAndOpticalFlow,
data_channel: DataChannelRates {
service_hz: 100,
raw_imu_hz: 20,
range_hz: Some(20),
optical_flow_hz: Some(20),
heartbeat_hz: 2,
},
}),
};
#[test]
@@ -367,7 +368,7 @@ mod tests {
100,
100,
));
channel.on_service_tick(true, false);
channel.on_service_tick(MavState::MAV_STATE_STANDBY, false);
}
channel.on_dma_complete(TxCompletion::Complete);