prns_runtime/runtime/packet_phy_retention/
mod.rs1mod fixed;
2#[cfg(feature = "alloc")]
3mod heap;
4#[cfg(test)]
5mod tests;
6
7use core::num::NonZeroUsize;
8
9use crate::interfaces::{PacketPhyStats, RssiDbm, SignalQualityTenthsPercent, SnrQuarterDb};
10use crate::routing::dedup::PacketHash;
11
12pub use fixed::{fixed_packet_phy_retention, FixedPacketMetricStorage, FixedPacketPhyRetention};
13#[cfg(feature = "alloc")]
14pub use heap::{HeapPacketMetricStorage, HeapPacketPhyRetention, RNS_1_4_2_PACKET_PHY_CAPACITY};
15
16pub trait PacketMetricStorage {
17 type Metric: Copy;
18
19 fn capacity(&self) -> NonZeroUsize;
20 fn len(&self) -> usize;
21 fn is_empty(&self) -> bool {
22 self.len() == 0
23 }
24 fn append(&mut self, packet_hash: PacketHash, metric: Self::Metric);
25 fn replace(&mut self, slot: usize, packet_hash: PacketHash, metric: Self::Metric);
26 fn get(&self, packet_hash: PacketHash) -> Option<Self::Metric>;
27}
28
29struct PacketMetricRetention<Storage> {
30 storage: Storage,
31 next_evict: usize,
32}
33
34impl<Storage: PacketMetricStorage> PacketMetricRetention<Storage> {
35 const fn new(storage: Storage) -> Self {
36 Self {
37 storage,
38 next_evict: 0,
39 }
40 }
41
42 fn remember(&mut self, packet_hash: PacketHash, metric: Storage::Metric) {
43 let capacity = self.storage.capacity().get();
44 if self.storage.len() < capacity {
45 self.storage.append(packet_hash, metric);
46 return;
47 }
48 let slot = self.next_evict;
49 self.storage.replace(slot, packet_hash, metric);
50 self.next_evict = (self.next_evict + 1) % capacity;
51 }
52
53 fn get(&self, packet_hash: PacketHash) -> Option<Storage::Metric> {
54 self.storage.get(packet_hash)
55 }
56}
57
58pub struct PacketPhyRetention<RssiStorage, SnrStorage, QualityStorage> {
59 rssi: PacketMetricRetention<RssiStorage>,
60 snr: PacketMetricRetention<SnrStorage>,
61 quality: PacketMetricRetention<QualityStorage>,
62}
63
64impl<RssiStorage, SnrStorage, QualityStorage>
65 PacketPhyRetention<RssiStorage, SnrStorage, QualityStorage>
66where
67 RssiStorage: PacketMetricStorage<Metric = RssiDbm>,
68 SnrStorage: PacketMetricStorage<Metric = SnrQuarterDb>,
69 QualityStorage: PacketMetricStorage<Metric = SignalQualityTenthsPercent>,
70{
71 pub const fn from_storages(
72 rssi: RssiStorage,
73 snr: SnrStorage,
74 quality: QualityStorage,
75 ) -> Self {
76 Self {
77 rssi: PacketMetricRetention::new(rssi),
78 snr: PacketMetricRetention::new(snr),
79 quality: PacketMetricRetention::new(quality),
80 }
81 }
82
83 pub fn remember(&mut self, packet_hash: PacketHash, stats: PacketPhyStats) {
84 if let Some(rssi) = stats.rssi {
85 self.rssi.remember(packet_hash, rssi);
86 }
87 if let Some(snr) = stats.snr {
88 self.snr.remember(packet_hash, snr);
89 }
90 if let Some(quality) = stats.quality {
91 self.quality.remember(packet_hash, quality);
92 }
93 }
94
95 pub fn get(&self, packet_hash: PacketHash) -> Option<PacketPhyStats> {
96 let stats = PacketPhyStats {
97 rssi: self.rssi.get(packet_hash),
98 snr: self.snr.get(packet_hash),
99 quality: self.quality.get(packet_hash),
100 };
101 (!stats.is_empty()).then_some(stats)
102 }
103}
104
105impl<RssiStorage, SnrStorage, QualityStorage> Default
106 for PacketPhyRetention<RssiStorage, SnrStorage, QualityStorage>
107where
108 RssiStorage: Default + PacketMetricStorage<Metric = RssiDbm>,
109 SnrStorage: Default + PacketMetricStorage<Metric = SnrQuarterDb>,
110 QualityStorage: Default + PacketMetricStorage<Metric = SignalQualityTenthsPercent>,
111{
112 fn default() -> Self {
113 Self::from_storages(
114 RssiStorage::default(),
115 SnrStorage::default(),
116 QualityStorage::default(),
117 )
118 }
119}