Skip to main content

ados_protocol/
node_presence.rs

1//! The `gnss` and `lora` node capability flags, shared by the LAN
2//! `/api/status/full` route and the cloud heartbeat so both transports report
3//! the same answer for the same node.
4
5use std::path::Path;
6use std::time::{Duration, SystemTime};
7
8/// Freshness window of the 1 Hz `gnss.json` sidecar (mirrors `contracts.toml`).
9pub const GNSS_FRESH: Duration = Duration::from_secs(5);
10
11fn unit_on(unit: &str, profile: &str) -> bool {
12    let profile = profile.replace('-', "_");
13    crate::units::find(unit).is_some_and(|u| u.on_profile(&profile))
14}
15
16/// The GNSS lane works: `ados-gnss` runs on this profile (wire or underscore
17/// form) and its sidecar is fresh. The service writes it every second only
18/// while receivers are configured, so a file left by a stopped service goes
19/// stale and does not count.
20pub fn gnss_present(profile: &str, run_dir: &Path, now: SystemTime) -> bool {
21    unit_on("ados-gnss", profile)
22        && crate::sidecar::read_fresh_at::<serde_json::Value>(
23            &run_dir.join("gnss.json"),
24            Some(GNSS_FRESH),
25            now,
26        )
27        .is_fresh()
28}
29
30/// The LoRa lane is enabled: `ados-lora` runs on this profile and the
31/// `lora-enabled` marker sits in the config directory (`etc_dir`).
32pub fn lora_present(profile: &str, etc_dir: &Path) -> bool {
33    unit_on("ados-lora", profile) && etc_dir.join("lora-enabled").exists()
34}