lr2021/cmd/
cmd_ranging.rs

1// Ranging commands API
2
3use crate::status::Status;
4
5/// Defines how many of the 4 bytes of the address are checked against the request address sent by the initiator. Checked bytes are the LSB if check_length<4
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum CheckLength {
9    Addr8b = 1,
10    Addr16b = 2,
11    Addr24b = 3,
12    Addr32b = 4,
13}
14
15/// Type of ranging result to return
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum RangingResKind {
19    LatestRaw = 0,
20    ExtendedRaw = 1,
21    GainSteps = 2,
22}
23
24/// Sets the ranging Id for this device (used by the responder)
25pub fn set_ranging_addr_cmd(addr: u32, check_length: CheckLength) -> [u8; 7] {
26    let mut cmd = [0u8; 7];
27    cmd[0] = 0x02;
28    cmd[1] = 0x78;
29
30    cmd[2] |= ((addr >> 24) & 0xFF) as u8;
31    cmd[3] |= ((addr >> 16) & 0xFF) as u8;
32    cmd[4] |= ((addr >> 8) & 0xFF) as u8;
33    cmd[5] |= (addr & 0xFF) as u8;
34    cmd[6] |= (check_length as u8) & 0x7;
35    cmd
36}
37
38/// Sets the ranging Id for the requests (used by the initiator)
39pub fn set_ranging_req_addr_cmd(req_addr: u32) -> [u8; 6] {
40    let mut cmd = [0u8; 6];
41    cmd[0] = 0x02;
42    cmd[1] = 0x79;
43
44    cmd[2] |= ((req_addr >> 24) & 0xFF) as u8;
45    cmd[3] |= ((req_addr >> 16) & 0xFF) as u8;
46    cmd[4] |= ((req_addr >> 8) & 0xFF) as u8;
47    cmd[5] |= (req_addr & 0xFF) as u8;
48    cmd
49}
50
51/// Gets the ranging result (For Master or spy only). Based on type parameter, different results are returned. The Distance (m) = rng1*150/(2^12*LoraBW), with LoraBW in MHz. For extended mode type=1 results, rng1 and rng2 values should be averaged to get a distance estimation unaffected by Doppler effect
52pub fn get_ranging_result_req(ranging_res_kind: RangingResKind) -> [u8; 3] {
53    let mut cmd = [0u8; 3];
54    cmd[0] = 0x02;
55    cmd[1] = 0x7A;
56
57    cmd[2] |= ranging_res_kind as u8;
58    cmd
59}
60
61
62
63
64
65/// Sets the Tx->Rx delay for the ranging calibration
66pub fn set_ranging_tx_rx_delay_cmd(delay: u32) -> [u8; 6] {
67    let mut cmd = [0u8; 6];
68    cmd[0] = 0x02;
69    cmd[1] = 0x7B;
70
71    cmd[2] |= ((delay >> 24) & 0xFF) as u8;
72    cmd[3] |= ((delay >> 16) & 0xFF) as u8;
73    cmd[4] |= ((delay >> 8) & 0xFF) as u8;
74    cmd[5] |= (delay & 0xFF) as u8;
75    cmd
76}
77
78/// Sets the ranging specific parameters
79pub fn set_ranging_params_cmd(extended: bool, spy_mode: bool, nb_symbols: u8) -> [u8; 3] {
80    let mut cmd = [0u8; 3];
81    cmd[0] = 0x02;
82    cmd[1] = 0x7C;
83
84    if extended { cmd[2] |= 128; }
85    if spy_mode { cmd[2] |= 64; }
86    cmd[2] |= nb_symbols & 0x3F;
87    cmd
88}
89
90/// Gets the ranging counters for ranging exchanges. Statistics are reset on a POR, sleep without memory retention and the command ResetRxStats. Note: for extended ranging mode, the counters are incremented twice, once for each request/response
91pub fn get_ranging_stats_req() -> [u8; 2] {
92    [0x02, 0x7D]
93}
94
95// Response structs
96
97/// Response for GetRangingResult command
98#[derive(Default)]
99pub struct RangingResultRsp([u8; 6]);
100
101impl RangingResultRsp {
102    /// Create a new response buffer
103    pub fn new() -> Self {
104        Self::default()
105    }
106
107    /// Return Status
108    pub fn status(&mut self) -> Status {
109        Status::from_slice(&self.0[..2])
110    }
111
112    /// Ranging measurement value. Distance in meter is given by rng*150/(2^12*Bandwidth),
113    pub fn rng(&self) -> i32 {
114        let raw = (self.0[4] as u32) |
115            ((self.0[3] as u32) << 8) |
116            ((self.0[2] as u32) << 16);
117        raw as i32 - if (self.0[2] & 0x80) != 0 {1<<24} else {0}
118    }
119
120    /// RSSI value
121    pub fn rssi(&self) -> u8 {
122        self.0[5]
123    }
124}
125
126impl AsMut<[u8]> for RangingResultRsp {
127    fn as_mut(&mut self) -> &mut [u8] {
128        &mut self.0
129    }
130}
131
132/// Response for GetRangingExtResult command
133#[derive(Default)]
134pub struct RangingExtResultRsp([u8; 9]);
135
136impl RangingExtResultRsp {
137    /// Create a new response buffer
138    pub fn new() -> Self {
139        Self::default()
140    }
141
142    /// Return Status
143    pub fn status(&mut self) -> Status {
144        Status::from_slice(&self.0[..2])
145    }
146
147    /// First ranging measurement value
148    pub fn rng1(&self) -> i32 {
149        let raw = (self.0[4] as u32) |
150            ((self.0[3] as u32) << 8) |
151            ((self.0[2] as u32) << 16);
152        raw as i32 - if (self.0[2] & 0x80) != 0 {1<<24} else {0}
153    }
154
155    /// RSSI value for first ranging measurement
156    pub fn rssi1(&self) -> u8 {
157        self.0[5]
158    }
159
160    /// Second ranging measurement value
161    pub fn rng2(&self) -> i32 {
162        let raw = (self.0[8] as u32) |
163            ((self.0[7] as u32) << 8) |
164            ((self.0[6] as u32) << 16);
165        raw as i32 - if (self.0[6] & 0x80) != 0 {1<<24} else {0}
166    }
167}
168
169impl AsMut<[u8]> for RangingExtResultRsp {
170    fn as_mut(&mut self) -> &mut [u8] {
171        &mut self.0
172    }
173}
174
175/// Response for GetRangingGainStep command
176#[derive(Default)]
177pub struct RangingGainStepRsp([u8; 4]);
178
179impl RangingGainStepRsp {
180    /// Create a new response buffer
181    pub fn new() -> Self {
182        Self::default()
183    }
184
185    /// Return Status
186    pub fn status(&mut self) -> Status {
187        Status::from_slice(&self.0[..2])
188    }
189
190    /// Radio gain used for first measurement
191    pub fn gain1(&self) -> u8 {
192        self.0[2]
193    }
194
195    /// Radio gain used for second measurement (if available)
196    pub fn gain2(&self) -> u8 {
197        self.0[3]
198    }
199}
200
201impl AsMut<[u8]> for RangingGainStepRsp {
202    fn as_mut(&mut self) -> &mut [u8] {
203        &mut self.0
204    }
205}
206
207/// Response for GetRangingStats command
208#[derive(Default)]
209pub struct RangingStatsRsp([u8; 12]);
210
211impl RangingStatsRsp {
212    /// Create a new response buffer
213    pub fn new() -> Self {
214        Self::default()
215    }
216
217    /// Return Status
218    pub fn status(&mut self) -> Status {
219        Status::from_slice(&self.0[..2])
220    }
221
222    /// Number of valid ranging exchanges
223    pub fn exchange_valid(&self) -> u16 {
224        (self.0[3] as u16) |
225        ((self.0[2] as u16) << 8)
226    }
227
228    /// Number of valid ranging requests
229    pub fn request_valid(&self) -> u16 {
230        (self.0[5] as u16) |
231        ((self.0[4] as u16) << 8)
232    }
233
234    /// Number of completed responses
235    pub fn response_done(&self) -> u16 {
236        (self.0[7] as u16) |
237        ((self.0[6] as u16) << 8)
238    }
239
240    /// Number of timeouts (For Initiator role: no response received from responder; For Responder role: no extended request received in extended mode)
241    pub fn timeout(&self) -> u16 {
242        (self.0[9] as u16) |
243        ((self.0[8] as u16) << 8)
244    }
245
246    /// Number of discarded requests
247    pub fn request_discarded(&self) -> u16 {
248        (self.0[11] as u16) |
249        ((self.0[10] as u16) << 8)
250    }
251}
252
253impl AsMut<[u8]> for RangingStatsRsp {
254    fn as_mut(&mut self) -> &mut [u8] {
255        &mut self.0
256    }
257}