semtech_udp/packet/
pull_resp.rs

1/*
2### 5.4. PULL_RESP packet ###
3That packet type is used by the server to send RF packets and associated
4metadata that will have to be emitted by the gateway.
5
6Bytes  | Function
7:------:|---------------------------------------------------------------------
80      | protocol version = 2
91-2    | random token
103      | PULL_RESP identifier 0x03
114-end  | JSON object, starting with {, ending with }, see section 6
12 */
13use super::{
14    tx_ack, types, write_preamble, Error as PktError, Identifier, MacAddress, SerializablePacket,
15    Tmst,
16};
17
18use serde::{Deserialize, Serialize};
19use std::io::{Cursor, Write};
20use types::{deserialize_codr, serialize_codr, DataRate, Modulation};
21
22#[derive(Debug, Clone)]
23pub struct Packet {
24    pub random_token: u16,
25    pub data: Data,
26}
27
28impl Packet {
29    pub fn into_ack_for_gateway(self, gateway_mac: MacAddress) -> tx_ack::Packet {
30        tx_ack::Packet {
31            gateway_mac,
32            random_token: self.random_token,
33            data: tx_ack::Data::default(),
34        }
35    }
36
37    pub fn into_nack_with_error_for_gateway(
38        self,
39        error: super::tx_ack::Error,
40        gateway_mac: MacAddress,
41    ) -> tx_ack::Packet {
42        tx_ack::Packet {
43            gateway_mac,
44            random_token: self.random_token,
45            data: super::tx_ack::Data::new_with_error(error),
46        }
47    }
48
49    // sets a default Gateway value
50    pub fn into_nack_with_error(self, e: super::tx_ack::Error) -> tx_ack::Packet {
51        self.into_nack_with_error_for_gateway(e, MacAddress::from([0; 8]))
52    }
53
54    // sets a default Gateway value
55    pub fn into_ack(self) -> tx_ack::Packet {
56        self.into_ack_for_gateway(MacAddress::from([0; 8]))
57    }
58}
59
60#[derive(Debug, Serialize, Deserialize, Clone)]
61pub struct Data {
62    pub txpk: TxPk,
63}
64
65impl Data {
66    pub fn from_txpk(txpk: TxPk) -> Data {
67        Data { txpk }
68    }
69}
70
71/*
72 Name |  Type  | Function
73:----:|:------:|--------------------------------------------------------------
74 imme | bool   | Send packet immediately (will ignore tmst & time)
75 tmst | number | Send packet on a certain timestamp value (will ignore time)
76 tmms | number | Send packet at a certain GPS time (GPS synchronization required)
77 freq | number | TX central frequency in MHz (unsigned float, Hz precision)
78 rfch | number | Concentrator "RF chain" used for TX (unsigned integer)
79 powe | number | TX output power in dBm (unsigned integer, dBm precision)
80 modu | string | Modulation identifier "LORA" or "FSK"
81 datr | string | LoRa datarate identifier (eg. SF12BW500)
82 datr | number | FSK datarate (unsigned, in bits per second)
83 codr | string | LoRa ECC coding rate identifier
84 fdev | number | FSK frequency deviation (unsigned integer, in Hz)
85 ipol | bool   | Lora modulation polarization inversion
86 prea | number | RF preamble size (unsigned integer)
87 size | number | RF packet payload size in bytes (unsigned integer)
88 data | string | Base64 encoded RF packet payload, padding optional
89 ncrc | bool   | If true, disable the CRC of the physical layer (optional)
90 */
91
92#[derive(Debug, Serialize, Deserialize, Clone)]
93pub struct TxPk {
94    #[serde(flatten)]
95    pub time: Time,
96    pub freq: f64,        // TX central frequency in MHz (unsigned float, Hz precision)
97    pub rfch: u64,        // Concentrator "RF chain" used for TX (unsigned integer)
98    pub powe: u64,        // TX output power in dBm (unsigned integer, dBm precision)
99    pub modu: Modulation, // Modulation identifier "LORA" or "FSK"
100    pub datr: DataRate,   // LoRa datarate identifier (eg. SF12BW500)
101    #[serde(
102        serialize_with = "serialize_codr",
103        deserialize_with = "deserialize_codr"
104    )]
105    pub codr: Option<lora_modulation::CodingRate>, // LoRa ECC coding rate identifier
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub fdev: Option<u64>, //FSK frequency deviation (unsigned integer, in Hz)
108    pub ipol: bool,       // Lora modulation polarization inversion
109    pub prea: Option<u64>, // RF preamble size (unsigned integer)
110    #[serde(flatten)]
111    pub data: PhyData,
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub ncrc: Option<bool>, // If true, disable the CRC of the physical layer (optional)
114}
115
116#[derive(Debug, Serialize, Deserialize, Clone)]
117pub struct Time {
118    imme: bool, // Send packet immediately (will ignore tmst & time)
119    #[serde(skip_serializing_if = "Option::is_none")]
120    tmst: Option<Tmst>, // Send packet on a certain timestamp value (will ignore time)
121    #[serde(skip_serializing_if = "Option::is_none")]
122    tmms: Option<Tmst>, // Send packet at a certain GPS time (GPS synchronization required)
123}
124
125impl Time {
126    pub fn is_immediate(&self) -> bool {
127        self.imme
128    }
129
130    pub fn tmst(&self) -> Option<u32> {
131        if let Some(Tmst::Tmst(val)) = self.tmst {
132            Some(val)
133        } else {
134            None
135        }
136    }
137
138    pub fn tmms(&self) -> Option<u32> {
139        if let Some(Tmst::Tmst(val)) = self.tmms {
140            Some(val)
141        } else {
142            None
143        }
144    }
145
146    pub fn immediate() -> Time {
147        Time {
148            imme: true,
149            tmst: None,
150            tmms: None,
151        }
152    }
153
154    pub fn by_tmst(tmst: u32) -> Time {
155        Time {
156            imme: false,
157            tmst: Some(Tmst::Tmst(tmst)),
158            tmms: None,
159        }
160    }
161
162    pub fn by_tmms(tmms: u32) -> Time {
163        Time {
164            imme: false,
165            tmst: None,
166            tmms: Some(Tmst::Tmst(tmms)),
167        }
168    }
169}
170
171#[derive(Debug, Serialize, Deserialize, Clone)]
172pub struct PhyData {
173    #[serde(with = "crate::packet::types::base64")]
174    data: Vec<u8>,
175    size: usize,
176}
177
178impl AsRef<[u8]> for PhyData {
179    fn as_ref(&self) -> &[u8] {
180        self.data.as_ref()
181    }
182}
183
184impl PhyData {
185    pub fn new(data: Vec<u8>) -> Self {
186        Self {
187            size: data.len(),
188            data,
189        }
190    }
191    pub fn set(&mut self, data: Vec<u8>) {
192        self.size = data.len();
193        self.data = data;
194    }
195
196    pub fn data(&self) -> &[u8] {
197        self.data.as_ref()
198    }
199    pub fn len(&self) -> usize {
200        self.size
201    }
202
203    pub fn is_empty(&self) -> bool {
204        self.size == 0
205    }
206}
207
208impl TxPk {
209    pub fn is_immediate(&self) -> bool {
210        self.time.imme
211    }
212
213    pub fn get_tmst(&self) -> Option<u32> {
214        if let Some(Tmst::Tmst(tmst)) = self.time.tmst {
215            Some(tmst)
216        } else {
217            None
218        }
219    }
220}
221
222use std::fmt;
223impl fmt::Display for TxPk {
224    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225        write!(
226            f,
227            "{}, {:.2} MHz, {:?}, len: {}",
228            if let Some(Tmst::Tmst(time)) = self.time.tmst {
229                format!("@{time} us")
230            } else {
231                "immediately".into()
232            },
233            self.freq,
234            self.datr,
235            self.data.size
236        )
237    }
238}
239
240impl SerializablePacket for Packet {
241    fn serialize(&self, buffer: &mut [u8]) -> std::result::Result<u64, PktError> {
242        let mut w = Cursor::new(buffer);
243        write_preamble(&mut w, self.random_token)?;
244        w.write_all(&[Identifier::PullResp as u8])?;
245        w.write_all(serde_json::to_string(&self.data)?.as_bytes())?;
246        Ok(w.position())
247    }
248}
249
250impl From<Packet> for super::Packet {
251    fn from(packet: Packet) -> super::Packet {
252        super::Packet::Down(super::Down::PullResp(Box::new(packet)))
253    }
254}
255
256impl From<Box<Packet>> for super::Packet {
257    fn from(packet: Box<Packet>) -> super::Packet {
258        super::Packet::Down(super::Down::PullResp(packet))
259    }
260}