mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #8822 from hasnainvirk/dr0_and_fcnt_issue
LoRaWAN: Mitigating reception issues at lower data rates & FCnt increment after retry exhaustionpull/9043/head
commit
3875ac18d0
|
@ -37,5 +37,5 @@ set(unittest-test-sources
|
|||
)
|
||||
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH=8 -DMBED_CONF_LORA_DUTY_CYCLE_ON_JOIN=true")
|
||||
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")
|
||||
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")
|
||||
|
|
|
@ -168,9 +168,10 @@ uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params,
|
|||
return LoRaPHY_stub::uint8_value;
|
||||
}
|
||||
|
||||
void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb,
|
||||
uint32_t rx_error, uint32_t wakeup_time,
|
||||
uint32_t *window_timeout, int32_t *window_offset)
|
||||
void LoRaPHY::get_rx_window_params(float t_symbol, uint8_t min_rx_symbols,
|
||||
float rx_error, float wakeup_time,
|
||||
uint32_t *window_length, int32_t *window_offset,
|
||||
uint8_t phy_dr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -614,6 +614,8 @@ void LoRaWANStack::post_process_tx_with_reception()
|
|||
_loramac.get_device_class() == CLASS_A ? "A" : "C");
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
_ctrl_flags |= RETRY_EXHAUSTED_FLAG;
|
||||
_loramac.post_process_mcps_req();
|
||||
make_tx_metadata_available();
|
||||
state_controller(DEVICE_STATE_STATUS_CHECK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,11 +166,12 @@ void LoRaMac::post_process_mcps_req()
|
|||
_params.is_node_ack_requested = false;
|
||||
_mcps_confirmation.ack_received = false;
|
||||
_mcps_indication.is_ack_recvd = false;
|
||||
_params.ul_frame_counter++;
|
||||
_params.adr_ack_counter++;
|
||||
} else {
|
||||
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
|
||||
}
|
||||
|
||||
_params.ul_frame_counter++;
|
||||
_params.adr_ack_counter++;
|
||||
} else {
|
||||
//UNCONFIRMED or PROPRIETARY
|
||||
_params.ul_frame_counter++;
|
||||
|
|
|
@ -32,8 +32,9 @@ SPDX-License-Identifier: BSD-3-Clause
|
|||
#define BACKOFF_DC_1_HOUR 100
|
||||
#define BACKOFF_DC_10_HOURS 1000
|
||||
#define BACKOFF_DC_24_HOURS 10000
|
||||
|
||||
#define CHANNELS_IN_MASK 16
|
||||
#define MAX_PREAMBLE_LENGTH 8.0f
|
||||
#define TICK_GRANULARITY_JITTER 1.0f
|
||||
#define CHANNELS_IN_MASK 16
|
||||
|
||||
LoRaPHY::LoRaPHY()
|
||||
: _radio(NULL),
|
||||
|
@ -388,23 +389,56 @@ uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params,
|
|||
return status;
|
||||
}
|
||||
|
||||
double LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth)
|
||||
float LoRaPHY::compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth)
|
||||
{
|
||||
return ((double)(1 << phy_dr) / (double) bandwidth) * 1000;
|
||||
// in milliseconds
|
||||
return ((float)(1 << phy_dr) / (float) bandwidth * 1000);
|
||||
}
|
||||
|
||||
double LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr)
|
||||
float LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr)
|
||||
{
|
||||
return (8.0 / (double) phy_dr); // 1 symbol equals 1 byte
|
||||
return (8.0f / (float) phy_dr); // 1 symbol equals 1 byte
|
||||
}
|
||||
|
||||
void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb,
|
||||
uint32_t rx_error, uint32_t wakeup_time,
|
||||
uint32_t *window_timeout, int32_t *window_offset)
|
||||
|
||||
void LoRaPHY::get_rx_window_params(float t_symb, uint8_t min_rx_symb,
|
||||
float error_fudge, float wakeup_time,
|
||||
uint32_t *window_length, int32_t *window_offset,
|
||||
uint8_t phy_dr)
|
||||
{
|
||||
// Computed number of symbols
|
||||
*window_timeout = MAX((uint32_t) ceil(((2 * min_rx_symb - 8) * t_symb + 2 * rx_error) / t_symb), min_rx_symb);
|
||||
*window_offset = (int32_t) ceil((4.0 * t_symb) - ((*window_timeout * t_symb) / 2.0) - wakeup_time);
|
||||
float target_rx_window_offset;
|
||||
float window_len_in_ms;
|
||||
|
||||
if (phy_params.fsk_supported && phy_dr == phy_params.max_rx_datarate) {
|
||||
min_rx_symb = MAX_PREAMBLE_LENGTH;
|
||||
}
|
||||
|
||||
// We wish to be as close as possible to the actual start of data, i.e.,
|
||||
// we are interested in the preamble symbols which are at the tail of the
|
||||
// preamble sequence.
|
||||
target_rx_window_offset = (MAX_PREAMBLE_LENGTH - min_rx_symb) * t_symb; //in ms
|
||||
|
||||
// Actual window offset in ms in response to timing error fudge factor and
|
||||
// radio wakeup/turned around time.
|
||||
*window_offset = floor(target_rx_window_offset - error_fudge - wakeup_time);
|
||||
|
||||
// possible wait for next symbol start if we start inside the preamble
|
||||
float possible_wait_for_symb_start = MIN(t_symb,
|
||||
((2 * error_fudge) + wakeup_time + TICK_GRANULARITY_JITTER));
|
||||
|
||||
// how early we might start reception relative to transmit start (so negative if before transmit starts)
|
||||
float earliest_possible_start_time = *window_offset - error_fudge - TICK_GRANULARITY_JITTER;
|
||||
|
||||
// time in (ms) we may have to wait for the other side to start transmission
|
||||
float possible_wait_for_transmit = -earliest_possible_start_time;
|
||||
|
||||
// Minimum reception time plus extra time (in ms) we may have turned on before the
|
||||
// other side started transmission
|
||||
window_len_in_ms = (min_rx_symb * t_symb) + MAX(possible_wait_for_transmit, possible_wait_for_symb_start);
|
||||
|
||||
// Setting the window_length in terms of 'symbols' for LoRa modulation or
|
||||
// in terms of 'bytes' for FSK
|
||||
*window_length = (uint32_t) ceil(window_len_in_ms / t_symb);
|
||||
}
|
||||
|
||||
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,
|
|||
uint32_t rx_error,
|
||||
rx_config_params_t *rx_conf_params)
|
||||
{
|
||||
double t_symbol = 0.0;
|
||||
float t_symbol = 0.0;
|
||||
|
||||
// Get the datarate, perform a boundary check
|
||||
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,
|
|||
rx_conf_params->frequency = phy_params.channels.channel_list[rx_conf_params->channel].frequency;
|
||||
}
|
||||
|
||||
|
||||
get_rx_window_params(t_symbol, min_rx_symbols, rx_error, RADIO_WAKEUP_TIME,
|
||||
&rx_conf_params->window_timeout, &rx_conf_params->window_offset);
|
||||
get_rx_window_params(t_symbol, min_rx_symbols, (float) rx_error, MBED_CONF_LORA_WAKEUP_TIME,
|
||||
&rx_conf_params->window_timeout, &rx_conf_params->window_offset,
|
||||
rx_conf_params->datarate);
|
||||
}
|
||||
|
||||
bool LoRaPHY::rx_config(rx_config_params_t *rx_conf)
|
||||
|
@ -847,13 +881,13 @@ bool LoRaPHY::rx_config(rx_config_params_t *rx_conf)
|
|||
// Radio configuration
|
||||
if (dr == DR_7 && phy_params.fsk_supported) {
|
||||
modem = MODEM_FSK;
|
||||
_radio->set_rx_config(modem, 50000, phy_dr * 1000, 0, 83333, 5,
|
||||
_radio->set_rx_config(modem, 50000, phy_dr * 1000, 0, 83333, MAX_PREAMBLE_LENGTH,
|
||||
rx_conf->window_timeout, false, 0, true, 0, 0,
|
||||
false, rx_conf->is_rx_continuous);
|
||||
} else {
|
||||
modem = MODEM_LORA;
|
||||
_radio->set_rx_config(modem, rx_conf->bandwidth, phy_dr, 1, 0,
|
||||
MBED_CONF_LORA_DOWNLINK_PREAMBLE_LENGTH,
|
||||
MAX_PREAMBLE_LENGTH,
|
||||
rx_conf->window_timeout, false, 0, false, 0, 0,
|
||||
true, rx_conf->is_rx_continuous);
|
||||
}
|
||||
|
@ -899,8 +933,8 @@ bool LoRaPHY::tx_config(tx_config_params_t *tx_conf, int8_t *tx_power,
|
|||
// High Speed FSK channel
|
||||
modem = MODEM_FSK;
|
||||
_radio->set_tx_config(modem, phy_tx_power, 25000, bandwidth,
|
||||
phy_dr * 1000, 0, 5, false, true, 0, 0, false,
|
||||
3000);
|
||||
phy_dr * 1000, 0, MBED_CONF_LORA_UPLINK_PREAMBLE_LENGTH,
|
||||
false, true, 0, 0, false, 3000);
|
||||
} else {
|
||||
modem = MODEM_LORA;
|
||||
_radio->set_tx_config(modem, phy_tx_power, 0, bandwidth, phy_dr, 1,
|
||||
|
|
|
@ -202,40 +202,63 @@ public:
|
|||
|
||||
/** Computing Receive Windows
|
||||
*
|
||||
* For more details please consult the following document, chapter 3.1.2.
|
||||
* http://www.semtech.com/images/datasheet/SX1272_settings_for_LoRaWAN_v2.0.pdf
|
||||
* or
|
||||
* http://www.semtech.com/images/datasheet/SX1276_settings_for_LoRaWAN_v2.0.pdf
|
||||
* The algorithm tries to calculate the length of receive windows (i.e.,
|
||||
* the minimum time it should remain to acquire a lock on the Preamble
|
||||
* for synchronization) and the error offset which compensates for the system
|
||||
* timing errors. Basic idea behind the algorithm is to optimize for the
|
||||
* reception of last 'min_rx_symbols' symbols out of transmitted Premable
|
||||
* symbols. The algorithm compensates for the clock drifts, tick granularity
|
||||
* and system wake up time (from sleep state) by opening the window early for
|
||||
* the lower SFs. For higher SFs, the symbol time is large enough that we can
|
||||
* afford to open late (hence the positive offset).
|
||||
* The table below shows the calculated values for SF7 to SF12 with 125 kHz
|
||||
* bandwidth.
|
||||
*
|
||||
* Downlink start: T = Tx + 1s (+/- 20 us)
|
||||
* |
|
||||
* TRxEarly | TRxLate
|
||||
* | | |
|
||||
* | | +---+---+---+---+---+---+---+---+
|
||||
* | | | Latest Rx window |
|
||||
* | | +---+---+---+---+---+---+---+---+
|
||||
* | | |
|
||||
* +----+-----+----------+---------+-------------------------+----------------------+-------------------------+
|
||||
* | SF | BW (kHz) | rx_error (ms) | wake_up (ms) | min_rx_symbols | window_timeout(symb) | window_offset(ms) |
|
||||
* +----+-----+----------+---------+-------------------------+----------------------+-------------------------+
|
||||
* | 7 | 125 | 5 | 5 | 5 | 18 | -7 |
|
||||
* | 8 | 125 | 5 | 5 | 5 | 10 | -4 |
|
||||
* | 9 | 125 | 5 | 5 | 5 | 6 | 2 |
|
||||
* | 10 | 125 | 5 | 5 | 5 | 6 | 14 |
|
||||
* | 11 | 125 | 5 | 5 | 5 | 6 | 39 |
|
||||
* | 12 | 125 | 5 | 5 | 5 | 6 | 88 |
|
||||
* +----+-----+----------+---------+-------------------------+----------------------+-------------------------+
|
||||
*
|
||||
* For example for SF7, the receive window will open at downlink start time
|
||||
* plus the offset calculated and will remain open for the length window_timeout.
|
||||
*
|
||||
* Symbol time = 1.024 ms
|
||||
* Downlink start: T = Tx + 1s (+/- 20 us)
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | 8 Preamble Symbols |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | RX Window start time = T +/- Offset
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | | | | | | | | | | | | | | | | | | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* Similarly for SF12:
|
||||
*
|
||||
* Symbol time = 32.768 ms
|
||||
* Downlink start: T = Tx + 1s (+/- 20 us)
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* | Earliest Rx window |
|
||||
* | 8 Preamble Symbols |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
*Downlink preamble 8 symbols | | | | | | | | |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* Worst case Rx window timings
|
||||
*
|
||||
* TRxLate = DEFAULT_MIN_RX_SYMBOLS * tSymbol - RADIO_WAKEUP_TIME
|
||||
* TRxEarly = 8 - DEFAULT_MIN_RX_SYMBOLS * tSymbol - RxWindowTimeout - RADIO_WAKEUP_TIME
|
||||
*
|
||||
* TRxLate - TRxEarly = 2 * DEFAULT_SYSTEM_MAX_RX_ERROR
|
||||
*
|
||||
* RxOffset = ( TRxLate + TRxEarly ) / 2
|
||||
*
|
||||
* RxWindowTimeout = ( 2 * DEFAULT_MIN_RX_SYMBOLS - 8 ) * tSymbol + 2 * DEFAULT_SYSTEM_MAX_RX_ERROR
|
||||
* RxOffset = 4 * tSymbol - RxWindowTimeout / 2 - RADIO_WAKE_UP_TIME
|
||||
*
|
||||
* The minimum value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol.
|
||||
* | RX Window start time = T +/- Offset
|
||||
* +---+---+---+---+---+---+
|
||||
* | | | | | | |
|
||||
* +---+---+---+---+---+---+
|
||||
*/
|
||||
/*!
|
||||
* Computes the RX window timeout and offset.
|
||||
|
@ -597,9 +620,10 @@ protected:
|
|||
/**
|
||||
* Computes the RX window timeout and the RX window offset.
|
||||
*/
|
||||
void get_rx_window_params(double t_symbol, uint8_t min_rx_symbols,
|
||||
uint32_t rx_error, uint32_t wakeup_time,
|
||||
uint32_t *window_timeout, int32_t *window_offset);
|
||||
void get_rx_window_params(float t_symbol, uint8_t min_rx_symbols,
|
||||
float rx_error, float wakeup_time,
|
||||
uint32_t *window_length, int32_t *window_offset,
|
||||
uint8_t phy_dr);
|
||||
|
||||
/**
|
||||
* Computes the txPower, based on the max EIRP and the antenna gain.
|
||||
|
@ -632,12 +656,12 @@ private:
|
|||
/**
|
||||
* Computes the symbol time for LoRa modulation.
|
||||
*/
|
||||
double compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth);
|
||||
float compute_symb_timeout_lora(uint8_t phy_dr, uint32_t bandwidth);
|
||||
|
||||
/**
|
||||
* Computes the symbol time for FSK modulation.
|
||||
*/
|
||||
double compute_symb_timeout_fsk(uint8_t phy_dr);
|
||||
float compute_symb_timeout_fsk(uint8_t phy_dr);
|
||||
|
||||
protected:
|
||||
LoRaRadio *_radio;
|
||||
|
|
|
@ -70,24 +70,28 @@
|
|||
"value": true
|
||||
},
|
||||
"max-sys-rx-error": {
|
||||
"help": "Maximum timing error of the receiver in ms. The receiver will turn on in [-RxError : + RxError]",
|
||||
"value": 10
|
||||
"help": "Max. timing error fudge. The receiver will turn on in [-RxError : + RxError]",
|
||||
"value": 5
|
||||
},
|
||||
"wakeup-time": {
|
||||
"help": "Time in (ms) the platform takes to wakeup from sleep/deep sleep state. This number is platform dependent",
|
||||
"value": 5
|
||||
},
|
||||
"downlink-preamble-length": {
|
||||
"help": "Number of preamble symbols need to be captured (out of 8) for successful demodulation",
|
||||
"value": 5
|
||||
"help": "Number of whole preamble symbols needed to have a firm lock on the signal.",
|
||||
"value": 5
|
||||
},
|
||||
"uplink-preamble-length": {
|
||||
"help": "Number of preamble symbols to transmit. Must be <= 8",
|
||||
"value": 8
|
||||
"help": "Number of preamble symbols to transmit. Default: 8",
|
||||
"value": 8
|
||||
},
|
||||
"fsb-mask": {
|
||||
"help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details",
|
||||
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}"
|
||||
"help": "FSB mask for upstream [Only for US915 & AU915] Check lorawan/FSB_Usage.txt for more details",
|
||||
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}"
|
||||
},
|
||||
"fsb-mask-china": {
|
||||
"help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details",
|
||||
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}"
|
||||
"help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details",
|
||||
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
typedef uint32_t lorawan_time_t;
|
||||
#endif
|
||||
|
||||
// Radio wake-up time from sleep - unit ms.
|
||||
#define RADIO_WAKEUP_TIME 1
|
||||
|
||||
/*!
|
||||
* Sets the length of the LoRaMAC footer field.
|
||||
* Mainly indicates the MIC field length.
|
||||
|
@ -1259,8 +1256,8 @@ typedef struct {
|
|||
|
||||
/*!
|
||||
* LoRaMac reception windows delay
|
||||
* \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
|
||||
* join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
|
||||
* \remark normal frame: RxWindowXDelay = ReceiveDelayX - Offset
|
||||
* join frame : RxWindowXDelay = JoinAcceptDelayX - Offset
|
||||
*/
|
||||
uint32_t rx_window1_delay;
|
||||
uint32_t rx_window2_delay;
|
||||
|
|
Loading…
Reference in New Issue