lr2021/cmd/
cmd_fsk.rs

1// Fsk commands API
2
3use crate::status::Status;
4
5/// Pulse shaping filter selection
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum PulseShape {
9    None = 0,
10    Custom = 1,
11    Bt0p3 = 4,
12    Bt0p5 = 5,
13    Bt0p7 = 6,
14    Bt1p0 = 7,
15    Bt2p0 = 2,
16    Rc0p3 = 8,
17    Rc0p5 = 9,
18    Rc0p7 = 10,
19    Rc1p0 = 11,
20    Rrc0p3 = 12,
21    Rrc0p4 = 3,
22    Rrc0p5 = 13,
23    Rrc0p7 = 14,
24    Rrc1p0 = 15,
25}
26
27/// RX bandwidth (same format as in the SetAdvancedModulationParams command)
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub enum RxBw {
31    BwAuto = 255,
32    Bw3076 = 0,
33    Bw2857 = 64,
34    Bw2666 = 128,
35    Bw2222 = 192,
36    Bw1333 = 136,
37    Bw1111 = 200,
38    Bw888 = 144,
39    Bw769 = 24,
40    Bw740 = 208,
41    Bw714 = 88,
42    Bw666 = 152,
43    Bw615 = 32,
44    Bw571 = 96,
45    Bw555 = 216,
46    Bw533 = 160,
47    Bw512 = 17,
48    Bw476 = 81,
49    Bw444 = 224,
50    Bw384 = 25,
51    Bw370 = 209,
52    Bw357 = 89,
53    Bw333 = 153,
54    Bw307 = 33,
55    Bw285 = 97,
56    Bw277 = 217,
57    Bw266 = 161,
58    Bw256 = 18,
59    Bw238 = 82,
60    Bw222 = 225,
61    Bw192 = 26,
62    Bw185 = 210,
63    Bw178 = 90,
64    Bw166 = 154,
65    Bw153 = 34,
66    Bw142 = 98,
67    Bw138 = 218,
68    Bw133 = 162,
69    Bw128 = 19,
70    Bw119 = 83,
71    Bw111 = 226,
72    Bw96 = 27,
73    Bw92 = 211,
74    Bw89 = 91,
75    Bw83 = 155,
76    Bw76 = 35,
77    Bw71 = 99,
78    Bw69 = 219,
79    Bw66 = 163,
80    Bw64 = 20,
81    Bw59 = 84,
82    Bw55 = 227,
83    Bw48 = 28,
84    Bw46 = 212,
85    Bw44 = 92,
86    Bw41 = 156,
87    Bw38 = 36,
88    Bw35 = 100,
89    Bw34 = 220,
90    Bw33 = 164,
91    Bw32 = 21,
92    Bw29 = 85,
93    Bw27 = 228,
94    Bw24 = 29,
95    Bw23 = 213,
96    Bw22 = 93,
97    Bw20 = 157,
98    Bw19 = 37,
99    Bw17 = 101,
100    Bw16 = 165,
101    Bw14 = 86,
102    Bw13 = 229,
103    Bw12 = 30,
104    Bw11 = 94,
105    Bw10 = 158,
106    Bw9p6 = 38,
107    Bw8p9 = 102,
108    Bw8p7 = 222,
109    Bw8p3 = 166,
110    Bw8 = 23,
111    Bw7p4 = 87,
112    Bw6p9 = 230,
113    Bw6 = 31,
114    Bw5p8 = 215,
115    Bw5p6 = 95,
116    Bw5p2 = 159,
117    Bw4p8 = 39,
118    Bw4p5 = 103,
119    Bw4p3 = 223,
120    Bw4p2 = 167,
121    Bw3p5 = 231,
122}
123
124/// Preamble detection length. 0=off (detection on syncword), others=length of preamble detection. Enables/disables PreambleDetected IRQ
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126#[cfg_attr(feature = "defmt", derive(defmt::Format))]
127pub enum PblLenDetect {
128    None = 0,
129    Len8Bits = 8,
130    Len16Bits = 16,
131    Len24Bits = 24,
132    Len32Bits = 32,
133}
134
135/// Payload length unit
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub enum PldLenUnit {
139    Bytes = 0,
140    Bits = 1,
141}
142
143/// Address filtering mode. If address comparison fails, packet reception is aborted and addrErr flag is set
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum AddrComp {
147    Off = 0,
148    Node = 1,
149    NodeBcast = 2,
150}
151
152/// Packet format selection (fixed or variable length)
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub enum FskPktFormat {
156    FixedLength = 0,
157    Variable8bit = 1,
158    Variable9bit = 2,
159    Variable16bit = 3,
160}
161
162/// CRC mode selection
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
165pub enum Crc {
166    CrcOff = 0,
167    Crc1Byte = 1,
168    Crc2Byte = 2,
169    Crc3Byte = 3,
170    Crc4Byte = 4,
171    Crc1ByteInv = 9,
172    Crc2ByteInv = 10,
173    Crc3ByteInv = 11,
174    Crc4ByteInv = 12,
175}
176
177/// Whitening type compatibility
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179#[cfg_attr(feature = "defmt", derive(defmt::Format))]
180pub enum WhitenType {
181    Sx126xLr11xx = 0,
182    Sx128x = 1,
183}
184
185/// Bit order for syncword transmission (over the air). Set MSB first for SX126x, LR11xx, SX1280 compatible value
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187#[cfg_attr(feature = "defmt", derive(defmt::Format))]
188pub enum BitOrder {
189    LsbFirst = 0,
190    MsbFirst = 1,
191}
192
193/// Sets the modulation parameters for FSK packets. FW configures respective modem registers. Will return CMD_FAIL in the status of the next command, if the packet type is not FSK
194pub fn set_fsk_modulation_params_cmd(bitrate: u32, pulse_shape: PulseShape, rx_bw: RxBw, fdev: u32) -> [u8; 11] {
195    let mut cmd = [0u8; 11];
196    cmd[0] = 0x02;
197    cmd[1] = 0x40;
198
199    cmd[2] |= ((bitrate >> 24) & 0xFF) as u8;
200    cmd[3] |= ((bitrate >> 16) & 0xFF) as u8;
201    cmd[4] |= ((bitrate >> 8) & 0xFF) as u8;
202    cmd[5] |= (bitrate & 0xFF) as u8;
203    cmd[6] |= (pulse_shape as u8) & 0xF;
204    cmd[7] |= rx_bw as u8;
205    cmd[8] |= ((fdev >> 16) & 0xFF) as u8;
206    cmd[9] |= ((fdev >> 8) & 0xFF) as u8;
207    cmd[10] |= (fdev & 0xFF) as u8;
208    cmd
209}
210
211#[allow(clippy::too_many_arguments)]
212/// Sets the packet parameters for FSK packets.. Command will fail if packet type is not FSK
213pub fn set_fsk_packet_params_cmd(pbl_len_tx: u16, pbl_len_detect: PblLenDetect, pbl_long: bool, pld_len_unit: PldLenUnit, addr_comp: AddrComp, fsk_pkt_format: FskPktFormat, pld_len: u16, crc: Crc, dc_free: bool) -> [u8; 9] {
214    let mut cmd = [0u8; 9];
215    cmd[0] = 0x02;
216    cmd[1] = 0x41;
217
218    cmd[2] |= ((pbl_len_tx >> 8) & 0xFF) as u8;
219    cmd[3] |= (pbl_len_tx & 0xFF) as u8;
220    cmd[4] |= pbl_len_detect as u8;
221    if pbl_long { cmd[5] |= 16; }
222    cmd[5] |= ((pld_len_unit as u8) & 0x1) << 4;
223    cmd[5] |= ((addr_comp as u8) & 0x3) << 2;
224    cmd[5] |= (fsk_pkt_format as u8) & 0x3;
225    cmd[6] |= ((pld_len >> 8) & 0xFF) as u8;
226    cmd[7] |= (pld_len & 0xFF) as u8;
227    cmd[8] |= ((crc as u8) & 0xF) << 4;
228    if dc_free { cmd[8] |= 1; }
229    cmd
230}
231
232/// Configure the whitening params for FSK packets, SX126x/LR11xx or SX128x compatible
233pub fn set_fsk_whitening_params_cmd(whiten_type: WhitenType, init: u16) -> [u8; 4] {
234    let mut cmd = [0u8; 4];
235    cmd[0] = 0x02;
236    cmd[1] = 0x42;
237
238    cmd[2] |= ((whiten_type as u8) & 0x1) << 4;
239    cmd[2] |= ((init >> 8) & 0xFF) as u8;
240    cmd[3] |= (init & 0xFF) as u8;
241    cmd
242}
243
244/// Configure the CRC params for FSK packets
245pub fn set_fsk_crc_params_cmd(polynom: u32, init: u32) -> [u8; 10] {
246    let mut cmd = [0u8; 10];
247    cmd[0] = 0x02;
248    cmd[1] = 0x43;
249
250    cmd[2] |= ((polynom >> 24) & 0xFF) as u8;
251    cmd[3] |= ((polynom >> 16) & 0xFF) as u8;
252    cmd[4] |= ((polynom >> 8) & 0xFF) as u8;
253    cmd[5] |= (polynom & 0xFF) as u8;
254    cmd[6] |= ((init >> 24) & 0xFF) as u8;
255    cmd[7] |= ((init >> 16) & 0xFF) as u8;
256    cmd[8] |= ((init >> 8) & 0xFF) as u8;
257    cmd[9] |= (init & 0xFF) as u8;
258    cmd
259}
260
261/// Configure the syncword for FSK packets
262pub fn set_fsk_sync_word_cmd(syncword: u64, bit_order: BitOrder, nb_bits: u8) -> [u8; 11] {
263    let mut cmd = [0u8; 11];
264    cmd[0] = 0x02;
265    cmd[1] = 0x44;
266
267    cmd[2] |= ((syncword >> 56) & 0xFF) as u8;
268    cmd[3] |= ((syncword >> 48) & 0xFF) as u8;
269    cmd[4] |= ((syncword >> 40) & 0xFF) as u8;
270    cmd[5] |= ((syncword >> 32) & 0xFF) as u8;
271    cmd[6] |= ((syncword >> 24) & 0xFF) as u8;
272    cmd[7] |= ((syncword >> 16) & 0xFF) as u8;
273    cmd[8] |= ((syncword >> 8) & 0xFF) as u8;
274    cmd[9] |= (syncword & 0xFF) as u8;
275    cmd[10] |= ((bit_order as u8) & 0x1) << 7;
276    cmd[10] |= nb_bits & 0x7F;
277    cmd
278}
279
280/// Configure the addresses for filtering for FSK packets
281pub fn set_fsk_address_cmd(addr_node: u8, addr_bcast: u8) -> [u8; 4] {
282    let mut cmd = [0u8; 4];
283    cmd[0] = 0x02;
284    cmd[1] = 0x45;
285
286    cmd[2] |= addr_node;
287    cmd[3] |= addr_bcast;
288    cmd
289}
290
291/// Get FSK RX stats
292pub fn get_fsk_rx_stats_req() -> [u8; 2] {
293    [0x02, 0x46]
294}
295
296/// Gets the status of the last received packet. Status is updated at the end of a reception (RxDone irq), but rssi_sync is already updated on SyncWordValid irq
297pub fn get_fsk_packet_status_req() -> [u8; 2] {
298    [0x02, 0x47]
299}
300
301// Response structs
302
303/// Response for GetFskRxStats command
304#[derive(Default)]
305pub struct FskRxStatsRsp([u8; 16]);
306
307impl FskRxStatsRsp {
308    /// Create a new response buffer
309    pub fn new() -> Self {
310        Self::default()
311    }
312
313    /// Return Status
314    pub fn status(&mut self) -> Status {
315        Status::from_slice(&self.0[..2])
316    }
317
318    /// Total number of received packets
319    pub fn pkt_rx(&self) -> u16 {
320        (self.0[3] as u16) |
321        ((self.0[2] as u16) << 8)
322    }
323
324    /// Number of received packets with a CRC error
325    pub fn crc_error(&self) -> u16 {
326        (self.0[5] as u16) |
327        ((self.0[4] as u16) << 8)
328    }
329
330    /// Number of packets with a length error
331    pub fn len_error(&self) -> u16 {
332        (self.0[7] as u16) |
333        ((self.0[6] as u16) << 8)
334    }
335
336    /// Number of detections
337    pub fn pbl_det(&self) -> u16 {
338        (self.0[9] as u16) |
339        ((self.0[8] as u16) << 8)
340    }
341
342    /// Number of good found syncword
343    pub fn sync_ok(&self) -> u16 {
344        (self.0[11] as u16) |
345        ((self.0[10] as u16) << 8)
346    }
347
348    /// Number of failed syncword
349    pub fn sync_fail(&self) -> u16 {
350        (self.0[13] as u16) |
351        ((self.0[12] as u16) << 8)
352    }
353
354    /// Number of RTC timeouts
355    pub fn timeout(&self) -> u16 {
356        (self.0[15] as u16) |
357        ((self.0[14] as u16) << 8)
358    }
359}
360
361impl AsMut<[u8]> for FskRxStatsRsp {
362    fn as_mut(&mut self) -> &mut [u8] {
363        &mut self.0
364    }
365}
366
367/// Response for GetFskPacketStatus command
368#[derive(Default)]
369pub struct FskPacketStatusRsp([u8; 8]);
370
371impl FskPacketStatusRsp {
372    /// Create a new response buffer
373    pub fn new() -> Self {
374        Self::default()
375    }
376
377    /// Return Status
378    pub fn status(&mut self) -> Status {
379        Status::from_slice(&self.0[..2])
380    }
381
382    /// Length of the last received packet in bytes (including optional data added in the FIFO, crc, ...)
383    pub fn pkt_len(&self) -> u16 {
384        (self.0[3] as u16) |
385        ((self.0[2] as u16) << 8)
386    }
387
388    /// Average over last packet received of RSSI. Actual signal power is –rssi_avg/2 (dBm)
389    pub fn rssi_avg(&self) -> u16 {
390        (((self.0[6] >> 2) & 0x1) as u16) |
391        ((self.0[4] as u16) << 1)
392    }
393
394    /// Latch RSSI value after syncword detection. Actual signal power is –rssi_sync/2 (dBm)
395    pub fn rssi_sync(&self) -> u16 {
396        ((self.0[6] & 0x1) as u16) |
397        ((self.0[5] as u16) << 1)
398    }
399
400    /// Indicates if the last packet received matched the broadcast address
401    pub fn addr_match_bcast(&self) -> bool {
402        (self.0[6] >> 5) & 0x1 != 0
403    }
404
405    /// Indicates if the last packet received matched the node address
406    pub fn addr_match_node(&self) -> bool {
407        (self.0[6] >> 4) & 0x1 != 0
408    }
409
410    /// Link quality indicator (0.25dB)
411    pub fn lqi(&self) -> u8 {
412        self.0[7]
413    }
414}
415
416impl AsMut<[u8]> for FskPacketStatusRsp {
417    fn as_mut(&mut self) -> &mut [u8] {
418        &mut self.0
419    }
420}