Skip to content

Commit 3875ac1

Browse files
author
Cruz Monrreal
authored
Merge pull request #8822 from hasnainvirk/dr0_and_fcnt_issue
LoRaWAN: Mitigating reception issues at lower data rates & FCnt increment after retry exhaustion
2 parents 61ade84 + 138fd74 commit 3875ac1

File tree

8 files changed

+142
-79
lines changed

8 files changed

+142
-79
lines changed

UNITTESTS/features/lorawan/loraphy/unittest.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ set(unittest-test-sources
3737
)
3838

3939

40-
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true")
41-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true")
40+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true -DMBED_CONF_LORA_WAKEUP_TIME=5")
41+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true -DMBED_CONF_LORA_WAKEUP_TIME=5")

UNITTESTS/stubs/LoRaPHY_stub.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,10 @@ uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params,
168168
return LoRaPHY_stub::uint8_value;
169169
}
170170

171-
void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb,
172-
uint32_t rx_error, uint32_t wakeup_time,
173-
uint32_t *window_timeout, int32_t *window_offset)
171+
void LoRaPHY::get_rx_window_params(float t_symbol, uint8_t min_rx_symbols,
172+
float rx_error, float wakeup_time,
173+
uint32_t *window_length, int32_t *window_offset,
174+
uint8_t phy_dr)
174175
{
175176
}
176177

features/lorawan/LoRaWANStack.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ void LoRaWANStack::post_process_tx_with_reception()
614614
_loramac.get_device_class() == CLASS_A ? "A" : "C");
615615
_ctrl_flags &= ~TX_DONE_FLAG;
616616
_ctrl_flags |= RETRY_EXHAUSTED_FLAG;
617+
_loramac.post_process_mcps_req();
618+
make_tx_metadata_available();
617619
state_controller(DEVICE_STATE_STATUS_CHECK);
618620
}
619621
}

features/lorawan/lorastack/mac/LoRaMac.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,12 @@ void LoRaMac::post_process_mcps_req()
166166
_params.is_node_ack_requested = false;
167167
_mcps_confirmation.ack_received = false;
168168
_mcps_indication.is_ack_recvd = false;
169-
_params.ul_frame_counter++;
170-
_params.adr_ack_counter++;
171169
} else {
172170
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
173171
}
172+
173+
_params.ul_frame_counter++;
174+
_params.adr_ack_counter++;
174175
} else {
175176
//UNCONFIRMED or PROPRIETARY
176177
_params.ul_frame_counter++;

features/lorawan/lorastack/phy/LoRaPHY.cpp

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ SPDX-License-Identifier: BSD-3-Clause
3232
#define BACKOFF_DC_1_HOUR 100
3333
#define BACKOFF_DC_10_HOURS 1000
3434
#define BACKOFF_DC_24_HOURS 10000
35-
36-
#define CHANNELS_IN_MASK 16
35+
#define MAX_PREAMBLE_LENGTH 8.0f
36+
#define TICK_GRANULARITY_JITTER 1.0f
37+
#define CHANNELS_IN_MASK 16
3738

3839
LoRaPHY::LoRaPHY()
3940
: _radio(NULL),
@@ -388,23 +389,56 @@ uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params,
388389
return status;
389390
}
390391

391-
double LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth)
392+
float LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth)
392393
{
393-
return ((double)(1 << phy_dr) / (double) bandwidth) * 1000;
394+
// in milliseconds
395+
return ((float)(1 << phy_dr) / (float) bandwidth * 1000);
394396
}
395397

396-
double LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr)
398+
float LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr)
397399
{
398-
return (8.0 / (double) phy_dr); // 1 symbol equals 1 byte
400+
return (8.0f / (float) phy_dr); // 1 symbol equals 1 byte
399401
}
400402

401-
void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb,
402-
uint32_t rx_error, uint32_t wakeup_time,
403-
uint32_t *window_timeout, int32_t *window_offset)
403+
404+
void LoRaPHY::get_rx_window_params(float t_symb, uint8_t min_rx_symb,
405+
float error_fudge, float wakeup_time,
406+
uint32_t *window_length, int32_t *window_offset,
407+
uint8_t phy_dr)
404408
{
405-
// Computed number of symbols
406-
*window_timeout = MAX((uint32_t) ceil(((2 * min_rx_symb - 8) * t_symb + 2 * rx_error) / t_symb), min_rx_symb);
407-
*window_offset = (int32_t) ceil((4.0 * t_symb) - ((*window_timeout * t_symb) / 2.0) - wakeup_time);
409+
float target_rx_window_offset;
410+
float window_len_in_ms;
411+
412+
if (phy_params.fsk_supported && phy_dr == phy_params.max_rx_datarate) {
413+
min_rx_symb = MAX_PREAMBLE_LENGTH;
414+
}
415+
416+
// We wish to be as close as possible to the actual start of data, i.e.,
417+
// we are interested in the preamble symbols which are at the tail of the
418+
// preamble sequence.
419+
target_rx_window_offset = (MAX_PREAMBLE_LENGTH - min_rx_symb) * t_symb; //in ms
420+
421+
// Actual window offset in ms in response to timing error fudge factor and
422+
// radio wakeup/turned around time.
423+
*window_offset = floor(target_rx_window_offset - error_fudge - wakeup_time);
424+
425+
// possible wait for next symbol start if we start inside the preamble
426+
float possible_wait_for_symb_start = MIN(t_symb,
427+
((2 * error_fudge) + wakeup_time + TICK_GRANULARITY_JITTER));
428+
429+
// how early we might start reception relative to transmit start (so negative if before transmit starts)
430+
float earliest_possible_start_time = *window_offset - error_fudge - TICK_GRANULARITY_JITTER;
431+
432+
// time in (ms) we may have to wait for the other side to start transmission
433+
float possible_wait_for_transmit = -earliest_possible_start_time;
434+
435+
// Minimum reception time plus extra time (in ms) we may have turned on before the
436+
// other side started transmission
437+
window_len_in_ms = (min_rx_symb * t_symb) + MAX(possible_wait_for_transmit, possible_wait_for_symb_start);
438+
439+
// Setting the window_length in terms of 'symbols' for LoRa modulation or
440+
// in terms of 'bytes' for FSK
441+
*window_length = (uint32_t) ceil(window_len_in_ms / t_symb);
408442
}
409443

410444
int8_t LoRaPHY::compute_tx_power(int8_t tx_power_idx, float max_eirp,
@@ -791,7 +825,7 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols,
791825
uint32_t rx_error,
792826
rx_config_params_t *rx_conf_params)
793827
{
794-
double t_symbol = 0.0;
828+
float t_symbol = 0.0;
795829

796830
// Get the datarate, perform a boundary check
797831
rx_conf_params->datarate = MIN(datarate, phy_params.max_rx_datarate);
@@ -811,9 +845,9 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols,
811845
rx_conf_params->frequency = phy_params.channels.channel_list[rx_conf_params->channel].frequency;
812846
}
813847

814-
815-
get_rx_window_params(t_symbol, min_rx_symbols, rx_error, RADIO_WAKEUP_TIME,
816-
&rx_conf_params->window_timeout, &rx_conf_params->window_offset);
848+
get_rx_window_params(t_symbol, min_rx_symbols, (float) rx_error, MBED_CONF_LORA_WAKEUP_TIME,
849+
&rx_conf_params->window_timeout, &rx_conf_params->window_offset,
850+
rx_conf_params->datarate);
817851
}
818852

