semtech_udp/packet/
tx_ack.rs

1/*
2### 5.5. TX_ACK packet ###
3
4That packet type is used by the gateway to send a feedback to the server
5to inform if a downlink request has been accepted or rejected by the gateway.
6The datagram may optionnaly contain a JSON string to give more details on
7acknoledge. If no JSON is present (empty string), this means than no error
8occured.
9
10Bytes  | Function
11:------:|---------------------------------------------------------------------
120      | protocol version = 2
131-2    | same token as the PULL_RESP packet to acknowledge
143      | TX_ACK identifier 0x05
154-11   | Gateway unique identifier (MAC address)
1612-end | [optional] JSON object, starting with {, ending with }, see section 6
17
18*/
19use super::{write_preamble, Error as PktError, Identifier, MacAddress, SerializablePacket};
20use serde::{Deserialize, Serialize};
21use std::io::{Cursor, Write};
22
23#[derive(Debug, Clone)]
24pub struct Packet {
25    pub random_token: u16,
26    pub gateway_mac: MacAddress,
27    pub data: Data,
28}
29
30impl Packet {
31    pub fn get_result(&self) -> Result<Option<u32>, Error> {
32        self.data.get_result()
33    }
34}
35
36impl SerializablePacket for Packet {
37    fn serialize(&self, buffer: &mut [u8]) -> Result<u64, PktError> {
38        let mut w = Cursor::new(buffer);
39        write_preamble(&mut w, self.random_token)?;
40        w.write_all(&[Identifier::TxAck as u8])?;
41        w.write_all(self.gateway_mac.as_bytes())?;
42        w.write_all(serde_json::to_string(&self.data)?.as_bytes())?;
43        Ok(w.position())
44    }
45}
46
47impl From<Packet> for super::Packet {
48    fn from(packet: Packet) -> super::Packet {
49        super::Packet::Up(super::Up::TxAck(packet))
50    }
51}
52
53// ERRORS
54//
55// Value             | Definition
56// :-----------------:|---------------------------------------------------------------------
57// NONE              | Packet has been programmed for downlink
58// TOO_LATE          | Rejected because it was already too late to program this packet for downlink
59// TOO_EARLY         | Rejected because downlink packet timestamp is too much in advance
60// COLLISION_PACKET  | Rejected because there was already a packet programmed in requested timeframe
61// COLLISION_BEACON  | Rejected because there was already a beacon planned in requested timeframe
62// TX_FREQ           | Rejected because requested frequency is not supported by TX RF chain
63// GPS_UNLOCKED      | Rejected because GPS is unlocked, so GPS timestamp cannot be used
64//
65// WARNINGS
66//
67// Value             | Definition
68// :-----------------:|---------------------------------------------------------------------
69// TX_POWER          | Requested transmit power is not supported by gateway and was reduced. Adjusted power follows in "value", dBm.
70//
71// Examples (white-spaces, indentation and newlines added for readability):
72//
73// ``` json
74// {"txpk_ack":{
75// "error":"COLLISION_PACKET"
76// }}
77// ```
78//
79// ``` json
80// {"txpk_ack":{
81// "warn":"TX_POWER", "value": 27
82// }}
83// ```
84
85/// We take all of the errors from the GWMP protocol.
86/// These are tolerated in both "warn" or "error" fields
87#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
88#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
89enum ErrorField {
90    None,
91    TooLate,
92    TooEarly,
93    CollisionPacket,
94    CollisionBeacon,
95    TxFreq,
96    TxPower,
97    GpsUnlocked,
98    SendLBT,
99    SendFail,
100}
101
102impl From<Result<(), Error>> for ErrorField {
103    fn from(other: Result<(), Error>) -> ErrorField {
104        match other {
105            Err(Error::TooLate) => ErrorField::TooLate,
106            Err(Error::TooEarly) => ErrorField::TooEarly,
107            Err(Error::CollisionPacket) => ErrorField::CollisionPacket,
108            Err(Error::CollisionBeacon) => ErrorField::CollisionBeacon,
109            Err(Error::InvalidTransmitFrequency) => ErrorField::TxFreq,
110            Err(Error::InvalidTransmitPower(_)) => ErrorField::TxPower,
111            Err(Error::AdjustedTransmitPower(_, _)) => ErrorField::TxPower,
112            Err(Error::GpsUnlocked) => ErrorField::GpsUnlocked,
113            Err(Error::SendLBT) => ErrorField::SendLBT,
114            Err(Error::SendFail) => ErrorField::SendFail,
115            _ => ErrorField::None,
116        }
117    }
118}
119
120impl ErrorField {
121    fn as_result(&self, tmst: Option<u32>) -> Result<Option<u32>, Error> {
122        match self {
123            ErrorField::TooEarly => Err(Error::TooEarly),
124            ErrorField::CollisionPacket => Err(Error::CollisionPacket),
125            ErrorField::CollisionBeacon => Err(Error::CollisionBeacon),
126            ErrorField::TooLate => Err(Error::TooLate),
127            ErrorField::TxFreq => Err(Error::InvalidTransmitFrequency),
128            ErrorField::TxPower => Err(Error::InvalidTransmitPower(None)),
129            ErrorField::GpsUnlocked => Err(Error::GpsUnlocked),
130            ErrorField::SendLBT => Err(Error::SendLBT),
131            ErrorField::SendFail => Err(Error::SendFail),
132            ErrorField::None => Ok(tmst),
133        }
134    }
135}
136
137use thiserror::Error;
138#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
139pub enum Error {
140    #[error("TxAck::Error::TOO_LATE")]
141    TooLate,
142    #[error("TxAck::Error::TOO_EARLY")]
143    TooEarly,
144    #[error("TxAck::Error::COLLISION_PACKET")]
145    CollisionPacket,
146    #[error("TxAck::Error::COLLISION_BEACON")]
147    CollisionBeacon,
148    #[error("TxAck::Error::TX_FREQ")]
149    InvalidTransmitFrequency,
150    #[error("TxAck::Error::TX_POWER({0:?})")]
151    InvalidTransmitPower(Option<i32>),
152    #[error("TxAck::Error::ADJUSTED_TX_POWER({0:?})")]
153    AdjustedTransmitPower(Option<i32>, Option<u32>),
154    #[error("TxAck::Error::GPS_UNLOCKED")]
155    GpsUnlocked,
156    #[error("TxAck::Error::SEND_LBT")]
157    SendLBT,
158    #[error("TxAck::Error::SEND_FAIL")]
159    SendFail,
160}
161
162#[derive(Debug, Serialize, Deserialize, Clone)]
163pub struct Data {
164    txpk_ack: TxPkAck,
165}
166
167#[derive(Debug, Serialize, Deserialize, Clone)]
168pub struct TxPkAck {
169    #[serde(skip_serializing_if = "Option::is_none")]
170    tmst: Option<u32>,
171    #[serde(flatten)]
172    result: Option<TxPkAckResult>,
173}
174
175impl Default for Data {
176    fn default() -> Self {
177        Data {
178            txpk_ack: TxPkAck {
179                tmst: None,
180                result: Some(TxPkAckResult::Error {
181                    error: ErrorField::None,
182                }),
183            },
184        }
185    }
186}
187
188impl Data {
189    pub fn new_with_error(error: Error) -> Data {
190        let (tmst, result) = if let Error::AdjustedTransmitPower(value, tmst) = error {
191            (
192                tmst,
193                TxPkAckResult::Warn {
194                    warn: ErrorField::from(Err(error)),
195                    value,
196                },
197            )
198        } else {
199            (
200                None,
201                TxPkAckResult::Error {
202                    error: ErrorField::from(Err(error)),
203                },
204            )
205        };
206        Data {
207            txpk_ack: TxPkAck {
208                tmst,
209                result: Some(result),
210            },
211        }
212    }
213
214    pub fn get_result(&self) -> Result<Option<u32>, Error> {
215        match &self.txpk_ack.result {
216            Some(TxPkAckResult::Error { error }) => (*error).as_result(self.txpk_ack.tmst),
217            Some(TxPkAckResult::Warn { warn, value }) => {
218                // We need special handling of the ErrorField when warning
219                // otherwise, the into will specify it as InvalidTransmitPower
220                if let ErrorField::TxPower = warn {
221                    Err(Error::AdjustedTransmitPower(*value, self.txpk_ack.tmst))
222                } else {
223                    (*warn).as_result(self.txpk_ack.tmst)
224                }
225            }
226            None => Ok(self.txpk_ack.tmst),
227        }
228    }
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
232#[serde(untagged)]
233enum TxPkAckResult {
234    Error {
235        error: ErrorField,
236    },
237    Warn {
238        warn: ErrorField,
239        #[serde(skip_serializing_if = "Option::is_none")]
240        value: Option<i32>,
241    },
242}
243
244impl Default for TxPkAckResult {
245    fn default() -> Self {
246        TxPkAckResult::Error {
247            error: ErrorField::None,
248        }
249    }
250}
251
252#[test]
253fn tx_nack_too_late() {
254    let json = "{\"txpk_ack\": { \"error\": \"TOO_LATE\"}}";
255    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
256    if let Err(Error::TooLate) = parsed.get_result() {
257    } else {
258        assert!(false);
259    }
260}
261
262#[test]
263fn tx_ack_deser() {
264    let json = "{\"txpk_ack\":{\"error\":\"NONE\"}}";
265    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
266    if let Err(_) = parsed.get_result() {
267        assert!(false);
268    }
269}
270
271#[test]
272fn tx_ack_deser_minimal() {
273    let json = "{\"txpk_ack\":{}}";
274    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
275    if let Err(_) = parsed.get_result() {
276        assert!(false);
277    }
278}
279
280#[test]
281fn tx_ack_deser_empty_error() {
282    let json = "{\"txpk_ack\":{\"error\":\"\"}}";
283    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
284    if let Err(_) = parsed.get_result() {
285        assert!(false);
286    }
287}
288
289#[test]
290fn tx_ack_deser_with_tmst() {
291    let json = "{\"txpk_ack\":{\"error\":\"NONE\", \"tmst\": 1234}}";
292    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
293    match parsed.get_result() {
294        Ok(Some(tmst)) => assert_eq!(1234, tmst),
295        _ => assert!(false),
296    }
297}
298
299#[test]
300fn tx_nack_tx_power_legacy() {
301    let json = "{ \"txpk_ack\": { \"error\" : \"TX_POWER\"}}";
302    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
303    if let Err(Error::InvalidTransmitPower(v)) = parsed.get_result() {
304        assert!(v.is_none());
305    } else {
306        assert!(false);
307    }
308}
309
310#[test]
311fn tx_nack_tx_power_sx1302deser() {
312    let json = "{ \"txpk_ack\": { \"warn\" : \"TX_POWER\", \"value\" : 27 }}";
313    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
314    if let Err(Error::AdjustedTransmitPower(power_used, tmst)) = parsed.get_result() {
315        if let (Some(power_used), None) = (power_used, tmst) {
316            assert_eq!(power_used, 27)
317        } else {
318            assert!(false)
319        }
320    } else {
321        assert!(false)
322    }
323}
324
325#[test]
326fn tx_nack_tx_power_sx1302deser_with_tmst() {
327    let json = "{ \"txpk_ack\": { \"warn\" : \"TX_POWER\", \"value\" : 27, \"tmst\": 1234 }}";
328    let parsed: Data = serde_json::from_str(json).expect("Error parsing tx_ack");
329    if let Err(Error::AdjustedTransmitPower(power_used, tmst)) = parsed.get_result() {
330        if let (Some(power_used), Some(tmst)) = (power_used, tmst) {
331            assert_eq!(power_used, 27);
332            assert_eq!(tmst, 1234)
333        } else {
334            assert!(false)
335        }
336    } else {
337        assert!(false)
338    }
339}
340
341#[test]
342fn tx_nack_tx_power_sx1302_ser() {
343    let invalid_transmit_power = Data::new_with_error(Error::AdjustedTransmitPower(Some(27), None));
344    let str = serde_json::to_string(&invalid_transmit_power).expect("serialization error");
345    assert_eq!("{\"txpk_ack\":{\"warn\":\"TX_POWER\",\"value\":27}}", str)
346}
347
348#[test]
349fn null_terminate() {
350    let bytes = hex::decode("02904905aa555a00000000007b227478706b5f61636b223a7b227761726e223a2254585f504f574552222c2276616c7565223a32372c22746d7374223a333937353336363839317d7d00").unwrap();
351    let _frame = crate::packet::Packet::parse(&bytes).unwrap();
352}
353
354#[test]
355fn dont_null_terminate() {
356    let bytes = hex::decode("02904905aa555a00000000007b227478706b5f61636b223a7b227761726e223a2254585f504f574552222c2276616c7565223a32372c22746d7374223a333937353336363839317d7d").unwrap();
357    let _frame = crate::packet::Packet::parse(&bytes).unwrap();
358}