lrwn/
relay.rs

1use anyhow::Result;
2#[cfg(feature = "serde")]
3use serde::Serialize;
4
5use crate::helpers::{decode_freq, encode_freq};
6use crate::phy_payload::PhyPayload;
7
8#[derive(Debug, PartialEq, Eq, Clone)]
9#[cfg_attr(feature = "serde", derive(Serialize))]
10pub struct UplinkMetadata {
11    pub dr: u8,
12    pub snr: isize,
13    pub rssi: isize,
14    pub wor_channel: u8,
15}
16
17impl UplinkMetadata {
18    pub fn from_bytes(b: [u8; 3]) -> Self {
19        UplinkMetadata {
20            dr: b[0] & 0x0f,
21            snr: ((b[0] >> 4) | ((b[1] & 0x01) << 4)) as isize - 20,
22            rssi: -((b[1] >> 1) as isize) - 15,
23            wor_channel: b[2] & 0x03,
24        }
25    }
26
27    pub fn to_bytes(&self) -> Result<[u8; 3]> {
28        if self.dr > 15 {
29            return Err(anyhow!("max dr value is 15"));
30        }
31
32        if self.wor_channel > 1 {
33            return Err(anyhow!("max wor_channel value is 1"));
34        }
35
36        let snr = self.snr.clamp(-20, 11);
37        let rssi = self.rssi.clamp(-142, -15);
38
39        // Encode values
40        let snr = (snr + 20) as u8;
41        let rssi = -(rssi + 15) as u8;
42
43        Ok([
44            self.dr | (snr << 4),
45            (snr >> 4) | (rssi << 1),
46            self.wor_channel,
47        ])
48    }
49}
50
51#[derive(Debug, PartialEq, Eq, Clone)]
52#[cfg_attr(feature = "serde", derive(Serialize))]
53pub struct ForwardUplinkReq {
54    pub metadata: UplinkMetadata,
55    pub frequency: u32,
56    pub payload: Box<PhyPayload>,
57}
58
59impl ForwardUplinkReq {
60    pub fn from_slice(b: &[u8]) -> Result<Self> {
61        if b.len() < 6 {
62            return Err(anyhow!("at least 6 bytes are expected"));
63        }
64
65        Ok(ForwardUplinkReq {
66            metadata: UplinkMetadata::from_bytes([b[0], b[1], b[2]]),
67            frequency: decode_freq(&b[3..6])?,
68            payload: Box::new(PhyPayload::from_slice(&b[6..])?),
69        })
70    }
71
72    pub fn to_vec(&self) -> Result<Vec<u8>> {
73        let mut b = Vec::new();
74        b.extend_from_slice(&self.metadata.to_bytes()?);
75        b.extend_from_slice(&encode_freq(self.frequency)?);
76        b.extend_from_slice(&self.payload.to_vec()?);
77        Ok(b)
78    }
79}
80
81#[derive(Debug, PartialEq, Eq, Clone)]
82#[cfg_attr(feature = "serde", derive(Serialize))]
83pub struct ForwardDownlinkReq {
84    pub payload: Box<PhyPayload>,
85}
86
87impl ForwardDownlinkReq {
88    pub fn from_slice(b: &[u8]) -> Result<Self> {
89        Ok(ForwardDownlinkReq {
90            payload: Box::new(PhyPayload::from_slice(b)?),
91        })
92    }
93
94    pub fn to_vec(&self) -> Result<Vec<u8>> {
95        self.payload.to_vec()
96    }
97}
98
99#[cfg(test)]
100mod test {
101    use crate::*;
102
103    #[test]
104    fn test_forward_uplink_req() {
105        let req = ForwardUplinkReq {
106            metadata: UplinkMetadata {
107                dr: 5,
108                snr: 9,
109                rssi: -110,
110                wor_channel: 1,
111            },
112            frequency: 868100000,
113            payload: Box::new(PhyPayload {
114                mhdr: MHDR {
115                    f_type: FType::Proprietary,
116                    major: Major::LoRaWANR1,
117                },
118                payload: Payload::Raw(vec![0x01, 0x02, 0x03]),
119                mic: None,
120            }),
121        };
122
123        let b = req.to_vec().unwrap();
124        assert_eq!(vec![213, 191, 1, 40, 118, 132, 224, 1, 2, 3], b);
125
126        let req_decoded = ForwardUplinkReq::from_slice(&b).unwrap();
127        assert_eq!(req, req_decoded);
128    }
129
130    #[test]
131    fn test_forward_downlink_req() {
132        let req = ForwardDownlinkReq {
133            payload: Box::new(PhyPayload {
134                mhdr: MHDR {
135                    f_type: FType::Proprietary,
136                    major: Major::LoRaWANR1,
137                },
138                payload: Payload::Raw(vec![0x01, 0x02, 0x03]),
139                mic: None,
140            }),
141        };
142
143        let b = req.to_vec().unwrap();
144        assert_eq!(vec![224, 1, 2, 3], b);
145
146        let req_decoded = ForwardDownlinkReq::from_slice(&b).unwrap();
147        assert_eq!(req, req_decoded);
148    }
149}