libs/kaptan-runtime:telemetry: use best-effort approach

Signed-off-by: Onur Özkan <work@onurozkan.dev>
This commit is contained in:
Onur Özkan committed 2026-07-19 23:20:34 +03:00
1 parent 869991b6ef
commit 3738bf4fda
1 file changed
+12 -18
+12 -18
View File
@@ -5,15 +5,13 @@ use kaptan_mavlink::{MavlinkFrame, MavlinkSender, message::MavState};
use kaptan_sensor::ImuSnapshot; use kaptan_sensor::ImuSnapshot;
use kaptan_tx::{FrameClass, PendingFrame, TransmitQueue}; use kaptan_tx::{FrameClass, PendingFrame, TransmitQueue};
/// Terminal fault from the telemetry worker. /// Failure while preparing or starting one telemetry frame.
#[derive(Debug)] #[derive(Debug)]
pub enum TelemetryFault<MemoryError, EngineError> { pub enum TelemetryFault<MemoryError, EngineError> {
/// DMA-visible frame preparation failed. /// DMA-visible frame preparation failed.
Memory(MemoryError), Memory(MemoryError),
/// The UART DMA route rejected or faulted a transfer. /// The UART DMA route rejected a transfer start.
Engine(EngineError), Engine(EngineError),
/// The DMA route cannot continue without explicit board recovery.
RouteHalted,
} }
/// Owns MAVLink packet sequencing and UART DMA frame lifecycle. /// Owns MAVLink packet sequencing and UART DMA frame lifecycle.
@@ -61,20 +59,19 @@ where
self.enqueue_and_start(FrameClass::Critical, frame) self.enqueue_and_start(FrameClass::Critical, frame)
} }
/// Releases a completed DMA frame and starts at most one next frame. /// Releases a terminal DMA frame and opportunistically starts the next.
pub fn on_dma_complete( ///
&mut self, /// Telemetry is best-effort: a terminal route fault drops only the active
completion: TxCompletion, /// frame and a rejected follow-up start is retried on later publication.
) -> Result<(), TelemetryFault<Memory::Error, Engine::StartError>> { pub fn on_dma_complete(&mut self, completion: TxCompletion) {
match completion { match completion {
TxCompletion::NotPending => Ok(()), TxCompletion::NotPending => {}
TxCompletion::Complete => { TxCompletion::Complete => {
let _ = self.transmit.complete(); let _ = self.transmit.complete();
self.start_next() let _ = self.start_next();
} }
TxCompletion::TransferFault | TxCompletion::Halted => { TxCompletion::TransferFault | TxCompletion::Halted => {
let _ = self.transmit.fail(); let _ = self.transmit.fail();
Err(TelemetryFault::RouteHalted)
} }
} }
} }
@@ -103,7 +100,7 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{TelemetryFault, TelemetryService}; use super::TelemetryService;
use kaptan_dma::{DmaReadableBuffer, DmaTxBufferFactory, DmaTxEngine, TxCompletion}; use kaptan_dma::{DmaReadableBuffer, DmaTxBufferFactory, DmaTxEngine, TxCompletion};
use kaptan_sensor::ImuSnapshot; use kaptan_sensor::ImuSnapshot;
use kaptan_time::Timestamp; use kaptan_time::Timestamp;
@@ -134,16 +131,13 @@ mod tests {
} }
#[test] #[test]
fn transfer_fault_halts_without_starting_the_next_frame() { fn transfer_fault_drops_only_the_active_frame() {
let mut service = TelemetryService::<Memory, Engine, 2>::new(1, 1, Memory, Engine); let mut service = TelemetryService::<Memory, Engine, 2>::new(1, 1, Memory, Engine);
service.publish_sample(&sample(1)).unwrap(); service.publish_sample(&sample(1)).unwrap();
service.publish_sample(&sample(2)).unwrap(); service.publish_sample(&sample(2)).unwrap();
assert!(service.transmit.is_active()); assert!(service.transmit.is_active());
assert!(matches!( service.on_dma_complete(TxCompletion::TransferFault);
service.on_dma_complete(TxCompletion::TransferFault),
Err(TelemetryFault::RouteHalted)
));
assert!(!service.transmit.is_active()); assert!(!service.transmit.is_active());
} }
} }