mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #7191 from hasnainvirk/precise_timing
LoRaWAN: Fine tuning timing for delays and receive windowspull/7264/head
commit
ba5b5a3870
|
@ -68,20 +68,20 @@ using namespace events;
|
||||||
* Constructor *
|
* Constructor *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
LoRaWANStack::LoRaWANStack()
|
LoRaWANStack::LoRaWANStack()
|
||||||
: _loramac(),
|
: _loramac(),
|
||||||
_device_current_state(DEVICE_STATE_NOT_INITIALIZED),
|
_device_current_state(DEVICE_STATE_NOT_INITIALIZED),
|
||||||
_lw_session(),
|
_lw_session(),
|
||||||
_tx_msg(),
|
_tx_msg(),
|
||||||
_rx_msg(),
|
_rx_msg(),
|
||||||
_tx_metadata(),
|
_tx_metadata(),
|
||||||
_rx_metadata(),
|
_rx_metadata(),
|
||||||
_num_retry(1),
|
_num_retry(1),
|
||||||
_ctrl_flags(IDLE_FLAG),
|
_ctrl_flags(IDLE_FLAG),
|
||||||
_app_port(INVALID_PORT),
|
_app_port(INVALID_PORT),
|
||||||
_link_check_requested(false),
|
_link_check_requested(false),
|
||||||
_automatic_uplink_ongoing(false),
|
_automatic_uplink_ongoing(false),
|
||||||
_ready_for_rx(true),
|
_ready_for_rx(true),
|
||||||
_queue(NULL)
|
_queue(NULL)
|
||||||
{
|
{
|
||||||
_tx_metadata.stale = true;
|
_tx_metadata.stale = true;
|
||||||
_rx_metadata.stale = true;
|
_rx_metadata.stale = true;
|
||||||
|
@ -481,7 +481,7 @@ lorawan_status_t LoRaWANStack::acquire_rx_metadata(lorawan_rx_metadata &metadata
|
||||||
return LORAWAN_STATUS_METADATA_NOT_AVAILABLE;
|
return LORAWAN_STATUS_METADATA_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int& backoff)
|
lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int &backoff)
|
||||||
{
|
{
|
||||||
if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
|
if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
|
||||||
return LORAWAN_STATUS_NOT_INITIALIZED;
|
return LORAWAN_STATUS_NOT_INITIALIZED;
|
||||||
|
@ -503,6 +503,7 @@ lorawan_status_t LoRaWANStack::acquire_backoff_metadata(int& backoff)
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
void LoRaWANStack::tx_interrupt_handler(void)
|
void LoRaWANStack::tx_interrupt_handler(void)
|
||||||
{
|
{
|
||||||
|
_tx_timestamp = _loramac.get_current_time();
|
||||||
const int ret = _queue->call(this, &LoRaWANStack::process_transmission);
|
const int ret = _queue->call(this, &LoRaWANStack::process_transmission);
|
||||||
MBED_ASSERT(ret != 0);
|
MBED_ASSERT(ret != 0);
|
||||||
(void)ret;
|
(void)ret;
|
||||||
|
@ -565,7 +566,7 @@ void LoRaWANStack::process_transmission_timeout()
|
||||||
void LoRaWANStack::process_transmission(void)
|
void LoRaWANStack::process_transmission(void)
|
||||||
{
|
{
|
||||||
tr_debug("Transmission completed");
|
tr_debug("Transmission completed");
|
||||||
_loramac.on_radio_tx_done();
|
_loramac.on_radio_tx_done(_tx_timestamp);
|
||||||
|
|
||||||
make_tx_metadata_available();
|
make_tx_metadata_available();
|
||||||
|
|
||||||
|
@ -680,10 +681,12 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
|
||||||
|
|
||||||
void LoRaWANStack::process_reception_timeout(bool is_timeout)
|
void LoRaWANStack::process_reception_timeout(bool is_timeout)
|
||||||
{
|
{
|
||||||
|
rx_slot_t slot = _loramac.get_current_slot();
|
||||||
|
|
||||||
// when is_timeout == false, a CRC error took place in the received frame
|
// when is_timeout == false, a CRC error took place in the received frame
|
||||||
// we treat that erroneous frame as no frame received at all, hence handle
|
// we treat that erroneous frame as no frame received at all, hence handle
|
||||||
// it exactly as we would handle timeout
|
// it exactly as we would handle timeout
|
||||||
rx_slot_t slot = _loramac.on_radio_rx_timeout(is_timeout);
|
_loramac.on_radio_rx_timeout(is_timeout);
|
||||||
|
|
||||||
if (slot == RX_SLOT_WIN_2 && !_loramac.nwk_joined()) {
|
if (slot == RX_SLOT_WIN_2 && !_loramac.nwk_joined()) {
|
||||||
state_controller(DEVICE_STATE_JOINING);
|
state_controller(DEVICE_STATE_JOINING);
|
||||||
|
@ -851,9 +854,11 @@ void LoRaWANStack::mlme_indication_handler()
|
||||||
#if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE
|
#if MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE
|
||||||
_automatic_uplink_ongoing = true;
|
_automatic_uplink_ongoing = true;
|
||||||
tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands...");
|
tr_debug("mlme indication: sending empty uplink to port 0 to acknowledge MAC commands...");
|
||||||
send_automatic_uplink_message(0);
|
const uint8_t port = 0;
|
||||||
|
const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, port);
|
||||||
|
MBED_ASSERT(ret != 0);
|
||||||
|
(void)ret;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
send_event_to_application(UPLINK_REQUIRED);
|
send_event_to_application(UPLINK_REQUIRED);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
|
@ -957,8 +962,9 @@ void LoRaWANStack::mcps_indication_handler()
|
||||||
_rx_msg.msg.mcps_indication.type = mcps_indication->type;
|
_rx_msg.msg.mcps_indication.type = mcps_indication->type;
|
||||||
|
|
||||||
// Notify application about received frame..
|
// Notify application about received frame..
|
||||||
tr_debug("Packet Received %d bytes",
|
tr_debug("Packet Received %d bytes, Port=%d",
|
||||||
_rx_msg.msg.mcps_indication.buffer_size);
|
_rx_msg.msg.mcps_indication.buffer_size,
|
||||||
|
mcps_indication->port);
|
||||||
_rx_msg.receive_ready = true;
|
_rx_msg.receive_ready = true;
|
||||||
send_event_to_application(RX_DONE);
|
send_event_to_application(RX_DONE);
|
||||||
}
|
}
|
||||||
|
@ -981,7 +987,9 @@ void LoRaWANStack::mcps_indication_handler()
|
||||||
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
|
#if (MBED_CONF_LORA_AUTOMATIC_UPLINK_MESSAGE)
|
||||||
tr_debug("Sending empty uplink message...");
|
tr_debug("Sending empty uplink message...");
|
||||||
_automatic_uplink_ongoing = true;
|
_automatic_uplink_ongoing = true;
|
||||||
send_automatic_uplink_message(mcps_indication->port);
|
const int ret = _queue->call(this, &LoRaWANStack::send_automatic_uplink_message, mcps_indication->port);
|
||||||
|
MBED_ASSERT(ret != 0);
|
||||||
|
(void)ret;
|
||||||
#else
|
#else
|
||||||
send_event_to_application(UPLINK_REQUIRED);
|
send_event_to_application(UPLINK_REQUIRED);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1354,9 +1362,11 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic
|
||||||
} else if (mcps_indication->buffer_size == 7) {
|
} else if (mcps_indication->buffer_size == 7) {
|
||||||
loramac_mlme_req_t mlme_req;
|
loramac_mlme_req_t mlme_req;
|
||||||
mlme_req.type = MLME_TXCW_1;
|
mlme_req.type = MLME_TXCW_1;
|
||||||
mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8) | mcps_indication->buffer[2]);
|
mlme_req.cw_tx_mode.timeout = (uint16_t)((mcps_indication->buffer[1] << 8)
|
||||||
mlme_req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16) | (mcps_indication->buffer[4] << 8)
|
| mcps_indication->buffer[2]);
|
||||||
| mcps_indication->buffer[5]) * 100;
|
mlme_req.cw_tx_mode.frequency = (uint32_t)((mcps_indication->buffer[3] << 16)
|
||||||
|
| (mcps_indication->buffer[4] << 8)
|
||||||
|
| mcps_indication->buffer[5]) * 100;
|
||||||
mlme_req.cw_tx_mode.power = mcps_indication->buffer[6];
|
mlme_req.cw_tx_mode.power = mcps_indication->buffer[6];
|
||||||
_loramac.mlme_request(&mlme_req);
|
_loramac.mlme_request(&mlme_req);
|
||||||
}
|
}
|
||||||
|
|
|
@ -548,6 +548,7 @@ private:
|
||||||
volatile bool _ready_for_rx;
|
volatile bool _ready_for_rx;
|
||||||
uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD];
|
uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD];
|
||||||
events::EventQueue *_queue;
|
events::EventQueue *_queue;
|
||||||
|
lorawan_time_t _tx_timestamp;
|
||||||
|
|
||||||
#if defined(LORAWAN_COMPLIANCE_TEST)
|
#if defined(LORAWAN_COMPLIANCE_TEST)
|
||||||
|
|
||||||
|
|
|
@ -72,19 +72,19 @@ using namespace mbed;
|
||||||
|
|
||||||
|
|
||||||
LoRaMac::LoRaMac()
|
LoRaMac::LoRaMac()
|
||||||
: _lora_time(),
|
: _lora_time(),
|
||||||
_lora_phy(_lora_time),
|
_lora_phy(_lora_time),
|
||||||
_mac_commands(),
|
_mac_commands(),
|
||||||
_channel_plan(),
|
_channel_plan(),
|
||||||
_lora_crypto(),
|
_lora_crypto(),
|
||||||
_ev_queue(NULL),
|
_ev_queue(NULL),
|
||||||
_mcps_indication(),
|
_mcps_indication(),
|
||||||
_mcps_confirmation(),
|
_mcps_confirmation(),
|
||||||
_mlme_indication(),
|
_mlme_indication(),
|
||||||
_mlme_confirmation(),
|
_mlme_confirmation(),
|
||||||
_is_nwk_joined(false),
|
_is_nwk_joined(false),
|
||||||
_continuous_rx2_window_open(false),
|
_continuous_rx2_window_open(false),
|
||||||
_device_class(CLASS_A)
|
_device_class(CLASS_A)
|
||||||
{
|
{
|
||||||
_params.keys.dev_eui = NULL;
|
_params.keys.dev_eui = NULL;
|
||||||
_params.keys.app_eui = NULL;
|
_params.keys.app_eui = NULL;
|
||||||
|
@ -189,41 +189,14 @@ void LoRaMac::post_process_mlme_ind()
|
||||||
_mlme_indication.pending = false;
|
_mlme_indication.pending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::on_radio_tx_done(void)
|
lorawan_time_t LoRaMac::get_current_time(void)
|
||||||
{
|
{
|
||||||
lorawan_time_t cur_time = _lora_time.get_current_time();
|
return _lora_time.get_current_time();
|
||||||
|
}
|
||||||
|
|
||||||
if (_device_class != CLASS_C) {
|
rx_slot_t LoRaMac::get_current_slot(void)
|
||||||
_lora_phy.put_radio_to_sleep();
|
{
|
||||||
} else {
|
return _params.rx_slot;
|
||||||
// this will open a continuous RX2 window until time==RECV_DELAY1
|
|
||||||
if (!_continuous_rx2_window_open) {
|
|
||||||
open_rx2_window();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_params.is_rx_window_enabled == true) {
|
|
||||||
// start timer after which rx1_window will get opened
|
|
||||||
_lora_time.start(_params.timers.rx_window1_timer, _params.rx_window1_delay);
|
|
||||||
|
|
||||||
if (_device_class != CLASS_C) {
|
|
||||||
_lora_time.start(_params.timers.rx_window2_timer, _params.rx_window2_delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_params.is_node_ack_requested) {
|
|
||||||
_lora_time.start(_params.timers.ack_timeout_timer,
|
|
||||||
_params.rx_window2_delay + _lora_phy.get_ack_timeout());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
|
||||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
_params.last_channel_idx = _params.channel;
|
|
||||||
|
|
||||||
_lora_phy.set_last_tx_done(_params.channel, _is_nwk_joined, cur_time);
|
|
||||||
|
|
||||||
_params.timers.aggregated_last_tx_time = cur_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -311,7 +284,7 @@ void LoRaMac::check_frame_size(uint16_t size)
|
||||||
uint8_t value = _lora_phy.get_max_payload(_mcps_indication.rx_datarate,
|
uint8_t value = _lora_phy.get_max_payload(_mcps_indication.rx_datarate,
|
||||||
_params.is_repeater_supported);
|
_params.is_repeater_supported);
|
||||||
|
|
||||||
if (MAX(0, (int16_t) ((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD))
|
if (MAX(0, (int16_t)((int16_t)size - (int16_t)LORA_MAC_FRMPAYLOAD_OVERHEAD))
|
||||||
> (int32_t) value) {
|
> (int32_t) value) {
|
||||||
tr_error("Invalid frame size");
|
tr_error("Invalid frame size");
|
||||||
}
|
}
|
||||||
|
@ -339,7 +312,7 @@ bool LoRaMac::message_integrity_check(const uint8_t *const payload,
|
||||||
mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 2] << 16);
|
mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 2] << 16);
|
||||||
mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 3] << 24);
|
mic_rx |= ((uint32_t) payload[size - LORAMAC_MFR_LEN + 3] << 24);
|
||||||
|
|
||||||
sequence_counter_prev = (uint16_t) *downlink_counter;
|
sequence_counter_prev = (uint16_t)*downlink_counter;
|
||||||
sequence_counter_diff = sequence_counter - sequence_counter_prev;
|
sequence_counter_diff = sequence_counter - sequence_counter_prev;
|
||||||
*downlink_counter += sequence_counter_diff;
|
*downlink_counter += sequence_counter_diff;
|
||||||
if (sequence_counter < sequence_counter_prev) {
|
if (sequence_counter < sequence_counter_prev) {
|
||||||
|
@ -444,7 +417,7 @@ void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload,
|
||||||
if (_lora_crypto.decrypt_payload(payload + payload_start_index,
|
if (_lora_crypto.decrypt_payload(payload + payload_start_index,
|
||||||
frame_len,
|
frame_len,
|
||||||
app_skey,
|
app_skey,
|
||||||
sizeof(_params.keys.app_skey)*8,
|
sizeof(_params.keys.app_skey) * 8,
|
||||||
address,
|
address,
|
||||||
DOWN_LINK,
|
DOWN_LINK,
|
||||||
downlink_counter,
|
downlink_counter,
|
||||||
|
@ -656,26 +629,53 @@ void LoRaMac::set_batterylevel_callback(mbed::Callback<uint8_t(void)> battery_le
|
||||||
_mac_commands.set_batterylevel_callback(battery_level);
|
_mac_commands.set_batterylevel_callback(battery_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoRaMac::on_radio_tx_done(lorawan_time_t timestamp)
|
||||||
|
{
|
||||||
|
if (_device_class == CLASS_C) {
|
||||||
|
// this will open a continuous RX2 window until time==RECV_DELAY1
|
||||||
|
open_rx2_window();
|
||||||
|
} else {
|
||||||
|
_lora_phy.put_radio_to_sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_params.is_rx_window_enabled == true) {
|
||||||
|
lorawan_time_t time_diff = _lora_time.get_current_time() - timestamp;
|
||||||
|
// start timer after which rx1_window will get opened
|
||||||
|
_lora_time.start(_params.timers.rx_window1_timer,
|
||||||
|
_params.rx_window1_delay - time_diff);
|
||||||
|
|
||||||
|
if (_device_class != CLASS_C) {
|
||||||
|
_lora_time.start(_params.timers.rx_window2_timer,
|
||||||
|
_params.rx_window2_delay - time_diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_params.is_node_ack_requested) {
|
||||||
|
_lora_time.start(_params.timers.ack_timeout_timer,
|
||||||
|
(_params.rx_window2_delay - time_diff) +
|
||||||
|
_lora_phy.get_ack_timeout());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||||
|
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
_params.last_channel_idx = _params.channel;
|
||||||
|
|
||||||
|
_lora_phy.set_last_tx_done(_params.channel, _is_nwk_joined, timestamp);
|
||||||
|
|
||||||
|
_params.timers.aggregated_last_tx_time = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
||||||
int16_t rssi, int8_t snr)
|
int16_t rssi, int8_t snr)
|
||||||
{
|
{
|
||||||
// stop the RX1 timer here if its the first RX slot.
|
if (_device_class == CLASS_C && !_continuous_rx2_window_open) {
|
||||||
// If the MIC will pass we will stop RX2 timer as well later.
|
open_rx2_window();
|
||||||
// If its RX2, stop RX2 timer.
|
} else {
|
||||||
if (_params.rx_slot == RX_SLOT_WIN_1) {
|
|
||||||
_lora_time.stop(_params.timers.rx_window1_timer);
|
_lora_time.stop(_params.timers.rx_window1_timer);
|
||||||
} else if (_params.rx_slot == RX_SLOT_WIN_2) {
|
_lora_phy.put_radio_to_sleep();
|
||||||
_lora_time.stop(_params.timers.rx_window2_timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_device_class == CLASS_C) {
|
|
||||||
if (!_continuous_rx2_window_open) {
|
|
||||||
open_rx2_window();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_lora_phy.put_radio_to_sleep();
|
|
||||||
}
|
|
||||||
|
|
||||||
loramac_mhdr_t mac_hdr;
|
loramac_mhdr_t mac_hdr;
|
||||||
uint8_t pos = 0;
|
uint8_t pos = 0;
|
||||||
mac_hdr.value = payload[pos++];
|
mac_hdr.value = payload[pos++];
|
||||||
|
@ -731,21 +731,23 @@ void LoRaMac::on_radio_tx_timeout(void)
|
||||||
post_process_mcps_req();
|
post_process_mcps_req();
|
||||||
}
|
}
|
||||||
|
|
||||||
rx_slot_t LoRaMac::on_radio_rx_timeout(bool is_timeout)
|
void LoRaMac::on_radio_rx_timeout(bool is_timeout)
|
||||||
{
|
{
|
||||||
if (_device_class != CLASS_C) {
|
if (_device_class == CLASS_C && !_continuous_rx2_window_open) {
|
||||||
|
open_rx2_window();
|
||||||
|
} else {
|
||||||
_lora_phy.put_radio_to_sleep();
|
_lora_phy.put_radio_to_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_params.rx_slot == RX_SLOT_WIN_1) {
|
if (_params.rx_slot == RX_SLOT_WIN_1) {
|
||||||
if (_params.is_node_ack_requested == true) {
|
if (_params.is_node_ack_requested == true) {
|
||||||
_mcps_confirmation.status = is_timeout ?
|
_mcps_confirmation.status = is_timeout ?
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT :
|
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT :
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
|
LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
|
||||||
}
|
}
|
||||||
_mlme_confirmation.status = is_timeout ?
|
_mlme_confirmation.status = is_timeout ?
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT :
|
LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT :
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
|
LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
|
||||||
|
|
||||||
if (_device_class != CLASS_C) {
|
if (_device_class != CLASS_C) {
|
||||||
if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) {
|
if (_lora_time.get_elapsed_time(_params.timers.aggregated_last_tx_time) >= _params.rx_window2_delay) {
|
||||||
|
@ -755,20 +757,14 @@ rx_slot_t LoRaMac::on_radio_rx_timeout(bool is_timeout)
|
||||||
} else {
|
} else {
|
||||||
if (_params.is_node_ack_requested == true) {
|
if (_params.is_node_ack_requested == true) {
|
||||||
_mcps_confirmation.status = is_timeout ?
|
_mcps_confirmation.status = is_timeout ?
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT :
|
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT :
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
|
LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mlme_confirmation.status = is_timeout ?
|
_mlme_confirmation.status = is_timeout ?
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT :
|
LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT :
|
||||||
LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
|
LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_device_class == CLASS_C) {
|
|
||||||
open_rx2_window();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _params.rx_slot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaMac::continue_joining_process()
|
bool LoRaMac::continue_joining_process()
|
||||||
|
@ -804,8 +800,8 @@ lorawan_status_t LoRaMac::send_join_request()
|
||||||
loramac_mhdr_t mac_hdr;
|
loramac_mhdr_t mac_hdr;
|
||||||
loramac_frame_ctrl_t fctrl;
|
loramac_frame_ctrl_t fctrl;
|
||||||
|
|
||||||
_params.sys_params.channel_data_rate = _lora_phy.get_alternate_DR(
|
_params.sys_params.channel_data_rate =
|
||||||
_params.join_request_trial_counter + 1);
|
_lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1);
|
||||||
|
|
||||||
mac_hdr.value = 0;
|
mac_hdr.value = 0;
|
||||||
mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ;
|
mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ;
|
||||||
|
@ -850,14 +846,13 @@ void LoRaMac::on_backoff_timer_expiry(void)
|
||||||
{
|
{
|
||||||
Lock lock(*this);
|
Lock lock(*this);
|
||||||
lorawan_status_t status = schedule_tx();
|
lorawan_status_t status = schedule_tx();
|
||||||
MBED_ASSERT(status==LORAWAN_STATUS_OK);
|
MBED_ASSERT(status == LORAWAN_STATUS_OK);
|
||||||
(void) status;
|
(void) status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::open_rx1_window(void)
|
void LoRaMac::open_rx1_window(void)
|
||||||
{
|
{
|
||||||
Lock lock(*this);
|
Lock lock(*this);
|
||||||
tr_debug("Opening RX1 Window");
|
|
||||||
_continuous_rx2_window_open = false;
|
_continuous_rx2_window_open = false;
|
||||||
_lora_time.stop(_params.timers.rx_window1_timer);
|
_lora_time.stop(_params.timers.rx_window1_timer);
|
||||||
_params.rx_slot = RX_SLOT_WIN_1;
|
_params.rx_slot = RX_SLOT_WIN_1;
|
||||||
|
@ -878,25 +873,26 @@ void LoRaMac::open_rx1_window(void)
|
||||||
|
|
||||||
_lora_phy.setup_rx_window(_params.rx_window1_config.is_rx_continuous,
|
_lora_phy.setup_rx_window(_params.rx_window1_config.is_rx_continuous,
|
||||||
_params.sys_params.max_rx_win_time);
|
_params.sys_params.max_rx_win_time);
|
||||||
|
|
||||||
|
tr_debug("Opening RX1 Window");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::open_rx2_window()
|
void LoRaMac::open_rx2_window()
|
||||||
{
|
{
|
||||||
Lock lock(*this);
|
Lock lock(*this);
|
||||||
tr_debug("Opening RX2 Window");
|
_continuous_rx2_window_open = true;
|
||||||
_lora_time.stop(_params.timers.rx_window2_timer);
|
_lora_time.stop(_params.timers.rx_window2_timer);
|
||||||
|
|
||||||
_params.rx_window2_config.channel = _params.channel;
|
_params.rx_window2_config.channel = _params.channel;
|
||||||
_params.rx_window2_config.frequency = _params.sys_params.rx2_channel.frequency;
|
_params.rx_window2_config.frequency = _params.sys_params.rx2_channel.frequency;
|
||||||
_params.rx_window2_config.dl_dwell_time = _params.sys_params.downlink_dwell_time;
|
_params.rx_window2_config.dl_dwell_time = _params.sys_params.downlink_dwell_time;
|
||||||
_params.rx_window2_config.is_repeater_supported = _params.is_repeater_supported;
|
_params.rx_window2_config.is_repeater_supported = _params.is_repeater_supported;
|
||||||
_params.rx_window2_config.rx_slot = RX_SLOT_WIN_2;
|
_params.rx_window2_config.rx_slot = _params.rx_window2_config.is_rx_continuous ?
|
||||||
|
RX_SLOT_WIN_CLASS_C : RX_SLOT_WIN_2;
|
||||||
|
|
||||||
if (get_device_class() == CLASS_C) {
|
if (get_device_class() == CLASS_C) {
|
||||||
_continuous_rx2_window_open = true;
|
|
||||||
_params.rx_window2_config.is_rx_continuous = true;
|
_params.rx_window2_config.is_rx_continuous = true;
|
||||||
} else {
|
} else {
|
||||||
_continuous_rx2_window_open = false;
|
|
||||||
_params.rx_window2_config.is_rx_continuous = false;
|
_params.rx_window2_config.is_rx_continuous = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,9 +903,10 @@ void LoRaMac::open_rx2_window()
|
||||||
_lora_phy.setup_rx_window(_params.rx_window2_config.is_rx_continuous,
|
_lora_phy.setup_rx_window(_params.rx_window2_config.is_rx_continuous,
|
||||||
_params.sys_params.max_rx_win_time);
|
_params.sys_params.max_rx_win_time);
|
||||||
|
|
||||||
_params.rx_slot = _params.rx_window2_config.is_rx_continuous ?
|
_params.rx_slot = _params.rx_window2_config.rx_slot;
|
||||||
RX_SLOT_WIN_CLASS_C : RX_SLOT_WIN_2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr_debug("Opening RX2 Window, Frequency = %u", _params.rx_window2_config.frequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::on_ack_timeout_timer_event(void)
|
void LoRaMac::on_ack_timeout_timer_event(void)
|
||||||
|
@ -953,7 +950,7 @@ void LoRaMac::on_ack_timeout_timer_event(void)
|
||||||
|
|
||||||
// now that is a critical failure
|
// now that is a critical failure
|
||||||
lorawan_status_t status = handle_retransmission();
|
lorawan_status_t status = handle_retransmission();
|
||||||
MBED_ASSERT(status==LORAWAN_STATUS_OK);
|
MBED_ASSERT(status == LORAWAN_STATUS_OK);
|
||||||
(void) status;
|
(void) status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1095,9 +1092,9 @@ lorawan_status_t LoRaMac::schedule_tx()
|
||||||
|
|
||||||
if (!_is_nwk_joined) {
|
if (!_is_nwk_joined) {
|
||||||
_params.rx_window1_delay = _params.sys_params.join_accept_delay1
|
_params.rx_window1_delay = _params.sys_params.join_accept_delay1
|
||||||
+ _params.rx_window1_config.window_offset;
|
+ _params.rx_window1_config.window_offset;
|
||||||
_params.rx_window2_delay = _params.sys_params.join_accept_delay2
|
_params.rx_window2_delay = _params.sys_params.join_accept_delay2
|
||||||
+ _params.rx_window2_config.window_offset;
|
+ _params.rx_window2_config.window_offset;
|
||||||
} else {
|
} else {
|
||||||
if (validate_payload_length(_params.tx_buffer_len,
|
if (validate_payload_length(_params.tx_buffer_len,
|
||||||
_params.sys_params.channel_data_rate,
|
_params.sys_params.channel_data_rate,
|
||||||
|
@ -1105,9 +1102,9 @@ lorawan_status_t LoRaMac::schedule_tx()
|
||||||
return LORAWAN_STATUS_LENGTH_ERROR;
|
return LORAWAN_STATUS_LENGTH_ERROR;
|
||||||
}
|
}
|
||||||
_params.rx_window1_delay = _params.sys_params.recv_delay1
|
_params.rx_window1_delay = _params.sys_params.recv_delay1
|
||||||
+ _params.rx_window1_config.window_offset;
|
+ _params.rx_window1_config.window_offset;
|
||||||
_params.rx_window2_delay = _params.sys_params.recv_delay2
|
_params.rx_window2_delay = _params.sys_params.recv_delay2
|
||||||
+ _params.rx_window2_config.window_offset;
|
+ _params.rx_window2_config.window_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the ack to the server here so that if the sending was cancelled
|
// handle the ack to the server here so that if the sending was cancelled
|
||||||
|
@ -1248,9 +1245,9 @@ int16_t LoRaMac::prepare_ongoing_tx(const uint8_t port,
|
||||||
|
|
||||||
// Handles unconfirmed messages
|
// Handles unconfirmed messages
|
||||||
if (flags & MSG_UNCONFIRMED_FLAG) {
|
if (flags & MSG_UNCONFIRMED_FLAG) {
|
||||||
_ongoing_tx_msg.type = MCPS_UNCONFIRMED;
|
_ongoing_tx_msg.type = MCPS_UNCONFIRMED;
|
||||||
_ongoing_tx_msg.fport = port;
|
_ongoing_tx_msg.fport = port;
|
||||||
_ongoing_tx_msg.nb_trials = 1;
|
_ongoing_tx_msg.nb_trials = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles confirmed messages
|
// Handles confirmed messages
|
||||||
|
@ -1346,8 +1343,6 @@ void LoRaMac::set_device_class(const device_class_t &device_class,
|
||||||
tr_debug("Changing device class to -> CLASS_C");
|
tr_debug("Changing device class to -> CLASS_C");
|
||||||
open_rx2_window();
|
open_rx2_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::setup_link_check_request()
|
void LoRaMac::setup_link_check_request()
|
||||||
|
@ -1542,7 +1537,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
||||||
|
|
||||||
_params.tx_buffer[pkt_header_len++] = _params.ul_frame_counter & 0xFF;
|
_params.tx_buffer[pkt_header_len++] = _params.ul_frame_counter & 0xFF;
|
||||||
_params.tx_buffer[pkt_header_len++] = (_params.ul_frame_counter >> 8)
|
_params.tx_buffer[pkt_header_len++] = (_params.ul_frame_counter >> 8)
|
||||||
& 0xFF;
|
& 0xFF;
|
||||||
|
|
||||||
_mac_commands.copy_repeat_commands_to_buffer();
|
_mac_commands.copy_repeat_commands_to_buffer();
|
||||||
|
|
||||||
|
@ -1556,8 +1551,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
||||||
// Update FCtrl field with new value of OptionsLength
|
// Update FCtrl field with new value of OptionsLength
|
||||||
_params.tx_buffer[0x05] = fctrl->value;
|
_params.tx_buffer[0x05] = fctrl->value;
|
||||||
|
|
||||||
const uint8_t *buffer =
|
const uint8_t *buffer = _mac_commands.get_mac_commands_buffer();
|
||||||
_mac_commands.get_mac_commands_buffer();
|
|
||||||
for (i = 0; i < mac_commands_len; i++) {
|
for (i = 0; i < mac_commands_len; i++) {
|
||||||
_params.tx_buffer[pkt_header_len++] = buffer[i];
|
_params.tx_buffer[pkt_header_len++] = buffer[i];
|
||||||
}
|
}
|
||||||
|
@ -1582,13 +1576,13 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
||||||
_params.tx_buffer[pkt_header_len++] = frame_port;
|
_params.tx_buffer[pkt_header_len++] = frame_port;
|
||||||
|
|
||||||
uint8_t *key = _params.keys.app_skey;
|
uint8_t *key = _params.keys.app_skey;
|
||||||
uint32_t key_length = sizeof(_params.keys.app_skey)*8;
|
uint32_t key_length = sizeof(_params.keys.app_skey) * 8;
|
||||||
if (frame_port == 0) {
|
if (frame_port == 0) {
|
||||||
_mac_commands.clear_command_buffer();
|
_mac_commands.clear_command_buffer();
|
||||||
key = _params.keys.nwk_skey;
|
key = _params.keys.nwk_skey;
|
||||||
key_length = sizeof(_params.keys.nwk_skey)*8;
|
key_length = sizeof(_params.keys.nwk_skey) * 8;
|
||||||
}
|
}
|
||||||
if (0 != _lora_crypto.encrypt_payload((uint8_t*) payload, _params.tx_buffer_len,
|
if (0 != _lora_crypto.encrypt_payload((uint8_t *) payload, _params.tx_buffer_len,
|
||||||
key, key_length,
|
key, key_length,
|
||||||
_params.dev_addr, UP_LINK,
|
_params.dev_addr, UP_LINK,
|
||||||
_params.ul_frame_counter,
|
_params.ul_frame_counter,
|
||||||
|
@ -1600,7 +1594,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
||||||
_params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len;
|
_params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len;
|
||||||
|
|
||||||
if (0 != _lora_crypto.compute_mic(_params.tx_buffer, _params.tx_buffer_len,
|
if (0 != _lora_crypto.compute_mic(_params.tx_buffer, _params.tx_buffer_len,
|
||||||
_params.keys.nwk_skey, sizeof(_params.keys.nwk_skey)*8,
|
_params.keys.nwk_skey, sizeof(_params.keys.nwk_skey) * 8,
|
||||||
_params.dev_addr,
|
_params.dev_addr,
|
||||||
UP_LINK, _params.ul_frame_counter, &mic)) {
|
UP_LINK, _params.ul_frame_counter, &mic)) {
|
||||||
status = LORAWAN_STATUS_CRYPTO_FAIL;
|
status = LORAWAN_STATUS_CRYPTO_FAIL;
|
||||||
|
@ -1775,7 +1769,7 @@ uint8_t LoRaMac::get_max_possible_tx_size(uint8_t size)
|
||||||
uint8_t max_possible_payload_size = 0;
|
uint8_t max_possible_payload_size = 0;
|
||||||
uint8_t current_payload_size = 0;
|
uint8_t current_payload_size = 0;
|
||||||
uint8_t fopt_len = _mac_commands.get_mac_cmd_length()
|
uint8_t fopt_len = _mac_commands.get_mac_cmd_length()
|
||||||
+ _mac_commands.get_repeat_commands_length();
|
+ _mac_commands.get_repeat_commands_length();
|
||||||
|
|
||||||
if (_params.sys_params.adr_on) {
|
if (_params.sys_params.adr_on) {
|
||||||
_lora_phy.get_next_ADR(false, _params.sys_params.channel_data_rate,
|
_lora_phy.get_next_ADR(false, _params.sys_params.channel_data_rate,
|
||||||
|
@ -1923,16 +1917,16 @@ lorawan_status_t LoRaMac::mlme_request(loramac_mlme_req_t *mlmeRequest)
|
||||||
|
|
||||||
if (MLME_TXCW == mlmeRequest->type) {
|
if (MLME_TXCW == mlmeRequest->type) {
|
||||||
set_tx_continuous_wave(_params.channel, _params.sys_params.channel_data_rate, _params.sys_params.channel_tx_power,
|
set_tx_continuous_wave(_params.channel, _params.sys_params.channel_data_rate, _params.sys_params.channel_tx_power,
|
||||||
_params.sys_params.max_eirp, _params.sys_params.antenna_gain, mlmeRequest->cw_tx_mode.timeout);
|
_params.sys_params.max_eirp, _params.sys_params.antenna_gain, mlmeRequest->cw_tx_mode.timeout);
|
||||||
_lora_time.start(_params.timers.mac_state_check_timer,
|
_lora_time.start(_params.timers.mac_state_check_timer,
|
||||||
MAC_STATE_CHECK_TIMEOUT);
|
MAC_STATE_CHECK_TIMEOUT);
|
||||||
|
|
||||||
_params.mac_state |= LORAMAC_TX_RUNNING;
|
_params.mac_state |= LORAMAC_TX_RUNNING;
|
||||||
status = LORAWAN_STATUS_OK;
|
status = LORAWAN_STATUS_OK;
|
||||||
} else if (MLME_TXCW_1 == mlmeRequest->type) {
|
} else if (MLME_TXCW_1 == mlmeRequest->type) {
|
||||||
set_tx_continuous_wave(0, 0, mlmeRequest->cw_tx_mode.power, 0, 0, mlmeRequest->cw_tx_mode.timeout);
|
set_tx_continuous_wave(0, 0, mlmeRequest->cw_tx_mode.power, 0, 0, mlmeRequest->cw_tx_mode.timeout);
|
||||||
_lora_time.start(_params.timers.mac_state_check_timer,
|
_lora_time.start(_params.timers.mac_state_check_timer,
|
||||||
MAC_STATE_CHECK_TIMEOUT);
|
MAC_STATE_CHECK_TIMEOUT);
|
||||||
|
|
||||||
_params.mac_state |= LORAMAC_TX_RUNNING;
|
_params.mac_state |= LORAMAC_TX_RUNNING;
|
||||||
status = LORAWAN_STATUS_OK;
|
status = LORAWAN_STATUS_OK;
|
||||||
|
@ -1946,7 +1940,7 @@ lorawan_status_t LoRaMac::mlme_request(loramac_mlme_req_t *mlmeRequest)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t LoRaMac::test_request( loramac_compliance_test_req_t *mcpsRequest )
|
lorawan_status_t LoRaMac::test_request(loramac_compliance_test_req_t *mcpsRequest)
|
||||||
{
|
{
|
||||||
if (_params.mac_state != LORAMAC_IDLE) {
|
if (_params.mac_state != LORAMAC_IDLE) {
|
||||||
return LORAWAN_STATUS_BUSY;
|
return LORAWAN_STATUS_BUSY;
|
||||||
|
@ -1981,7 +1975,7 @@ lorawan_status_t LoRaMac::test_request( loramac_compliance_test_req_t *mcpsReque
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return LORAWAN_STATUS_PARAMETER_INVALID;
|
return LORAWAN_STATUS_PARAMETER_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter fPorts
|
// Filter fPorts
|
||||||
|
@ -1999,7 +1993,7 @@ lorawan_status_t LoRaMac::test_request( loramac_compliance_test_req_t *mcpsReque
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t status = send(&machdr, mcpsRequest->fport, mcpsRequest->f_buffer,
|
lorawan_status_t status = send(&machdr, mcpsRequest->fport, mcpsRequest->f_buffer,
|
||||||
mcpsRequest->f_buffer_size);
|
mcpsRequest->f_buffer_size);
|
||||||
if (status == LORAWAN_STATUS_OK) {
|
if (status == LORAWAN_STATUS_OK) {
|
||||||
_mcps_confirmation.req_type = mcpsRequest->type;
|
_mcps_confirmation.req_type = mcpsRequest->type;
|
||||||
_params.flags.bits.mcps_req = 1;
|
_params.flags.bits.mcps_req = 1;
|
||||||
|
@ -2010,38 +2004,37 @@ lorawan_status_t LoRaMac::test_request( loramac_compliance_test_req_t *mcpsReque
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t LoRaMac::LoRaMacSetTxTimer( uint32_t TxDutyCycleTime )
|
lorawan_status_t LoRaMac::LoRaMacSetTxTimer(uint32_t TxDutyCycleTime)
|
||||||
{
|
{
|
||||||
_lora_time.start(tx_next_packet_timer, TxDutyCycleTime);
|
_lora_time.start(tx_next_packet_timer, TxDutyCycleTime);
|
||||||
return LORAWAN_STATUS_OK;
|
return LORAWAN_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t LoRaMac::LoRaMacStopTxTimer( )
|
lorawan_status_t LoRaMac::LoRaMacStopTxTimer()
|
||||||
{
|
{
|
||||||
_lora_time.stop(tx_next_packet_timer);
|
_lora_time.stop(tx_next_packet_timer);
|
||||||
return LORAWAN_STATUS_OK;
|
return LORAWAN_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::LoRaMacTestRxWindowsOn( bool enable )
|
void LoRaMac::LoRaMacTestRxWindowsOn(bool enable)
|
||||||
{
|
{
|
||||||
_params.is_rx_window_enabled = enable;
|
_params.is_rx_window_enabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::LoRaMacTestSetMic( uint16_t txPacketCounter )
|
void LoRaMac::LoRaMacTestSetMic(uint16_t txPacketCounter)
|
||||||
{
|
{
|
||||||
_params.ul_frame_counter = txPacketCounter;
|
_params.ul_frame_counter = txPacketCounter;
|
||||||
_params.is_ul_frame_counter_fixed = true;
|
_params.is_ul_frame_counter_fixed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::LoRaMacTestSetDutyCycleOn( bool enable )
|
void LoRaMac::LoRaMacTestSetDutyCycleOn(bool enable)
|
||||||
{
|
{
|
||||||
if(_lora_phy.verify_duty_cycle(enable) == true)
|
if (_lora_phy.verify_duty_cycle(enable) == true) {
|
||||||
{
|
|
||||||
_params.is_dutycycle_on = enable;
|
_params.is_dutycycle_on = enable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaMac::LoRaMacTestSetChannel( uint8_t channel )
|
void LoRaMac::LoRaMacTestSetChannel(uint8_t channel)
|
||||||
{
|
{
|
||||||
_params.channel = channel;
|
_params.channel = channel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,7 +386,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* MAC operations upon successful transmission
|
* MAC operations upon successful transmission
|
||||||
*/
|
*/
|
||||||
void on_radio_tx_done(void);
|
void on_radio_tx_done(lorawan_time_t timestamp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MAC operations upon reception
|
* MAC operations upon reception
|
||||||
|
@ -407,7 +407,7 @@ public:
|
||||||
*
|
*
|
||||||
* @return current RX slot
|
* @return current RX slot
|
||||||
*/
|
*/
|
||||||
rx_slot_t on_radio_rx_timeout(bool is_timeout);
|
void on_radio_rx_timeout(bool is_timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles retransmissions of Join requests if an Accept
|
* Handles retransmissions of Join requests if an Accept
|
||||||
|
@ -455,6 +455,16 @@ public:
|
||||||
*/
|
*/
|
||||||
lorawan_status_t clear_tx_pipe(void);
|
lorawan_status_t clear_tx_pipe(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current time
|
||||||
|
*/
|
||||||
|
lorawan_time_t get_current_time(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current receive slot
|
||||||
|
*/
|
||||||
|
rx_slot_t get_current_slot(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These locks trample through to the upper layers and make
|
* These locks trample through to the upper layers and make
|
||||||
* the stack thread safe.
|
* the stack thread safe.
|
||||||
|
@ -757,7 +767,7 @@ public: // Test interface
|
||||||
* \ref LORAWAN_STATUS_OK
|
* \ref LORAWAN_STATUS_OK
|
||||||
* \ref LORAWAN_STATUS_PARAMETER_INVALID
|
* \ref LORAWAN_STATUS_PARAMETER_INVALID
|
||||||
*/
|
*/
|
||||||
lorawan_status_t LoRaMacSetTxTimer( uint32_t NextTxTime );
|
lorawan_status_t LoRaMacSetTxTimer(uint32_t NextTxTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief LoRaMAC stop tx timer.
|
* \brief LoRaMAC stop tx timer.
|
||||||
|
@ -768,7 +778,7 @@ public: // Test interface
|
||||||
* \ref LORAWAN_STATUS_OK
|
* \ref LORAWAN_STATUS_OK
|
||||||
* \ref LORAWAN_STATUS_PARAMETER_INVALID
|
* \ref LORAWAN_STATUS_PARAMETER_INVALID
|
||||||
*/
|
*/
|
||||||
lorawan_status_t LoRaMacStopTxTimer( );
|
lorawan_status_t LoRaMacStopTxTimer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Enabled or disables the reception windows
|
* \brief Enabled or disables the reception windows
|
||||||
|
@ -778,7 +788,7 @@ public: // Test interface
|
||||||
*
|
*
|
||||||
* \param [in] enable - Enabled or disables the reception windows
|
* \param [in] enable - Enabled or disables the reception windows
|
||||||
*/
|
*/
|
||||||
void LoRaMacTestRxWindowsOn( bool enable );
|
void LoRaMacTestRxWindowsOn(bool enable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Enables the MIC field test
|
* \brief Enables the MIC field test
|
||||||
|
@ -788,7 +798,7 @@ public: // Test interface
|
||||||
*
|
*
|
||||||
* \param [in] txPacketCounter - Fixed Tx packet counter value
|
* \param [in] txPacketCounter - Fixed Tx packet counter value
|
||||||
*/
|
*/
|
||||||
void LoRaMacTestSetMic( uint16_t txPacketCounter );
|
void LoRaMacTestSetMic(uint16_t txPacketCounter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Enabled or disables the duty cycle
|
* \brief Enabled or disables the duty cycle
|
||||||
|
@ -798,7 +808,7 @@ public: // Test interface
|
||||||
*
|
*
|
||||||
* \param [in] enable - Enabled or disables the duty cycle
|
* \param [in] enable - Enabled or disables the duty cycle
|
||||||
*/
|
*/
|
||||||
void LoRaMacTestSetDutyCycleOn( bool enable );
|
void LoRaMacTestSetDutyCycleOn(bool enable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sets the channel index
|
* \brief Sets the channel index
|
||||||
|
@ -808,7 +818,7 @@ public: // Test interface
|
||||||
*
|
*
|
||||||
* \param [in] channel - Channel index
|
* \param [in] channel - Channel index
|
||||||
*/
|
*/
|
||||||
void LoRaMacTestSetChannel( uint8_t channel );
|
void LoRaMacTestSetChannel(uint8_t channel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -47,30 +47,35 @@ LoRaPHY::~LoRaPHY()
|
||||||
_radio = NULL;
|
_radio = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaPHY::mask_bit_test(const uint16_t *mask, unsigned bit) {
|
bool LoRaPHY::mask_bit_test(const uint16_t *mask, unsigned bit)
|
||||||
return mask[bit/16] & (1U << (bit % 16));
|
{
|
||||||
|
return mask[bit / 16] & (1U << (bit % 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::mask_bit_set(uint16_t *mask, unsigned bit) {
|
void LoRaPHY::mask_bit_set(uint16_t *mask, unsigned bit)
|
||||||
mask[bit/16] |= (1U << (bit % 16));
|
{
|
||||||
|
mask[bit / 16] |= (1U << (bit % 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::mask_bit_clear(uint16_t *mask, unsigned bit) {
|
void LoRaPHY::mask_bit_clear(uint16_t *mask, unsigned bit)
|
||||||
mask[bit/16] &= ~(1U << (bit % 16));
|
{
|
||||||
|
mask[bit / 16] &= ~(1U << (bit % 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::set_radio_instance(LoRaRadio& radio)
|
void LoRaPHY::set_radio_instance(LoRaRadio &radio)
|
||||||
{
|
{
|
||||||
_radio = &radio;
|
_radio = &radio;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::put_radio_to_sleep() {
|
void LoRaPHY::put_radio_to_sleep()
|
||||||
|
{
|
||||||
_radio->lock();
|
_radio->lock();
|
||||||
_radio->sleep();
|
_radio->sleep();
|
||||||
_radio->unlock();
|
_radio->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::put_radio_to_standby() {
|
void LoRaPHY::put_radio_to_standby()
|
||||||
|
{
|
||||||
_radio->lock();
|
_radio->lock();
|
||||||
_radio->standby();
|
_radio->standby();
|
||||||
_radio->unlock();
|
_radio->unlock();
|
||||||
|
@ -100,7 +105,7 @@ uint32_t LoRaPHY::get_radio_rng()
|
||||||
uint32_t rand;
|
uint32_t rand;
|
||||||
|
|
||||||
_radio->lock();
|
_radio->lock();
|
||||||
rand =_radio->random();
|
rand = _radio->random();
|
||||||
_radio->unlock();
|
_radio->unlock();
|
||||||
|
|
||||||
return rand;
|
return rand;
|
||||||
|
@ -113,7 +118,7 @@ void LoRaPHY::handle_send(uint8_t *buf, uint8_t size)
|
||||||
_radio->unlock();
|
_radio->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LoRaPHY::request_new_channel(int8_t channel_id, channel_params_t* new_channel)
|
uint8_t LoRaPHY::request_new_channel(int8_t channel_id, channel_params_t *new_channel)
|
||||||
{
|
{
|
||||||
if (!phy_params.custom_channelplans_supported) {
|
if (!phy_params.custom_channelplans_supported) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -129,27 +134,22 @@ uint8_t LoRaPHY::request_new_channel(int8_t channel_id, channel_params_t* new_ch
|
||||||
} else {
|
} else {
|
||||||
new_channel->band = lookup_band_for_frequency(new_channel->frequency);
|
new_channel->band = lookup_band_for_frequency(new_channel->frequency);
|
||||||
switch (add_channel(new_channel, channel_id)) {
|
switch (add_channel(new_channel, channel_id)) {
|
||||||
case LORAWAN_STATUS_OK:
|
case LORAWAN_STATUS_OK: {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LORAWAN_STATUS_FREQUENCY_INVALID:
|
case LORAWAN_STATUS_FREQUENCY_INVALID: {
|
||||||
{
|
|
||||||
status &= 0xFE;
|
status &= 0xFE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LORAWAN_STATUS_DATARATE_INVALID:
|
case LORAWAN_STATUS_DATARATE_INVALID: {
|
||||||
{
|
|
||||||
status &= 0xFD;
|
status &= 0xFD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LORAWAN_STATUS_FREQ_AND_DR_INVALID:
|
case LORAWAN_STATUS_FREQ_AND_DR_INVALID: {
|
||||||
{
|
|
||||||
status &= 0xFC;
|
status &= 0xFC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
{
|
|
||||||
status &= 0xFC;
|
status &= 0xFC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -164,9 +164,9 @@ int32_t LoRaPHY::get_random(int32_t min, int32_t max)
|
||||||
return (int32_t) rand() % (max - min + 1) + min;
|
return (int32_t) rand() % (max - min + 1) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaPHY::verify_channel_DR(uint8_t nb_channels, uint16_t* channel_mask,
|
bool LoRaPHY::verify_channel_DR(uint8_t nb_channels, uint16_t *channel_mask,
|
||||||
int8_t dr, int8_t min_dr, int8_t max_dr,
|
int8_t dr, int8_t min_dr, int8_t max_dr,
|
||||||
channel_params_t* channels)
|
channel_params_t *channels)
|
||||||
{
|
{
|
||||||
if (val_in_range(dr, min_dr, max_dr) == 0) {
|
if (val_in_range(dr, min_dr, max_dr) == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -186,7 +186,7 @@ bool LoRaPHY::verify_channel_DR(uint8_t nb_channels, uint16_t* channel_mask,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaPHY::val_in_range( int8_t value, int8_t min, int8_t max )
|
bool LoRaPHY::val_in_range(int8_t value, int8_t min, int8_t max)
|
||||||
{
|
{
|
||||||
if ((value >= min) && (value <= max)) {
|
if ((value >= min) && (value <= max)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -195,7 +195,7 @@ bool LoRaPHY::val_in_range( int8_t value, int8_t min, int8_t max )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaPHY::disable_channel(uint16_t* channel_mask, uint8_t id,
|
bool LoRaPHY::disable_channel(uint16_t *channel_mask, uint8_t id,
|
||||||
uint8_t max_channels_num)
|
uint8_t max_channels_num)
|
||||||
{
|
{
|
||||||
uint8_t index = id / 16;
|
uint8_t index = id / 16;
|
||||||
|
@ -214,7 +214,7 @@ uint8_t LoRaPHY::count_bits(uint16_t mask, uint8_t nbBits)
|
||||||
{
|
{
|
||||||
uint8_t nbActiveBits = 0;
|
uint8_t nbActiveBits = 0;
|
||||||
|
|
||||||
for(uint8_t j = 0; j < nbBits; j++) {
|
for (uint8_t j = 0; j < nbBits; j++) {
|
||||||
if (mask_bit_test(&mask, j)) {
|
if (mask_bit_test(&mask, j)) {
|
||||||
nbActiveBits++;
|
nbActiveBits++;
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ uint8_t LoRaPHY::count_bits(uint16_t mask, uint8_t nbBits)
|
||||||
return nbActiveBits;
|
return nbActiveBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LoRaPHY::num_active_channels(uint16_t* channel_mask, uint8_t start_idx,
|
uint8_t LoRaPHY::num_active_channels(uint16_t *channel_mask, uint8_t start_idx,
|
||||||
uint8_t stop_idx)
|
uint8_t stop_idx)
|
||||||
{
|
{
|
||||||
uint8_t nb_channels = 0;
|
uint8_t nb_channels = 0;
|
||||||
|
@ -239,10 +239,10 @@ uint8_t LoRaPHY::num_active_channels(uint16_t* channel_mask, uint8_t start_idx,
|
||||||
return nb_channels;
|
return nb_channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::copy_channel_mask(uint16_t* dest_mask, uint16_t* src_mask, uint8_t len)
|
void LoRaPHY::copy_channel_mask(uint16_t *dest_mask, uint16_t *src_mask, uint8_t len)
|
||||||
{
|
{
|
||||||
if ((dest_mask != NULL) && (src_mask != NULL)) {
|
if ((dest_mask != NULL) && (src_mask != NULL)) {
|
||||||
for( uint8_t i = 0; i < len; i++ ) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
dest_mask[i] = src_mask[i];
|
dest_mask[i] = src_mask[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,37 +264,37 @@ void LoRaPHY::set_last_tx_done(uint8_t channel, bool joined, lorawan_time_t last
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_time_t LoRaPHY::update_band_timeoff(bool joined, bool duty_cycle,
|
lorawan_time_t LoRaPHY::update_band_timeoff(bool joined, bool duty_cycle,
|
||||||
band_t* bands, uint8_t nb_bands)
|
band_t *bands, uint8_t nb_bands)
|
||||||
{
|
{
|
||||||
lorawan_time_t next_tx_delay = (lorawan_time_t) (-1);
|
lorawan_time_t next_tx_delay = (lorawan_time_t)(-1);
|
||||||
|
|
||||||
// Update bands Time OFF
|
// Update bands Time OFF
|
||||||
for (uint8_t i = 0; i < nb_bands; i++) {
|
for (uint8_t i = 0; i < nb_bands; i++) {
|
||||||
|
|
||||||
if (joined == false) {
|
if (joined == false) {
|
||||||
uint32_t txDoneTime = MAX(_lora_time.get_elapsed_time(bands[i].last_join_tx_time),
|
uint32_t txDoneTime = MAX(_lora_time.get_elapsed_time(bands[i].last_join_tx_time),
|
||||||
(duty_cycle == true) ?
|
(duty_cycle == true) ?
|
||||||
_lora_time.get_elapsed_time(bands[i].last_tx_time) : 0);
|
_lora_time.get_elapsed_time(bands[i].last_tx_time) : 0);
|
||||||
|
|
||||||
if (bands[i].off_time <= txDoneTime) {
|
if (bands[i].off_time <= txDoneTime) {
|
||||||
bands[i].off_time = 0;
|
bands[i].off_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bands[i].off_time != 0) {
|
if (bands[i].off_time != 0) {
|
||||||
next_tx_delay = MIN( bands[i].off_time - txDoneTime, next_tx_delay );
|
next_tx_delay = MIN(bands[i].off_time - txDoneTime, next_tx_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// if network has been joined
|
// if network has been joined
|
||||||
if (duty_cycle == true) {
|
if (duty_cycle == true) {
|
||||||
|
|
||||||
if( bands[i].off_time <= _lora_time.get_elapsed_time(bands[i].last_tx_time)) {
|
if (bands[i].off_time <= _lora_time.get_elapsed_time(bands[i].last_tx_time)) {
|
||||||
bands[i].off_time = 0;
|
bands[i].off_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bands[i].off_time != 0 ) {
|
if (bands[i].off_time != 0) {
|
||||||
next_tx_delay = MIN(bands[i].off_time - _lora_time.get_elapsed_time(bands[i].last_tx_time),
|
next_tx_delay = MIN(bands[i].off_time - _lora_time.get_elapsed_time(bands[i].last_tx_time),
|
||||||
next_tx_delay);
|
next_tx_delay);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if duty cycle is not on
|
// if duty cycle is not on
|
||||||
|
@ -307,7 +307,8 @@ lorawan_time_t LoRaPHY::update_band_timeoff(bool joined, bool duty_cycle,
|
||||||
return next_tx_delay;
|
return next_tx_delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LoRaPHY::parse_link_ADR_req(const uint8_t* payload, link_adr_params_t* params)
|
uint8_t LoRaPHY::parse_link_ADR_req(const uint8_t *payload,
|
||||||
|
link_adr_params_t *params)
|
||||||
{
|
{
|
||||||
uint8_t ret_index = 0;
|
uint8_t ret_index = 0;
|
||||||
|
|
||||||
|
@ -324,7 +325,7 @@ uint8_t LoRaPHY::parse_link_ADR_req(const uint8_t* payload, link_adr_params_t* p
|
||||||
|
|
||||||
// Parse ChMaskCtrl and nbRep
|
// Parse ChMaskCtrl and nbRep
|
||||||
params->nb_rep = payload[4];
|
params->nb_rep = payload[4];
|
||||||
params->ch_mask_ctrl = ( params->nb_rep >> 4 ) & 0x07;
|
params->ch_mask_ctrl = (params->nb_rep >> 4) & 0x07;
|
||||||
params->nb_rep &= 0x0F;
|
params->nb_rep &= 0x0F;
|
||||||
|
|
||||||
// LinkAdrReq has 4 bytes length + 1 byte CMD
|
// LinkAdrReq has 4 bytes length + 1 byte CMD
|
||||||
|
@ -334,8 +335,8 @@ uint8_t LoRaPHY::parse_link_ADR_req(const uint8_t* payload, link_adr_params_t* p
|
||||||
return ret_index;
|
return ret_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t* verify_params,
|
uint8_t LoRaPHY::verify_link_ADR_req(verify_adr_params_t *verify_params,
|
||||||
int8_t* dr, int8_t* tx_pow, uint8_t* nb_rep)
|
int8_t *dr, int8_t *tx_pow, uint8_t *nb_rep)
|
||||||
{
|
{
|
||||||
uint8_t status = verify_params->status;
|
uint8_t status = verify_params->status;
|
||||||
int8_t datarate = verify_params->datarate;
|
int8_t datarate = verify_params->datarate;
|
||||||
|
@ -404,10 +405,10 @@ double LoRaPHY::compute_symb_timeout_fsk(uint8_t phy_dr)
|
||||||
|
|
||||||
void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb,
|
void LoRaPHY::get_rx_window_params(double t_symb, uint8_t min_rx_symb,
|
||||||
uint32_t rx_error, uint32_t wakeup_time,
|
uint32_t rx_error, uint32_t wakeup_time,
|
||||||
uint32_t* window_timeout, int32_t* window_offset)
|
uint32_t *window_timeout, int32_t *window_offset)
|
||||||
{
|
{
|
||||||
// Computed number of symbols
|
// 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_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);
|
*window_offset = (int32_t) ceil((4.0 * t_symb) - ((*window_timeout * t_symb) / 2.0 ) - wakeup_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,7 +431,7 @@ int8_t LoRaPHY::get_next_lower_dr(int8_t dr, int8_t min_dr)
|
||||||
if (next_lower_dr != min_dr) {
|
if (next_lower_dr != min_dr) {
|
||||||
next_lower_dr -= 1;
|
next_lower_dr -= 1;
|
||||||
}
|
}
|
||||||
} while((next_lower_dr != min_dr) && !is_datarate_supported(next_lower_dr));
|
} while ((next_lower_dr != min_dr) && !is_datarate_supported(next_lower_dr));
|
||||||
|
|
||||||
return next_lower_dr;
|
return next_lower_dr;
|
||||||
}
|
}
|
||||||
|
@ -439,7 +440,7 @@ uint8_t LoRaPHY::get_bandwidth(uint8_t dr)
|
||||||
{
|
{
|
||||||
uint32_t *bandwidths = (uint32_t *) phy_params.bandwidths.table;
|
uint32_t *bandwidths = (uint32_t *) phy_params.bandwidths.table;
|
||||||
|
|
||||||
switch(bandwidths[dr]) {
|
switch (bandwidths[dr]) {
|
||||||
default:
|
default:
|
||||||
case 125000:
|
case 125000:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -462,7 +463,7 @@ uint8_t LoRaPHY::enabled_channel_count(bool joined, uint8_t datarate,
|
||||||
if (mask_bit_test(channel_mask, i)) {
|
if (mask_bit_test(channel_mask, i)) {
|
||||||
|
|
||||||
if (val_in_range(datarate, phy_params.channels.channel_list[i].dr_range.fields.min,
|
if (val_in_range(datarate, phy_params.channels.channel_list[i].dr_range.fields.min,
|
||||||
phy_params.channels.channel_list[i].dr_range.fields.max ) == 0) {
|
phy_params.channels.channel_list[i].dr_range.fields.max) == 0) {
|
||||||
// data rate range invalid for this channel
|
// data rate range invalid for this channel
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -602,7 +603,7 @@ uint8_t LoRaPHY::get_default_rx2_datarate()
|
||||||
return phy_params.rx_window2_datarate;
|
return phy_params.rx_window2_datarate;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t* LoRaPHY::get_channel_mask(bool get_default)
|
uint16_t *LoRaPHY::get_channel_mask(bool get_default)
|
||||||
{
|
{
|
||||||
if (get_default) {
|
if (get_default) {
|
||||||
return phy_params.channels.default_mask;
|
return phy_params.channels.default_mask;
|
||||||
|
@ -615,7 +616,7 @@ uint8_t LoRaPHY::get_max_nb_channels()
|
||||||
return phy_params.max_channel_cnt;
|
return phy_params.max_channel_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel_params_t* LoRaPHY::get_phy_channels()
|
channel_params_t *LoRaPHY::get_phy_channels()
|
||||||
{
|
{
|
||||||
return phy_params.channels.channel_list;
|
return phy_params.channels.channel_list;
|
||||||
}
|
}
|
||||||
|
@ -628,7 +629,7 @@ bool LoRaPHY::is_custom_channel_plan_supported()
|
||||||
void LoRaPHY::restore_default_channels()
|
void LoRaPHY::restore_default_channels()
|
||||||
{
|
{
|
||||||
// Restore channels default mask
|
// Restore channels default mask
|
||||||
for (uint8_t i=0; i < phy_params.channels.mask_size; i++) {
|
for (uint8_t i = 0; i < phy_params.channels.mask_size; i++) {
|
||||||
phy_params.channels.mask[i] |= phy_params.channels.default_mask[i];
|
phy_params.channels.mask[i] |= phy_params.channels.default_mask[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -644,7 +645,7 @@ bool LoRaPHY::verify_rx_datarate(uint8_t datarate)
|
||||||
} else {
|
} else {
|
||||||
return val_in_range(datarate,
|
return val_in_range(datarate,
|
||||||
phy_params.dwell_limit_datarate,
|
phy_params.dwell_limit_datarate,
|
||||||
phy_params.max_rx_datarate );
|
phy_params.max_rx_datarate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -690,7 +691,7 @@ bool LoRaPHY::verify_nb_join_trials(uint8_t nb_join_trials)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::apply_cf_list(const uint8_t* payload, uint8_t size)
|
void LoRaPHY::apply_cf_list(const uint8_t *payload, uint8_t size)
|
||||||
{
|
{
|
||||||
// if the underlying PHY doesn't support CF-List, ignore the request
|
// if the underlying PHY doesn't support CF-List, ignore the request
|
||||||
if (!phy_params.cflist_supported) {
|
if (!phy_params.cflist_supported) {
|
||||||
|
@ -700,8 +701,8 @@ void LoRaPHY::apply_cf_list(const uint8_t* payload, uint8_t size)
|
||||||
channel_params_t new_channel;
|
channel_params_t new_channel;
|
||||||
|
|
||||||
// Setup default datarate range
|
// Setup default datarate range
|
||||||
new_channel.dr_range.value = (phy_params.default_max_datarate << 4)
|
new_channel.dr_range.value = (phy_params.default_max_datarate << 4) |
|
||||||
| phy_params.default_datarate;
|
phy_params.default_datarate;
|
||||||
|
|
||||||
// Size of the optional CF list
|
// Size of the optional CF list
|
||||||
if (size != 16) {
|
if (size != 16) {
|
||||||
|
@ -716,7 +717,7 @@ void LoRaPHY::apply_cf_list(const uint8_t* payload, uint8_t size)
|
||||||
// should override this function in the implementation of that particular
|
// should override this function in the implementation of that particular
|
||||||
// PHY.
|
// PHY.
|
||||||
for (uint8_t i = 0, channel_id = phy_params.default_channel_cnt;
|
for (uint8_t i = 0, channel_id = phy_params.default_channel_cnt;
|
||||||
channel_id < phy_params.max_channel_cnt; i+=3, channel_id++) {
|
channel_id < phy_params.max_channel_cnt; i += 3, channel_id++) {
|
||||||
if (channel_id < (phy_params.cflist_channel_cnt + phy_params.default_channel_cnt)) {
|
if (channel_id < (phy_params.cflist_channel_cnt + phy_params.default_channel_cnt)) {
|
||||||
// Channel frequency
|
// Channel frequency
|
||||||
new_channel.frequency = (uint32_t) payload[i];
|
new_channel.frequency = (uint32_t) payload[i];
|
||||||
|
@ -745,8 +746,8 @@ void LoRaPHY::apply_cf_list(const uint8_t* payload, uint8_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LoRaPHY::get_next_ADR(bool restore_channel_mask, int8_t& dr_out,
|
bool LoRaPHY::get_next_ADR(bool restore_channel_mask, int8_t &dr_out,
|
||||||
int8_t& tx_power_out, uint32_t& adr_ack_cnt)
|
int8_t &tx_power_out, uint32_t &adr_ack_cnt)
|
||||||
{
|
{
|
||||||
bool set_adr_ack_bit = false;
|
bool set_adr_ack_bit = false;
|
||||||
|
|
||||||
|
@ -791,7 +792,7 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols,
|
||||||
double t_symbol = 0.0;
|
double t_symbol = 0.0;
|
||||||
|
|
||||||
// Get the datarate, perform a boundary check
|
// Get the datarate, perform a boundary check
|
||||||
rx_conf_params->datarate = MIN( datarate, phy_params.max_rx_datarate);
|
rx_conf_params->datarate = MIN(datarate, phy_params.max_rx_datarate);
|
||||||
|
|
||||||
rx_conf_params->bandwidth = get_bandwidth(rx_conf_params->datarate);
|
rx_conf_params->bandwidth = get_bandwidth(rx_conf_params->datarate);
|
||||||
|
|
||||||
|
@ -801,14 +802,14 @@ void LoRaPHY::compute_rx_win_params(int8_t datarate, uint8_t min_rx_symbols,
|
||||||
} else {
|
} else {
|
||||||
// LoRa
|
// LoRa
|
||||||
t_symbol = compute_symb_timeout_lora(((uint8_t *)phy_params.datarates.table)[rx_conf_params->datarate],
|
t_symbol = compute_symb_timeout_lora(((uint8_t *)phy_params.datarates.table)[rx_conf_params->datarate],
|
||||||
((uint32_t *)phy_params.bandwidths.table)[rx_conf_params->datarate]);
|
((uint32_t *)phy_params.bandwidths.table)[rx_conf_params->datarate]);
|
||||||
}
|
}
|
||||||
|
|
||||||
get_rx_window_params(t_symbol, min_rx_symbols, rx_error, RADIO_WAKEUP_TIME,
|
get_rx_window_params(t_symbol, min_rx_symbols, rx_error, RADIO_WAKEUP_TIME,
|
||||||
&rx_conf_params->window_timeout, &rx_conf_params->window_offset);
|
&rx_conf_params->window_timeout, &rx_conf_params->window_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaPHY::rx_config(rx_config_params_t* rx_conf)
|
bool LoRaPHY::rx_config(rx_config_params_t *rx_conf)
|
||||||
{
|
{
|
||||||
radio_modems_t modem;
|
radio_modems_t modem;
|
||||||
uint8_t dr = rx_conf->datarate;
|
uint8_t dr = rx_conf->datarate;
|
||||||
|
@ -871,8 +872,8 @@ bool LoRaPHY::rx_config(rx_config_params_t* rx_conf)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaPHY::tx_config(tx_config_params_t* tx_conf, int8_t* tx_power,
|
bool LoRaPHY::tx_config(tx_config_params_t *tx_conf, int8_t *tx_power,
|
||||||
lorawan_time_t* tx_toa)
|
lorawan_time_t *tx_toa)
|
||||||
{
|
{
|
||||||
radio_modems_t modem;
|
radio_modems_t modem;
|
||||||
int8_t phy_dr = ((uint8_t *)phy_params.datarates.table)[tx_conf->datarate];
|
int8_t phy_dr = ((uint8_t *)phy_params.datarates.table)[tx_conf->datarate];
|
||||||
|
@ -895,7 +896,7 @@ bool LoRaPHY::tx_config(tx_config_params_t* tx_conf, int8_t* tx_power,
|
||||||
// Setup the radio frequency
|
// Setup the radio frequency
|
||||||
_radio->set_channel(list[tx_conf->channel].frequency);
|
_radio->set_channel(list[tx_conf->channel].frequency);
|
||||||
|
|
||||||
if( tx_conf->datarate == phy_params.max_tx_datarate ) {
|
if (tx_conf->datarate == phy_params.max_tx_datarate) {
|
||||||
// High Speed FSK channel
|
// High Speed FSK channel
|
||||||
modem = MODEM_FSK;
|
modem = MODEM_FSK;
|
||||||
_radio->set_tx_config(modem, phy_tx_power, 25000, bandwidth,
|
_radio->set_tx_config(modem, phy_tx_power, 25000, bandwidth,
|
||||||
|
@ -904,11 +905,11 @@ bool LoRaPHY::tx_config(tx_config_params_t* tx_conf, int8_t* tx_power,
|
||||||
} else {
|
} else {
|
||||||
modem = MODEM_LORA;
|
modem = MODEM_LORA;
|
||||||
_radio->set_tx_config(modem, phy_tx_power, 0, bandwidth, phy_dr, 1, 8,
|
_radio->set_tx_config(modem, phy_tx_power, 0, bandwidth, phy_dr, 1, 8,
|
||||||
false, true, 0, 0, false, 3000 );
|
false, true, 0, 0, false, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup maximum payload lenght of the radio driver
|
// Setup maximum payload lenght of the radio driver
|
||||||
_radio->set_max_payload_length( modem, tx_conf->pkt_len);
|
_radio->set_max_payload_length(modem, tx_conf->pkt_len);
|
||||||
// Get the time-on-air of the next tx frame
|
// Get the time-on-air of the next tx frame
|
||||||
*tx_toa = _radio->time_on_air(modem, tx_conf->pkt_len);
|
*tx_toa = _radio->time_on_air(modem, tx_conf->pkt_len);
|
||||||
|
|
||||||
|
@ -919,9 +920,9 @@ bool LoRaPHY::tx_config(tx_config_params_t* tx_conf, int8_t* tx_power,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LoRaPHY::link_ADR_request(adr_req_params_t* link_adr_req,
|
uint8_t LoRaPHY::link_ADR_request(adr_req_params_t *link_adr_req,
|
||||||
int8_t* dr_out, int8_t* tx_power_out,
|
int8_t *dr_out, int8_t *tx_power_out,
|
||||||
uint8_t* nb_rep_out, uint8_t* nb_bytes_processed)
|
uint8_t *nb_rep_out, uint8_t *nb_bytes_processed)
|
||||||
{
|
{
|
||||||
uint8_t status = 0x07;
|
uint8_t status = 0x07;
|
||||||
link_adr_params_t adr_settings;
|
link_adr_params_t adr_settings;
|
||||||
|
@ -939,7 +940,7 @@ uint8_t LoRaPHY::link_ADR_request(adr_req_params_t* link_adr_req,
|
||||||
while (bytes_processed < link_adr_req->payload_size) {
|
while (bytes_processed < link_adr_req->payload_size) {
|
||||||
// Get ADR request parameters
|
// Get ADR request parameters
|
||||||
next_index = parse_link_ADR_req(&(link_adr_req->payload[bytes_processed]),
|
next_index = parse_link_ADR_req(&(link_adr_req->payload[bytes_processed]),
|
||||||
&adr_settings);
|
&adr_settings);
|
||||||
|
|
||||||
if (next_index == 0) {
|
if (next_index == 0) {
|
||||||
break; // break loop, since no more request has been found
|
break; // break loop, since no more request has been found
|
||||||
|
@ -960,8 +961,7 @@ uint8_t LoRaPHY::link_ADR_request(adr_req_params_t* link_adr_req,
|
||||||
}
|
}
|
||||||
|
|
||||||
// channel mask applies to first 16 channels
|
// channel mask applies to first 16 channels
|
||||||
if (adr_settings.ch_mask_ctrl == 0 ||
|
if (adr_settings.ch_mask_ctrl == 0 || adr_settings.ch_mask_ctrl == 6) {
|
||||||
adr_settings.ch_mask_ctrl == 6) {
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) {
|
for (uint8_t i = 0; i < phy_params.max_channel_cnt; i++) {
|
||||||
|
|
||||||
|
@ -977,7 +977,7 @@ uint8_t LoRaPHY::link_ADR_request(adr_req_params_t* link_adr_req,
|
||||||
// if channel mask control is 0, we test the bits and
|
// if channel mask control is 0, we test the bits and
|
||||||
// frequencies and change the status if we find a discrepancy
|
// frequencies and change the status if we find a discrepancy
|
||||||
if ((mask_bit_test(temp_channel_mask, i)) &&
|
if ((mask_bit_test(temp_channel_mask, i)) &&
|
||||||
(phy_params.channels.channel_list[i].frequency == 0)) {
|
(phy_params.channels.channel_list[i].frequency == 0)) {
|
||||||
// Trying to enable an undefined channel
|
// Trying to enable an undefined channel
|
||||||
status &= 0xFE; // Channel mask KO
|
status &= 0xFE; // Channel mask KO
|
||||||
}
|
}
|
||||||
|
@ -1030,10 +1030,14 @@ uint8_t LoRaPHY::link_ADR_request(adr_req_params_t* link_adr_req,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LoRaPHY::accept_rx_param_setup_req(rx_param_setup_req_t* params)
|
uint8_t LoRaPHY::accept_rx_param_setup_req(rx_param_setup_req_t *params)
|
||||||
{
|
{
|
||||||
uint8_t status = 0x07;
|
uint8_t status = 0x07;
|
||||||
|
|
||||||
|
if (lookup_band_for_frequency(params->frequency) < 0) {
|
||||||
|
status &= 0xFE;
|
||||||
|
}
|
||||||
|
|
||||||
// Verify radio frequency
|
// Verify radio frequency
|
||||||
if (_radio->check_rf_frequency(params->frequency) == false) {
|
if (_radio->check_rf_frequency(params->frequency) == false) {
|
||||||
status &= 0xFE; // Channel frequency KO
|
status &= 0xFE; // Channel frequency KO
|
||||||
|
@ -1069,7 +1073,7 @@ int LoRaPHY::lookup_band_for_frequency(uint32_t freq) const
|
||||||
// check all sub bands (if there are sub-bands) to check if the given
|
// check all sub bands (if there are sub-bands) to check if the given
|
||||||
// frequency falls into any of the frequency ranges
|
// frequency falls into any of the frequency ranges
|
||||||
|
|
||||||
for (int band=0; band<phy_params.bands.size; band++) {
|
for (int band = 0; band < phy_params.bands.size; band++) {
|
||||||
if (verify_frequency_for_band(freq, band)) {
|
if (verify_frequency_for_band(freq, band)) {
|
||||||
return band;
|
return band;
|
||||||
}
|
}
|
||||||
|
@ -1194,8 +1198,7 @@ void LoRaPHY::calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_
|
||||||
|
|
||||||
// No back-off if the last frame was not a join request and when the
|
// No back-off if the last frame was not a join request and when the
|
||||||
// duty cycle is not enabled
|
// duty cycle is not enabled
|
||||||
if (dc_enabled == false &&
|
if (dc_enabled == false && last_tx_was_join_req == false) {
|
||||||
last_tx_was_join_req == false) {
|
|
||||||
band_table[band_idx].off_time = 0;
|
band_table[band_idx].off_time = 0;
|
||||||
} else {
|
} else {
|
||||||
// Apply band time-off.
|
// Apply band time-off.
|
||||||
|
@ -1203,9 +1206,9 @@ void LoRaPHY::calculate_backoff(bool joined, bool last_tx_was_join_req, bool dc_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t* params,
|
lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t *params,
|
||||||
uint8_t* channel, lorawan_time_t* time,
|
uint8_t *channel, lorawan_time_t *time,
|
||||||
lorawan_time_t* aggregate_timeoff)
|
lorawan_time_t *aggregate_timeoff)
|
||||||
{
|
{
|
||||||
uint8_t channel_count = 0;
|
uint8_t channel_count = 0;
|
||||||
uint8_t delay_tx = 0;
|
uint8_t delay_tx = 0;
|
||||||
|
@ -1217,7 +1220,7 @@ lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t* params,
|
||||||
// memory we chose to use a magic number of 16
|
// memory we chose to use a magic number of 16
|
||||||
uint8_t enabled_channels[16];
|
uint8_t enabled_channels[16];
|
||||||
|
|
||||||
memset(enabled_channels, 0xFF, sizeof(uint8_t)*16);
|
memset(enabled_channels, 0xFF, sizeof(uint8_t) * 16);
|
||||||
|
|
||||||
lorawan_time_t next_tx_delay = 0;
|
lorawan_time_t next_tx_delay = 0;
|
||||||
band_t *band_table = (band_t *) phy_params.bands.table;
|
band_t *band_table = (band_t *) phy_params.bands.table;
|
||||||
|
@ -1238,17 +1241,17 @@ lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t* params,
|
||||||
|
|
||||||
// Update bands Time OFF
|
// Update bands Time OFF
|
||||||
next_tx_delay = update_band_timeoff(params->joined,
|
next_tx_delay = update_band_timeoff(params->joined,
|
||||||
params->dc_enabled,
|
params->dc_enabled,
|
||||||
band_table, phy_params.bands.size);
|
band_table, phy_params.bands.size);
|
||||||
|
|
||||||
// Search how many channels are enabled
|
// Search how many channels are enabled
|
||||||
channel_count = enabled_channel_count(params->joined, params->current_datarate,
|
channel_count = enabled_channel_count(params->joined, params->current_datarate,
|
||||||
phy_params.channels.mask,
|
phy_params.channels.mask,
|
||||||
enabled_channels, &delay_tx);
|
enabled_channels, &delay_tx);
|
||||||
} else {
|
} else {
|
||||||
delay_tx++;
|
delay_tx++;
|
||||||
next_tx_delay = params->aggregate_timeoff
|
next_tx_delay = params->aggregate_timeoff -
|
||||||
- _lora_time.get_elapsed_time(params->last_aggregate_tx_time);
|
_lora_time.get_elapsed_time(params->last_aggregate_tx_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel_count > 0) {
|
if (channel_count > 0) {
|
||||||
|
@ -1272,7 +1275,8 @@ lorawan_status_t LoRaPHY::set_next_channel(channel_selection_params_t* params,
|
||||||
return LORAWAN_STATUS_NO_CHANNEL_FOUND;
|
return LORAWAN_STATUS_NO_CHANNEL_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
lorawan_status_t LoRaPHY::add_channel(const channel_params_t* new_channel, uint8_t id)
|
lorawan_status_t LoRaPHY::add_channel(const channel_params_t *new_channel,
|
||||||
|
uint8_t id)
|
||||||
{
|
{
|
||||||
bool dr_invalid = false;
|
bool dr_invalid = false;
|
||||||
bool freq_invalid = false;
|
bool freq_invalid = false;
|
||||||
|
@ -1367,7 +1371,7 @@ bool LoRaPHY::remove_channel(uint8_t channel_id)
|
||||||
phy_params.max_channel_cnt);
|
phy_params.max_channel_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaPHY::set_tx_cont_mode(cw_mode_params_t* params, uint32_t given_frequency)
|
void LoRaPHY::set_tx_cont_mode(cw_mode_params_t *params, uint32_t given_frequency)
|
||||||
{
|
{
|
||||||
band_t *bands_table = (band_t *) phy_params.bands.table;
|
band_t *bands_table = (band_t *) phy_params.bands.table;
|
||||||
channel_params_t *channels = phy_params.channels.channel_list;
|
channel_params_t *channels = phy_params.channels.channel_list;
|
||||||
|
@ -1380,7 +1384,7 @@ void LoRaPHY::set_tx_cont_mode(cw_mode_params_t* params, uint32_t given_frequenc
|
||||||
uint32_t frequency = 0;
|
uint32_t frequency = 0;
|
||||||
|
|
||||||
if (given_frequency == 0) {
|
if (given_frequency == 0) {
|
||||||
frequency = channels[params->channel].frequency;
|
frequency = channels[params->channel].frequency;
|
||||||
} else {
|
} else {
|
||||||
frequency = given_frequency;
|
frequency = given_frequency;
|
||||||
}
|
}
|
||||||
|
@ -1388,7 +1392,7 @@ void LoRaPHY::set_tx_cont_mode(cw_mode_params_t* params, uint32_t given_frequenc
|
||||||
// Calculate physical TX power
|
// Calculate physical TX power
|
||||||
if (params->max_eirp > 0 && params->antenna_gain > 0) {
|
if (params->max_eirp > 0 && params->antenna_gain > 0) {
|
||||||
phy_tx_power = compute_tx_power(params->tx_power, params->max_eirp,
|
phy_tx_power = compute_tx_power(params->tx_power, params->max_eirp,
|
||||||
params->antenna_gain );
|
params->antenna_gain);
|
||||||
} else {
|
} else {
|
||||||
phy_tx_power = params->tx_power;
|
phy_tx_power = params->tx_power;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue