feat: implement interleaved sensor measurement timing with slot-based coordination to prevent overlap
This commit is contained in:
@@ -289,6 +289,7 @@ async fn main(spawner: Spawner) {
|
|||||||
standard_moisture_id,
|
standard_moisture_id,
|
||||||
standard_identify_id,
|
standard_identify_id,
|
||||||
standard_firmware_build_id,
|
standard_firmware_build_id,
|
||||||
|
slot,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
@@ -369,7 +370,7 @@ async fn can_task(
|
|||||||
warn: &'static mut Output<'static>,
|
warn: &'static mut Output<'static>,
|
||||||
identify_id: StandardId,
|
identify_id: StandardId,
|
||||||
moisture_id: StandardId,
|
moisture_id: StandardId,
|
||||||
firmware_build_id: StandardId,
|
_firmware_build_id: StandardId,
|
||||||
) {
|
) {
|
||||||
// Non-blocking beacon blink timing.
|
// Non-blocking beacon blink timing.
|
||||||
// We keep this inside the CAN task so it can't stall other tasks (like `worker`) with `await`s.
|
// We keep this inside the CAN task so it can't stall other tasks (like `worker`) with `await`s.
|
||||||
@@ -469,6 +470,7 @@ async fn worker(
|
|||||||
moisture_id: StandardId,
|
moisture_id: StandardId,
|
||||||
identify_id: StandardId,
|
identify_id: StandardId,
|
||||||
firmware_build_id: StandardId,
|
firmware_build_id: StandardId,
|
||||||
|
slot: SensorSlot,
|
||||||
) {
|
) {
|
||||||
// 555 emulation state: Q initially Low
|
// 555 emulation state: Q initially Low
|
||||||
let mut q_high = false;
|
let mut q_high = false;
|
||||||
@@ -478,6 +480,33 @@ async fn worker(
|
|||||||
const AVG_WINDOWS: u32 = 4;
|
const AVG_WINDOWS: u32 = 4;
|
||||||
const YIELD_EVERY: u32 = 64;
|
const YIELD_EVERY: u32 = 64;
|
||||||
let probe_duration = Duration::from_millis(100);
|
let probe_duration = Duration::from_millis(100);
|
||||||
|
let measurement_time = probe_duration.as_millis() * AVG_WINDOWS as u64; // 400ms
|
||||||
|
let interleaving_gap = Duration::from_millis(50);
|
||||||
|
|
||||||
|
// Interleaving timing to ensure A and B never overlap:
|
||||||
|
// - Sensor A: measures for 400ms
|
||||||
|
// - Gap: 50ms
|
||||||
|
// - Sensor B: measures for 400ms
|
||||||
|
// - Gap: 50ms
|
||||||
|
// Total cycle: 900ms, so each sensor measures every 900ms (~1.1 measurements/second)
|
||||||
|
//
|
||||||
|
// Timeline:
|
||||||
|
// 0-400ms: A measures, B idle
|
||||||
|
// 400-450ms: both idle (gap)
|
||||||
|
// 450-850ms: B measures, A idle
|
||||||
|
// 850-900ms: both idle (gap)
|
||||||
|
// Then repeat from 0ms
|
||||||
|
|
||||||
|
// Initial offset: B waits for A's measurement time + one gap
|
||||||
|
match slot {
|
||||||
|
SensorSlot::A => {
|
||||||
|
// A sensors start measuring immediately
|
||||||
|
}
|
||||||
|
SensorSlot::B => {
|
||||||
|
// B sensors wait for A to finish measuring + gap
|
||||||
|
Timer::after(Duration::from_millis(measurement_time + interleaving_gap.as_millis())).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut total_pulses: u32 = 0;
|
let mut total_pulses: u32 = 0;
|
||||||
@@ -555,6 +584,12 @@ async fn worker(
|
|||||||
if let Some(build_frame) = CanFrame::new(firmware_build_id, &FIRMWARE_BUILD_MINUTES.to_be_bytes()) {
|
if let Some(build_frame) = CanFrame::new(firmware_build_id, &FIRMWARE_BUILD_MINUTES.to_be_bytes()) {
|
||||||
CAN_TX_CH.send(build_frame).await;
|
CAN_TX_CH.send(build_frame).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for the other slot to measure, plus gaps to ensure no overlap
|
||||||
|
// After A finishes measuring: wait 50ms (gap) + 400ms (B measures) + 50ms (gap) = 500ms
|
||||||
|
// After B finishes measuring: wait 50ms (gap) + 400ms (A measures) + 50ms (gap) = 500ms
|
||||||
|
// This ensures the full 900ms cycle is maintained and A/B never overlap
|
||||||
|
Timer::after(Duration::from_millis(interleaving_gap.as_millis() + measurement_time + interleaving_gap.as_millis())).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user