Files
stm32_rust/usart_async_buffered_generalized2/src/uart/safety.rs
2025-10-31 13:19:54 +01:00

58 lines
1.8 KiB
Rust

// src/safety.rs
use defmt::info;
use embassy_time::Duration;
// ISR RX ring capacity = RX_BUF len
const ISR_RX_BUF_CAP: usize = 256;
// Yield 1/2 the time it takes to fill ISR RX ring.
const YIELD_MARGIN_NUM: u32 = 1;
const YIELD_MARGIN_DEN: u32 = 2;
// Ensure RX_PIPE_CAP can hold this.
const WORST_MAIN_LATENCY_MS: u32 = 20;
pub const TX_PIPE_CAP: usize = 1024;
pub const RX_PIPE_CAP: usize = 1024;
/// Perform safety checks and compute yield timing to avoid buffer overflow.
///
/// # Panics
/// Panics if pipe capacities are too small for the configured baud.
pub fn preflight_and_suggest_yield_period(baud: u32) -> Duration {
// Approx bytes per second for 8N1 (10 bits per byte on the wire)
let bytes_per_sec = (baud / 10).max(1);
// Time until ISR RX ring fills, in microseconds.
let t_fill_us = (ISR_RX_BUF_CAP as u64) * 1_000_000u64 / (bytes_per_sec as u64);
// Choose a yield period as a fraction of t_fill.
let yield_us = (t_fill_us as u64)
.saturating_mul(YIELD_MARGIN_NUM as u64)
/ (YIELD_MARGIN_DEN as u64);
// Verify RX pipe can absorb a worst-case app latency so uart_task
// can always forward without dropping when it runs.
let required_rx_pipe = (bytes_per_sec as u64) * (WORST_MAIN_LATENCY_MS as u64) / 1000;
if (RX_PIPE_CAP as u64) < required_rx_pipe {
core::panic!(
"RX pipe too small: have {}B, need >= {}B for {}ms at {} bps",
RX_PIPE_CAP, required_rx_pipe, WORST_MAIN_LATENCY_MS, baud
);
}
info!(
"Preflight: baud={}, rx_isr={}B, rx_pipe={}B, bytes/s={}, t_fill_us={}, yield_us={}",
baud,
ISR_RX_BUF_CAP,
RX_PIPE_CAP,
bytes_per_sec,
t_fill_us,
yield_us
);
// Never choose zero.
Duration::from_micros(yield_us.max(1) as u64)
}