1mod rxpk;
16pub use rxpk::*;
17
18use super::{
19 push_ack, types, write_preamble, Error as PktError, Identifier, MacAddress, SerializablePacket,
20};
21use serde::{Deserialize, Serialize};
22use serde_repr::{Deserialize_repr, Serialize_repr};
23use std::io::{Cursor, Write};
24use types::{DataRate, Modulation};
25
26#[derive(Debug, Clone)]
27pub struct Packet {
28 pub random_token: u16,
29 pub gateway_mac: MacAddress,
30 pub data: Data,
31}
32
33impl Packet {
34 pub fn from_rxpk(gateway_mac: MacAddress, rxpk: RxPk) -> Packet {
35 let rxpk = vec![rxpk];
36 Packet {
37 random_token: 0,
38 gateway_mac,
39 data: Data {
40 rxpk: Some(rxpk),
41 stat: None,
42 },
43 }
44 }
45
46 pub fn from_stat(gateway_mac: MacAddress, stat: Stat) -> Packet {
47 Packet {
48 random_token: 0,
49 gateway_mac,
50 data: Data {
51 rxpk: None,
52 stat: Some(stat),
53 },
54 }
55 }
56
57 pub fn random() -> Packet {
58 let rxpk = vec![RxPk::V1(RxPkV1 {
59 chan: 0,
60 codr: Some(lora_modulation::CodingRate::_4_5),
61 data: vec![0, 0],
62 datr: DataRate::default(),
63 freq: 902.800_000,
64 lsnr: -15.0,
65 modu: Modulation::LORA,
66 rfch: 0,
67 rssi: -80,
68 rssis: Some(-80),
69 size: 12,
70 stat: CRC::OK,
71 tmst: 12,
72 time: None,
73 })];
74
75 Packet {
76 random_token: rand::random(),
77 gateway_mac: MacAddress::from([0; 8]),
78 data: Data {
79 rxpk: Some(rxpk),
80 stat: None,
81 },
82 }
83 }
84}
85
86#[derive(Debug, Serialize, Deserialize, Clone)]
87pub struct Data {
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub rxpk: Option<Vec<RxPk>>,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub stat: Option<Stat>,
92}
93
94#[derive(Debug, Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq)]
95#[repr(i8)]
96pub enum CRC {
97 Disabled = 0,
98 OK = 1,
99 Fail = -1,
100}
101
102use std::fmt;
103impl fmt::Display for RxPk {
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 write!(
106 f,
107 "@{} us, {:.2} MHz, {:?}, {}, snr: {}, len: {}",
108 self.timestamp(),
109 self.frequency(),
110 self.datarate(),
111 if let Some(rssis) = self.signal_rssi() {
112 format!("rssis: {rssis}")
113 } else {
114 format!("rssic: {}", self.channel_rssi())
115 },
116 self.snr(),
117 self.data().len()
118 )
119 }
120}
121
122macro_rules! get_field_ref {
123 ($self:expr, $field:ident) => {
124 match $self {
125 RxPk::V1(pk) => &pk.$field,
126 RxPk::V2(pk) => &pk.$field,
127 }
128 };
129}
130macro_rules! get_field {
131 ($self:expr, $field:ident) => {
132 match $self {
133 RxPk::V1(pk) => pk.$field,
134 RxPk::V2(pk) => pk.$field,
135 }
136 };
137}
138use std::cmp;
139
140impl RxPk {
141 pub fn snr(&self) -> f32 {
142 match self {
143 RxPk::V1(pk) => pk.lsnr,
144 RxPk::V2(pk) => pk
145 .rsig
146 .iter()
147 .fold(-150.0, |max, x| {
149 if (max as i32) < (x.lsnr as i32) {
150 x.lsnr
151 } else {
152 max
153 }
154 }),
155 }
156 }
157
158 pub fn channel_rssi(&self) -> i32 {
159 match self {
160 RxPk::V1(pk) => pk.rssi,
161 RxPk::V2(pk) => pk.rsig.iter().fold(-150, |max, x| cmp::max(max, x.rssic)),
162 }
163 }
164
165 pub fn signal_rssi(&self) -> Option<i32> {
166 match self {
167 RxPk::V1(pk) => pk.rssis,
168 RxPk::V2(pk) => pk.rsig.iter().fold(None, |max, x| {
169 if let Some(rssis) = x.rssis {
170 Some(if let Some(current_max) = max {
171 cmp::max(current_max, rssis)
172 } else {
173 rssis
174 })
175 } else {
176 max
177 }
178 }),
179 }
180 }
181
182 pub fn frequency(&self) -> f64 {
183 get_field!(self, freq)
184 }
185
186 pub fn data(&self) -> &Vec<u8> {
187 get_field_ref!(self, data)
188 }
189
190 pub fn timestamp(&self) -> u32 {
191 get_field!(self, tmst)
192 }
193
194 pub fn time(&self) -> &Option<String> {
195 get_field_ref!(self, time)
196 }
197
198 pub fn datarate(&self) -> DataRate {
199 get_field!(self, datr)
200 }
201
202 pub fn crc_status(&self) -> CRC {
203 get_field!(self, stat)
204 }
205
206 pub fn coding_rate(&self) -> Option<lora_modulation::CodingRate> {
207 get_field!(self, codr)
208 }
209}
210
211#[derive(Debug, Serialize, Deserialize, Clone)]
229pub struct Stat {
230 pub time: String,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub lati: Option<f64>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub long: Option<f64>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub alti: Option<i64>,
237 pub rxnb: u64,
238 pub rxok: u64,
239 pub rxfw: u64,
240 pub ackr: Option<f64>,
242 pub dwnb: u64,
243 pub txnb: u64,
244 pub temp: Option<f64>,
245}
246
247impl SerializablePacket for Packet {
248 fn serialize(&self, buffer: &mut [u8]) -> std::result::Result<u64, PktError> {
249 let mut w = Cursor::new(buffer);
250 write_preamble(&mut w, self.random_token)?;
251 w.write_all(&[Identifier::PushData as u8])?;
252 w.write_all(self.gateway_mac.as_bytes())?;
253 w.write_all(serde_json::to_string(&self.data)?.as_bytes())?;
254 Ok(w.position())
255 }
256}
257
258impl From<Packet> for super::Packet {
259 fn from(packet: Packet) -> super::Packet {
260 super::Packet::Up(super::Up::PushData(packet))
261 }
262}
263
264impl Packet {
265 pub fn into_ack(self) -> push_ack::Packet {
266 push_ack::Packet {
267 random_token: self.random_token,
268 }
269 }
270}
271
272#[cfg(test)]
273mod test {
274 use super::*;
275
276 fn check_given_snr(data: Data, expected_snr: f32) {
277 if let Some(mut rxpk) = data.rxpk {
278 assert_eq!(rxpk.len(), 1);
279 if let Some(rxpk) = rxpk.pop() {
280 assert_eq!(rxpk.snr(), expected_snr)
281 } else {
282 assert!(false)
284 }
285 } else {
286 assert!(false)
288 }
289 }
290
291 #[test]
292 fn rxpk_positive_lsnr() {
293 let json = "{\"rxpk\":[{\"aesk\":0,\"brd\":263,\"codr\":\"4/5\",\"data\":\"QC65rwEA4w8CaH7LyGf/3+dxzrXkkfEsRCcXbFM=\",\"datr\":\"SF12BW125\",\"freq\":868.5,\"jver\":2,\"modu\":\"LORA\",\"rsig\":[{\"ant\":0,\"chan\":7,\"lsnr\":7.8,\"rssic\":-103}],\"size\":29,\"stat\":1,\"time\":\"2022-03-31T07:51:15.709338Z\",\"tmst\":445296860}]}";
294 let parsed: Data = serde_json::from_str(json).expect("Error parsing push_data::Data");
295 check_given_snr(parsed, 7.8);
296 }
297
298 #[test]
299 fn rxpk_negative_lsnr() {
300 let json = "{\"rxpk\":[{\"aesk\":0,\"brd\":261,\"codr\":\"4/5\",\"data\":\"QI8cACQA6iAD3TTei0kPKKyxBA==\",\"datr\":\"SF11BW125\",\"freq\":868.1,\"jver\":2,\"modu\":\"LORA\",\"rsig\":[{\"ant\":0,\"chan\":5,\"lsnr\":-3.5,\"rssic\":-120}],\"size\":19,\"stat\":1,\"time\":\"2022-03-31T07:51:12.631018Z\",\"tmst\":442218540}]}";
301 let parsed: Data = serde_json::from_str(json).expect("Error parsing push_data::Data");
302 check_given_snr(parsed, -3.5);
303 }
304
305 #[test]
306 fn snr_roundtrip() {
307 let json = "{\"rxpk\":[{\"jver\":1,\"tmst\":682631918,\"chan\":0,\"rfch\":0,\"freq\":865.062500,\"mid\": 0,\"stat\":1,\"modu\":\"LORA\",\"datr\":\"SF12BW125\",\"codr\":\"4/5\",\"rssis\":-95,\"lsnr\":6.8,\"foff\":-1300,\"rssi\":-94,\"size\":20,\"data\":\"QNbPNwABAQANyqD8ngiq26Hk4gs=\"}]}";
308 let parsed: Data = serde_json::from_str(json).expect("Error parsing push_data::Data");
309 check_given_snr(parsed.clone(), 6.8);
310 let serialized = serde_json::to_string(&parsed).expect("Error serializing push_data::Data");
311 let reparsed: Data =
312 serde_json::from_str(&serialized).expect("Error parsing push_data::Data");
313 check_given_snr(reparsed, 6.8);
314 }
315}