Skip to content
File

Blob: firmware/crates/esp32-radio/src/metrics.rs

rust85 lines
1//! Low-priority sampling on core 1 refreshes idle accounting even while FFT sleeps.
2use crate::{error::Result, platform};
3use radio_core::metrics::{CpuWindow, Hardware};
4use std::{
5 sync::mpsc::{Receiver, SyncSender, TrySendError, sync_channel},
6 thread,
7 time::Duration,
8};
9 
10#[derive(Clone, Copy)]
11pub(crate) struct Reading {
12 pub hardware: Hardware,
13 pub rssi: Option<i32>,
14}
15pub(crate) struct Client {
16 receiver: Receiver<Reading>,
17 latest: Option<Reading>,
18}
19pub(crate) struct Worker {
20 sender: SyncSender<Reading>,
21}
22 
23pub(crate) fn channel() -> (Client, Worker) {
24 let (sender, receiver) = sync_channel(1);
25 (
26 Client {
27 receiver,
28 latest: None,
29 },
30 Worker { sender },
31 )
32}
33 
34impl Client {
35 pub(crate) fn latest(&mut self, now_us: u64) -> Option<Reading> {
36 if let Ok(reading) = self.receiver.try_recv() {
37 self.latest = Some(reading);
38 }
39 self.latest.filter(|reading| {
40 (now_us / 1000)
41 .checked_sub(reading.hardware.sampled_at_ms)
42 .is_some_and(|age| age <= 3000)
43 })
44 }
45}
46 
47impl Worker {
48 pub(crate) fn run(self) -> Result<()> {
49 let mut native = platform::Metrics::open()?;
50 let mut cpu = CpuWindow::default();
51 let mut next_detailed = 0;
52 let mut stack_free = 0;
53 loop {
54 let started = platform::now_us();
55 let detailed = started >= next_detailed;
56 let sample = native.sample(detailed)?;
57 if detailed {
58 stack_free = platform::stack_free();
59 next_detailed = started + 5_000_000;
60 }
61 let hardware = Hardware {
62 sampled_at_ms: sample.now_us / 1000,
63 cpu_busy_bps: cpu.sample(sample.now_us, sample.idle_us),
64 chip_temperature_mc: sample.temperature_mc,
65 internal: sample.internal,
66 psram: sample.psram,
67 sample_cost_us: platform::now_us()
68 .saturating_sub(started)
69 .min(u32::MAX as u64) as u32,
70 sampler_stack_free: stack_free,
71 };
72 match self.sender.try_send(Reading {
73 hardware,
74 rssi: sample.rssi,
75 }) {
76 Ok(()) | Err(TrySendError::Full(_)) => {}
77 Err(TrySendError::Disconnected(_)) => return Ok(()),
78 }
79 thread::sleep(Duration::from_micros(
80 (started + 1_000_000).saturating_sub(platform::now_us()),
81 ));
82 }
83 }
84}