819853
bool LoRaPHY::rx_config(rx_config_params_t *rx_conf)
@@ -847,13 +881,13 @@ bool LoRaPHY::rx_config(rx_config_params_t *rx_conf)
847881
// Radio configuration
848882
if (dr == DR_7 && phy_params.fsk_supported) {
849883
modem = MODEM_FSK;
850-
_radio->set_rx_config(modem, 50000, phy_dr * 1000, 0, 83333, 5,
884+
_radio->set_rx_config(modem, 50000, phy_dr * 1000, 0, 83333, MAX_PREAMBLE_LENGTH,
851885
rx_conf->window_timeout, false, 0, true, 0, 0,
852886
false, rx_conf->is_rx_continuous);
853887
} else {
854888
modem = MODEM_LORA;
855889
_radio->set_rx_config(modem, rx_conf->bandwidth, phy_dr, 1, 0,
856-
MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH,
890+
MAX_PREAMBLE_LENGTH,
857891
rx_conf->window_timeout, false, 0, false, 0, 0,
858892
true, rx_conf->is_rx_continuous);
859893
}
@@ -899,8 +933,8 @@ bool LoRaPHY::tx_config(tx_config_params_t *tx_conf, int8_t *tx_power,
899933
// High Speed FSK channel
900934
modem = MODEM_FSK;
901935
_radio->set_tx_config(modem, phy_tx_power, 25000, bandwidth,
902-
phy_dr * 1000, 0, 5, false, true, 0, 0, false,
903-
3000);
936+
phy_dr * 1000, 0, MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH,
937+
false, true, 0, 0, false, 3000);
904938
} else {
905939
modem = MODEM_LORA;
906940
_radio->set_tx_config(modem, phy_tx_power, 0, bandwidth, phy_dr, 1,

features/lorawan/lorastack/phy/LoRaPHY.h

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -202,40 +202,63 @@ class LoRaPHY : private mbed::NonCopyable<LoRaPHY> {
202202

203203
/** Computing Receive Windows
204204
*
205-
* For more details please consult the following document, chapter 3.1.2.
206-
* http://www.semtech.com/images/datasheet/SX1272_settings_for_LoRaWAN_v2.0.pdf
207-
* or
208-
* http://www.semtech.com/images/datasheet/SX1276_settings_for_LoRaWAN_v2.0.pdf
209-
*
210-
* Downlink start: T = Tx + 1s (+/- 20 us)
211-
* |
212-
* TRxEarly | TRxLate
213-
* | | |
214-
* | | +---+---+---+---+---+---+---+---+
215-
* | | | Latest Rx window |
216-
* | | +---+---+---+---+---+---+---+---+
217-
* | | |
205+
* The algorithm tries to calculate the length of receive windows (i.e.,
206+
* the minimum time it should remain to acquire a lock on the Preamble
207+
* for synchronization) and the error offset which compensates for the system
208+
* timing errors. Basic idea behind the algorithm is to optimize for the
209+
* reception of last 'min_rx_symbols' symbols out of transmitted Premable
210+
* symbols. The algorithm compensates for the clock drifts, tick granularity
211+
* and system wake up time (from sleep state) by opening the window early for
212+
* the lower SFs. For higher SFs, the symbol time is large enough that we can
213+
* afford to open late (hence the positive offset).
214+
* The table below shows the calculated values for SF7 to SF12 with 125 kHz
215+
* bandwidth.
216+
*
217+
* +----+-----+----------+---------+-------------------------+----------------------+-------------------------+
218+
* | SF | BW (kHz) | rx_error (ms) | wake_up (ms) | min_rx_symbols | window_timeout(symb) | window_offset(ms) |
219+
* +----+-----+----------+---------+-------------------------+----------------------+-------------------------+
220+
* | 7 | 125 | 5 | 5 | 5 | 18 | -7 |
221+
* | 8 | 125 | 5 | 5 | 5 | 10 | -4 |
222+
* | 9 | 125 | 5 | 5 | 5 | 6 | 2 |
223+
* | 10 | 125 | 5 | 5 | 5 | 6 | 14 |
224+
* | 11 | 125 | 5 | 5 | 5 | 6 | 39 |
225+
* | 12 | 125 | 5 | 5 | 5 | 6 | 88 |
226+
* +----+-----+----------+---------+-------------------------+----------------------+-------------------------+
227+
*
228+
* For example for SF7, the receive window will open at downlink start time
229+
* plus the offset calculated and will remain open for the length window_timeout.
230+
*
231+
* Symbol time = 1.024 ms
232+
* Downlink start: T = Tx + 1s (+/- 20 us)
233+
* |
234+
* |
235+
* |
236+
* |
237+
* |
238+
* +---+---+---+---+---+---+---+---+
239+
* | 8 Preamble Symbols |
240+
* +---+---+---+---+---+---+---+---+
241+
* | RX Window start time = T +/- Offset
242+
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
243+
* | | | | | | | | | | | | | | | | | | |
244+
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
245+
*
246+
* Similarly for SF12:
247+
*
248+
* Symbol time = 32.768 ms
249+
* Downlink start: T = Tx + 1s (+/- 20 us)
250+
* |
251+
* |
252+
* |
253+
* |
254+
* |
218255
* +---+---+---+---+---+---+---+---+
219-
* | Earliest Rx window |
256+
* | 8 Preamble Symbols |
220257
* +---+---+---+---+---+---+---+---+
221-
* |
222-
* +---+---+---+---+---+---+---+---+
223-
*Downlink preamble 8 symbols | | | | | | | | |
224-
* +---+---+---+---+---+---+---+---+
225-
*
226-
* Worst case Rx window timings
227-
*
228-
* TRxLate = DEFAULT_MIN_RX_SYMBOLS * tSymbol - RADIO_WAKEUP_TIME
229-
* TRxEarly = 8 - DEFAULT_MIN_RX_SYMBOLS * tSymbol - RxWindowTimeout - RADIO_WAKEUP_TIME
230-
*
231-
* TRxLate - TRxEarly = 2 * DEFAULT_SYSTEM_MAX_RX_ERROR
232-
*
233-
* RxOffset = ( TRxLate + TRxEarly ) / 2
234-
*
235-
* RxWindowTimeout = ( 2 * DEFAULT_MIN_RX_SYMBOLS - 8 ) * tSymbol + 2 * DEFAULT_SYSTEM_MAX_RX_ERROR
236-
* RxOffset = 4 * tSymbol - RxWindowTimeout / 2 - RADIO_WAKE_UP_TIME
237-
*
238-
* The minimum value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol.
258+
* | RX Window start time = T +/- Offset
259+
* +---+---+---+---+---+---+
260+
* | | | | | | |
261+
* +---+---+---+---+---+---+
239262
*/
240263
/*!
241264
* Computes the RX window timeout and offset.
@@ -597,9 +620,10 @@ class LoRaPHY : private mbed::NonCopyable<LoRaPHY> {
597620
/**
598621
* Computes the RX window timeout and the RX window offset.
599622
*/
600-
void get_rx_window_params(double t_symbol, uint8_t min_rx_symbols,
601-
uint32_t rx_error, uint32_t wakeup_time,
602-
uint32_t *window_timeout, int32_t *window_offset);
623+
void get_rx_window_params(float t_symbol, uint8_t min_rx_symbols,
624+
float rx_error, float wakeup_time,
625+
uint32_t *window_length, int32_t *window_offset,
626+
uint8_t phy_dr);
603627

604628
/**
605629
* Computes the txPower, based on the max EIRP and the antenna gain.
@@ -632,12 +656,12 @@ class LoRaPHY : private mbed::NonCopyable<LoRaPHY> {
632656
/**
633657
* Computes the symbol time for LoRa modulation.
634658
*/
635-
double compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth);
659+
float compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth);
636660

637661
/**
638662
* Computes the symbol time for FSK modulation.
639663
*/
640-
double compute_symb_timeout_fsk(uint8_t phy_dr);
664+
float compute_symb_timeout_fsk(uint8_t phy_dr);
641665

642666
protected:
643667
LoRaRadio *_radio;

features/lorawan/mbed_lib.json

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,28 @@
7070
"value": true
7171
},
7272
"max-sys-rx-error": {
73-
"help": "Maximum timing error of the receiver in ms. The receiver will turn on in [-RxError : + RxError]",
74-
"value": 10
73+
"help": "Max. timing error fudge. The receiver will turn on in [-RxError : + RxError]",
74+
"value": 5
75+
},
76+
"wakeup-time": {
77+
"help": "Time in (ms) the platform takes to wakeup from sleep/deep sleep state. This number is platform dependent",
78+
"value": 5
7579
},
7680
"downlink-preamble-length": {
77-
"help": "Number of preamble symbols need to be captured (out of 8) for successful demodulation",
78-
"value": 5
81+
"help": "Number of whole preamble symbols needed to have a firm lock on the signal.",
82+
"value": 5
7983
},
8084
"uplink-preamble-length": {
81-
"help": "Number of preamble symbols to transmit. Must be <= 8",
82-
"value": 8
85+
"help": "Number of preamble symbols to transmit. Default: 8",
86+
"value": 8
8387
},
8488
"fsb-mask": {
85-
"help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details",
86-
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}"
89+
"help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details",
90+
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}"
8791
},
8892
"fsb-mask-china": {
89-
"help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details",
90-
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}"
93+
"help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details",
94+
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}"
9195
}
9296
}
9397
}

features/lorawan/system/lorawan_data_structures.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@
4444
typedef uint32_t lorawan_time_t;
4545
#endif
4646

47-
// Radio wake-up time from sleep - unit ms.
48-
#define RADIO_WAKEUP_TIME 1
49-
5047
/*!
5148
* Sets the length of the LoRaMAC footer field.
5249
* Mainly indicates the MIC field length.
@@ -1259,8 +1256,8 @@ typedef struct {
12591256

12601257
/*!
12611258
* LoRaMac reception windows delay
1262-
* \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
1263-
* join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
1259+
* \remark normal frame: RxWindowXDelay = ReceiveDelayX - Offset
1260+
* join frame : RxWindowXDelay = JoinAcceptDelayX - Offset
12641261
*/
12651262
uint32_t rx_window1_delay;
12661263
uint32_t rx_window2_delay;

0 commit comments

Comments
 (0)