Skip to main content

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