lr2021/cmd/
cmd_common.rs

1// Common commands API
2
3use crate::status::Status;
4
5/// RX path selection
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum RxPath {
9    LfPath = 0,
10    HfPath = 1,
11}
12
13/// RX boost configuration (0..7). Will keep previous value if not sent
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum RxBoost {
17    Off = 0,
18    B1 = 1,
19    B2 = 2,
20    B3 = 3,
21    B4 = 4,
22    B5 = 5,
23    B6 = 6,
24    Max = 7,
25}
26
27/// Select which PA to use
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub enum PaSel {
31    LfPa = 0,
32    HfPa = 1,
33}
34
35/// PA LF mode (if unused set to 0)
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38pub enum PaLfMode {
39    LfPaFsm = 0,
40    LfPaFdm = 1,
41    LfPaHsmRfo1 = 2,
42    LfPaHsmRfo2 = 3,
43}
44
45/// PA ramp time selection
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum RampTime {
49    Ramp2u = 0,
50    Ramp4u = 1,
51    Ramp8u = 2,
52    Ramp16u = 3,
53    Ramp32u = 4,
54    Ramp48u = 5,
55    Ramp64u = 6,
56    Ramp80u = 7,
57    Ramp96u = 8,
58    Ramp112u = 9,
59    Ramp128u = 10,
60    Ramp144u = 11,
61    Ramp160u = 12,
62    Ramp176u = 13,
63    Ramp192u = 14,
64    Ramp208u = 15,
65}
66
67/// Fallback mode selection
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum FallbackMode {
71    StandbyRc = 1,
72    StandbyXosc = 2,
73    Fs = 3,
74}
75
76/// Packet type selection
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79pub enum PacketType {
80    Lora = 0,
81    FskGeneric = 1,
82    FskLegacy = 2,
83    Ble = 3,
84    Ranging = 4,
85    Flrc = 5,
86    Bpsk = 6,
87    LrFhss = 7,
88    Wmbus = 8,
89    Wisun = 9,
90    Ook = 10,
91    Raw = 11,
92    Zwave = 12,
93    Zigbee = 13,
94}
95
96/// Test mode selection
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98#[cfg_attr(feature = "defmt", derive(defmt::Format))]
99pub enum TestMode {
100    Packet = 0,
101    Preamble = 1,
102    Tone = 2,
103    Prbs9 = 3,
104}
105
106/// Auto mode configuration
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108#[cfg_attr(feature = "defmt", derive(defmt::Format))]
109pub enum AutoTxrxMode {
110    Disable = 0,
111    Always = 1,
112    RxOk = 2,
113}
114
115/// Index of the source to configure (0-2)
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[cfg_attr(feature = "defmt", derive(defmt::Format))]
118pub enum TimestampIndex {
119    Ts0 = 0,
120    Ts1 = 1,
121    Ts2 = 2,
122}
123
124/// Event source selection
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126#[cfg_attr(feature = "defmt", derive(defmt::Format))]
127pub enum TimestampSource {
128    None = 0,
129    TxDone = 1,
130    RxDone = 2,
131    Sync = 3,
132    Header = 4,
133}
134
135/// Action taken after the CAD
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub enum ExitMode {
139    Fallback = 0,
140    Tx = 1,
141    Rx = 2,
142}
143
144/// Sets the RF frequency for subsequent radio operations. Will not work with the chip in TX mode. All frequency dependent parameters are automatically recomputed by the FW
145pub fn set_rf_frequency_cmd(rf_freq: u32) -> [u8; 6] {
146    let mut cmd = [0u8; 6];
147    cmd[0] = 0x02;
148    cmd[1] = 0x00;
149
150    cmd[2] |= ((rf_freq >> 24) & 0xFF) as u8;
151    cmd[3] |= ((rf_freq >> 16) & 0xFF) as u8;
152    cmd[4] |= ((rf_freq >> 8) & 0xFF) as u8;
153    cmd[5] |= (rf_freq & 0xFF) as u8;
154    cmd
155}
156
157/// Sets the RX path and boost configuration. If rx_boost is changed, the SRC calibration (ADC offset) is run again for G12 and G13 with the updated boost configuration
158pub fn set_rx_path_cmd(rx_path: RxPath) -> [u8; 3] {
159    let mut cmd = [0u8; 3];
160    cmd[0] = 0x02;
161    cmd[1] = 0x01;
162
163    cmd[2] |= (rx_path as u8) & 0x1;
164    cmd
165}
166
167/// Sets the RX path and boost configuration. If rx_boost is changed, the SRC calibration (ADC offset) is run again for G12 and G13 with the updated boost configuration
168pub fn set_rx_path_adv_cmd(rx_path: RxPath, rx_boost: RxBoost) -> [u8; 4] {
169    let mut cmd = [0u8; 4];
170    cmd[0] = 0x02;
171    cmd[1] = 0x01;
172
173    cmd[2] |= (rx_path as u8) & 0x1;
174    cmd[3] |= (rx_boost as u8) & 0x7;
175    cmd
176}
177
178/// Chooses which PA to use and sets the parameters of the PA
179pub fn set_pa_config_cmd(pa_sel: PaSel, pa_lf_mode: PaLfMode, pa_lf_duty_cycle: u8, pa_lf_slices: u8) -> [u8; 4] {
180    let mut cmd = [0u8; 4];
181    cmd[0] = 0x02;
182    cmd[1] = 0x02;
183
184    cmd[2] |= ((pa_sel as u8) & 0x1) << 7;
185    cmd[2] |= (pa_lf_mode as u8) & 0x3;
186    cmd[2] |= (pa_lf_duty_cycle & 0xF) << 4;
187    cmd[3] |= pa_lf_slices & 0xF;
188    cmd
189}
190
191/// Chooses which PA to use and sets the parameters of the PA
192pub fn set_pa_config_adv_cmd(pa_sel: PaSel, pa_lf_mode: PaLfMode, pa_lf_duty_cycle: u8, pa_lf_slices: u8, pa_hf_duty_cycle: u8) -> [u8; 5] {
193    let mut cmd = [0u8; 5];
194    cmd[0] = 0x02;
195    cmd[1] = 0x02;
196
197    cmd[2] |= ((pa_sel as u8) & 0x1) << 7;
198    cmd[2] |= (pa_lf_mode as u8) & 0x3;
199    cmd[2] |= (pa_lf_duty_cycle & 0xF) << 4;
200    cmd[3] |= pa_lf_slices & 0xF;
201    cmd[4] |= pa_hf_duty_cycle & 0x1F;
202    cmd
203}
204
205/// Sets the TX power and ramp time of the PA. The FW configures the corresponding registers, including OCP/OVP
206pub fn set_tx_params_cmd(tx_power: i8, ramp_time: RampTime) -> [u8; 4] {
207    let mut cmd = [0u8; 4];
208    cmd[0] = 0x02;
209    cmd[1] = 0x03;
210
211    cmd[2] |= (tx_power) as u8;
212    cmd[3] |= ramp_time as u8;
213    cmd
214}
215
216/// Configures the fallback mode after a RX or TX operation (after transmission/reception or timeout)
217pub fn set_rx_tx_fallback_mode_cmd(fallback_mode: FallbackMode) -> [u8; 3] {
218    let mut cmd = [0u8; 3];
219    cmd[0] = 0x02;
220    cmd[1] = 0x06;
221
222    cmd[2] |= (fallback_mode as u8) & 0x3;
223    cmd
224}
225
226/// Sets the current packet type. This is the first command to be sent when configuring the radio for transceiver operation. Will only work in Standby RC, Standby XOSC or FS mode
227pub fn set_packet_type_cmd(packet_type: PacketType) -> [u8; 3] {
228    let mut cmd = [0u8; 3];
229    cmd[0] = 0x02;
230    cmd[1] = 0x07;
231
232    cmd[2] |= packet_type as u8;
233    cmd
234}
235
236/// Returns the current packet type of the radio
237pub fn get_packet_type_req() -> [u8; 2] {
238    [0x02, 0x08]
239}
240
241/// Defines if the RX timeout should be stopped on Syncword/Header detection or on Preamble detection
242pub fn set_stop_timeout_cmd(stop_on_preamble: bool) -> [u8; 3] {
243    let mut cmd = [0u8; 3];
244    cmd[0] = 0x02;
245    cmd[1] = 0x09;
246
247    if stop_on_preamble { cmd[2] |= 1; }
248    cmd
249}
250
251/// Reset Rx Statistics
252pub fn reset_rx_stats_cmd() -> [u8; 2] {
253    [0x02, 0x0A]
254}
255
256/// Gets the instantaneous RSSI value during reception of the packet. Returned value corresponds to -rssi/2 (dBm)
257pub fn get_rssi_inst_req() -> [u8; 2] {
258    [0x02, 0x0B]
259}
260
261/// Sets the device into RX mode. The RTC is started with the given value. RxTimeout is in 1/32.768kHz steps, allowing a maximum of 512 seconds timeout. If image rejection calibration was not done for current RF frequency, error RXFREQ_NO_CAL_ERR is generated
262pub fn set_rx_cmd() -> [u8; 2] {
263    [0x02, 0x0C]
264}
265
266/// Sets the device into RX mode. The RTC is started with the given value. RxTimeout is in 1/32.768kHz steps, allowing a maximum of 512 seconds timeout. If image rejection calibration was not done for current RF frequency, error RXFREQ_NO_CAL_ERR is generated
267pub fn set_rx_adv_cmd(rx_timeout: u32) -> [u8; 5] {
268    let mut cmd = [0u8; 5];
269    cmd[0] = 0x02;
270    cmd[1] = 0x0C;
271
272    cmd[2] |= ((rx_timeout >> 16) & 0xFF) as u8;
273    cmd[3] |= ((rx_timeout >> 8) & 0xFF) as u8;
274    cmd[4] |= (rx_timeout & 0xFF) as u8;
275    cmd
276}
277
278/// Sets the device into TX mode. The RTC is started with the given value. TxTimeout is in 1/32.768kHz steps, allowing a maximum of 512 seconds timeout
279pub fn set_tx_cmd() -> [u8; 2] {
280    [0x02, 0x0D]
281}
282
283/// Sets the device into TX mode. The RTC is started with the given value. TxTimeout is in 1/32.768kHz steps, allowing a maximum of 512 seconds timeout
284pub fn set_tx_adv_cmd(tx_timeout: u32) -> [u8; 5] {
285    let mut cmd = [0u8; 5];
286    cmd[0] = 0x02;
287    cmd[1] = 0x0D;
288
289    cmd[2] |= ((tx_timeout >> 16) & 0xFF) as u8;
290    cmd[3] |= ((tx_timeout >> 8) & 0xFF) as u8;
291    cmd[4] |= (tx_timeout & 0xFF) as u8;
292    cmd
293}
294
295/// Sets the device into TX test mode
296pub fn set_tx_test_mode_cmd(test_mode: TestMode) -> [u8; 3] {
297    let mut cmd = [0u8; 3];
298    cmd[0] = 0x02;
299    cmd[1] = 0x0E;
300
301    cmd[2] |= test_mode as u8;
302    cmd
303}
304
305/// Select which PA to use. Configuration must have been provided beforehand using SetPaConfig. Selection cannot be changed in TX mode
306pub fn sel_pa_cmd(pa_sel: PaSel) -> [u8; 3] {
307    let mut cmd = [0u8; 3];
308    cmd[0] = 0x02;
309    cmd[1] = 0x0F;
310
311    cmd[2] |= (pa_sel as u8) & 0x1;
312    cmd
313}
314
315/// Start reception every cycle_time and listen for rx_max_time
316pub fn set_rx_duty_cycle_cmd(rx_max_time: u32, cycle_time: u32, use_lora_cad: bool, dram_ret: u8) -> [u8; 9] {
317    let mut cmd = [0u8; 9];
318    cmd[0] = 0x02;
319    cmd[1] = 0x10;
320
321    cmd[2] |= ((rx_max_time >> 16) & 0xFF) as u8;
322    cmd[3] |= ((rx_max_time >> 8) & 0xFF) as u8;
323    cmd[4] |= (rx_max_time & 0xFF) as u8;
324    cmd[5] |= ((cycle_time >> 16) & 0xFF) as u8;
325    cmd[6] |= ((cycle_time >> 8) & 0xFF) as u8;
326    cmd[7] |= (cycle_time & 0xFF) as u8;
327    if use_lora_cad { cmd[8] |= 16; }
328    cmd[8] |= dram_ret & 0x7;
329    cmd
330}
331
332/// Activate or deactivate the auto TX/auto RX mode. In auto RX mode, chip automatically goes from TX to RX after TxDone. In auto TX mode, chip automatically goes from RX to TX after RxDone
333pub fn set_auto_rx_tx_cmd(clear: bool, auto_txrx_mode: AutoTxrxMode, timeout: u32, delay: u32) -> [u8; 10] {
334    let mut cmd = [0u8; 10];
335    cmd[0] = 0x02;
336    cmd[1] = 0x11;
337
338    if clear { cmd[2] |= 128; }
339    cmd[2] |= (auto_txrx_mode as u8) & 0x3;
340    cmd[3] |= ((timeout >> 16) & 0xFF) as u8;
341    cmd[4] |= ((timeout >> 8) & 0xFF) as u8;
342    cmd[5] |= (timeout & 0xFF) as u8;
343    cmd[6] |= ((delay >> 24) & 0xFF) as u8;
344    cmd[7] |= ((delay >> 16) & 0xFF) as u8;
345    cmd[8] |= ((delay >> 8) & 0xFF) as u8;
346    cmd[9] |= (delay & 0xFF) as u8;
347    cmd
348}
349
350/// Get the length of the last received packet
351pub fn get_rx_pkt_length_req() -> [u8; 2] {
352    [0x02, 0x12]
353}
354
355/// Set the global value of the power offset
356pub fn set_power_offset_cmd(power_offset: u8) -> [u8; 3] {
357    let mut cmd = [0u8; 3];
358    cmd[0] = 0x02;
359    cmd[1] = 0x14;
360
361    cmd[2] |= power_offset & 0x3F;
362    cmd
363}
364
365/// Sets the default RX and TX timeouts to be used for DIO RX/TX triggers, or if the timeout parameters are not sent in the SetRx and SetTx commands
366pub fn set_default_rx_tx_timeout_cmd(rx_timeout: u32, tx_timeout: u32) -> [u8; 8] {
367    let mut cmd = [0u8; 8];
368    cmd[0] = 0x02;
369    cmd[1] = 0x15;
370
371    cmd[2] |= ((rx_timeout >> 16) & 0xFF) as u8;
372    cmd[3] |= ((rx_timeout >> 8) & 0xFF) as u8;
373    cmd[4] |= (rx_timeout & 0xFF) as u8;
374    cmd[5] |= ((tx_timeout >> 16) & 0xFF) as u8;
375    cmd[6] |= ((tx_timeout >> 8) & 0xFF) as u8;
376    cmd[7] |= (tx_timeout & 0xFF) as u8;
377    cmd
378}
379
380/// Sets the source event for time-stamping different radio events. 3 sources can be configured in parallel
381pub fn set_timestamp_source_cmd(timestamp_index: TimestampIndex, timestamp_source: TimestampSource) -> [u8; 3] {
382    let mut cmd = [0u8; 3];
383    cmd[0] = 0x02;
384    cmd[1] = 0x16;
385
386    cmd[2] |= ((timestamp_index as u8) & 0x3) << 4;
387    cmd[2] |= (timestamp_source as u8) & 0xF;
388    cmd
389}
390
391/// Get the delay in HF clk tick between the event and the SPI NSS falling edge of the request. Will not return a correct value if the event occurred before a sleep period
392pub fn get_timestamp_value_req(timestamp_index: TimestampIndex) -> [u8; 3] {
393    let mut cmd = [0u8; 3];
394    cmd[0] = 0x02;
395    cmd[1] = 0x17;
396
397    cmd[2] |= (timestamp_index as u8) & 0x3;
398    cmd
399}
400
401/// Set the radio into RX mode for Clear Channel Assessment measurements. The radio measures the RSSI for the given duration
402pub fn set_cca_cmd(duration: u32) -> [u8; 5] {
403    let mut cmd = [0u8; 5];
404    cmd[0] = 0x02;
405    cmd[1] = 0x18;
406
407    cmd[2] |= ((duration >> 16) & 0xFF) as u8;
408    cmd[3] |= ((duration >> 8) & 0xFF) as u8;
409    cmd[4] |= (duration & 0xFF) as u8;
410    cmd
411}
412
413/// Set the radio into RX mode for Clear Channel Assessment measurements. The radio measures the RSSI for the given duration
414pub fn set_cca_adv_cmd(duration: u32, gain: u8) -> [u8; 6] {
415    let mut cmd = [0u8; 6];
416    cmd[0] = 0x02;
417    cmd[1] = 0x18;
418
419    cmd[2] |= ((duration >> 16) & 0xFF) as u8;
420    cmd[3] |= ((duration >> 8) & 0xFF) as u8;
421    cmd[4] |= (duration & 0xFF) as u8;
422    cmd[5] |= gain;
423    cmd
424}
425
426/// Get the RSSI statistics for the CCA measurement
427pub fn get_cca_result_req() -> [u8; 2] {
428    [0x02, 0x19]
429}
430
431/// Set the manual gain of the AGC. A value of 0 enables the AGC: automatic gain
432pub fn set_agc_gain_manual_cmd(gain_step: u8) -> [u8; 3] {
433    let mut cmd = [0u8; 3];
434    cmd[0] = 0x02;
435    cmd[1] = 0x1A;
436
437    cmd[2] |= gain_step & 0xF;
438    cmd
439}
440
441/// Set the CAD parameters for the Channel Activity Detect for packet types other than LoRa. This CAD is based on the measured RSSI
442pub fn set_cad_params_cmd(cad_timeout: u32, threshold: u8, exit_mode: ExitMode, trx_timeout: u32) -> [u8; 10] {
443    let mut cmd = [0u8; 10];
444    cmd[0] = 0x02;
445    cmd[1] = 0x1B;
446
447    cmd[2] |= ((cad_timeout >> 16) & 0xFF) as u8;
448    cmd[3] |= ((cad_timeout >> 8) & 0xFF) as u8;
449    cmd[4] |= (cad_timeout & 0xFF) as u8;
450    cmd[5] |= threshold;
451    cmd[6] |= (exit_mode as u8) & 0x3;
452    cmd[7] |= ((trx_timeout >> 16) & 0xFF) as u8;
453    cmd[8] |= ((trx_timeout >> 8) & 0xFF) as u8;
454    cmd[9] |= (trx_timeout & 0xFF) as u8;
455    cmd
456}
457
458/// Set device into RX CAD mode (not LoRa). Parameters must have been previously set using SetCadParams command
459pub fn set_cad_cmd() -> [u8; 2] {
460    [0x02, 0x1C]
461}
462
463// Response structs
464
465/// Response for GetPacketType command
466#[derive(Default)]
467pub struct PacketTypeRsp([u8; 3]);
468
469impl PacketTypeRsp {
470    /// Create a new response buffer
471    pub fn new() -> Self {
472        Self::default()
473    }
474
475    /// Return Status
476    pub fn status(&mut self) -> Status {
477        Status::from_slice(&self.0[..2])
478    }
479
480    /// Current packet type (see SetPacketType for values)
481    pub fn packet_type(&self) -> u8 {
482        self.0[2]
483    }
484}
485
486impl AsMut<[u8]> for PacketTypeRsp {
487    fn as_mut(&mut self) -> &mut [u8] {
488        &mut self.0
489    }
490}
491
492/// Response for GetRssiInst command
493#[derive(Default)]
494pub struct RssiInstRsp([u8; 4]);
495
496impl RssiInstRsp {
497    /// Create a new response buffer
498    pub fn new() -> Self {
499        Self::default()
500    }
501
502    /// Return Status
503    pub fn status(&mut self) -> Status {
504        Status::from_slice(&self.0[..2])
505    }
506
507    /// Instantaneous RSSI value. Actual signal power is -rssi/2 (dBm). If only 1 dBm resolution is wanted, reading the fractional bit is optional
508    pub fn rssi(&self) -> u16 {
509        ((self.0[3] & 0x1) as u16) |
510        ((self.0[2] as u16) << 1)
511    }
512}
513
514impl AsMut<[u8]> for RssiInstRsp {
515    fn as_mut(&mut self) -> &mut [u8] {
516        &mut self.0
517    }
518}
519
520/// Response for GetRxPktLength command
521#[derive(Default)]
522pub struct RxPktLengthRsp([u8; 4]);
523
524impl RxPktLengthRsp {
525    /// Create a new response buffer
526    pub fn new() -> Self {
527        Self::default()
528    }
529
530    /// Return Status
531    pub fn status(&mut self) -> Status {
532        Status::from_slice(&self.0[..2])
533    }
534
535    /// Length of the last received packet in bytes
536    pub fn pkt_length(&self) -> u16 {
537        (self.0[3] as u16) |
538        ((self.0[2] as u16) << 8)
539    }
540}
541
542impl AsMut<[u8]> for RxPktLengthRsp {
543    fn as_mut(&mut self) -> &mut [u8] {
544        &mut self.0
545    }
546}
547
548/// Response for GetTimestampValue command
549#[derive(Default)]
550pub struct TimestampValueRsp([u8; 6]);
551
552impl TimestampValueRsp {
553    /// Create a new response buffer
554    pub fn new() -> Self {
555        Self::default()
556    }
557
558    /// Return Status
559    pub fn status(&mut self) -> Status {
560        Status::from_slice(&self.0[..2])
561    }
562
563    /// Timestamp value in HF clock ticks
564    pub fn timestamp(&self) -> u32 {
565        (self.0[5] as u32) |
566        ((self.0[4] as u32) << 8) |
567        ((self.0[3] as u32) << 16) |
568        ((self.0[2] as u32) << 24)
569    }
570}
571
572impl AsMut<[u8]> for TimestampValueRsp {
573    fn as_mut(&mut self) -> &mut [u8] {
574        &mut self.0
575    }
576}
577
578/// Response for GetCcaResult command
579#[derive(Default)]
580pub struct CcaResultRsp([u8; 6]);
581
582impl CcaResultRsp {
583    /// Create a new response buffer
584    pub fn new() -> Self {
585        Self::default()
586    }
587
588    /// Return Status
589    pub fn status(&mut self) -> Status {
590        Status::from_slice(&self.0[..2])
591    }
592
593    /// Minimum RSSI value measured during CCA. Actual value is -rssi_min/2 (dBm)
594    pub fn rssi_min(&self) -> u16 {
595        (((self.0[5] >> 2) & 0x1) as u16) |
596        ((self.0[2] as u16) << 1)
597    }
598
599    /// Maximum RSSI value measured during CCA. Actual value is -rssi_max/2 (dBm)
600    pub fn rssi_max(&self) -> u16 {
601        (((self.0[5] >> 1) & 0x1) as u16) |
602        ((self.0[3] as u16) << 1)
603    }
604
605    /// Average RSSI value measured during CCA. Actual value is -rssi_avg/2 (dBm)
606    pub fn rssi_avg(&self) -> u16 {
607        ((self.0[5] & 0x1) as u16) |
608        ((self.0[4] as u16) << 1)
609    }
610}
611
612impl AsMut<[u8]> for CcaResultRsp {
613    fn as_mut(&mut self) -> &mut [u8] {
614        &mut self.0
615    }
616}
617
618// Commands with variable length parameters (not implemented):
619// - SetRssiCalibration