Skip to content

Commit 9973eb3

Browse files
author
Hasnain Virk
committed
Stability improvements & CRYPTO_ERROR addition
General stability improvements are performed. A flag is added if a Class C RX2 window is open. We shouldn't open it again if its already opened. TX_CRYPTO_ERROR is renamed to CRYPTO_ERROR. Keeping TX_CRYPTO_ERROR for backwards compatibility.
1 parent 0feb0ef commit 9973eb3

File tree

4 files changed

+93
-59
lines changed

4 files changed

+93
-59
lines changed

features/lorawan/LoRaWANStack.cpp

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -608,55 +608,59 @@ void LoRaWANStack::process_reception(const uint8_t* const payload, uint16_t size
608608
mlme_confirm_handler();
609609
}
610610

611-
if (_loramac.nwk_joined()) {
612-
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
613-
// if ack was not received, we will try retransmission after
614-
// ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
615-
// if ack was received. Otherwise, following method will be called in
616-
// LoRaMac.cpp, on_ack_timeout_timer_event().
617-
if (_loramac.get_mcps_indication()->is_ack_recvd) {
618-
tr_debug("Ack=OK, NbTrials=%d", _loramac.get_mcps_confirmation()->nb_retries);
619-
_loramac.post_process_mcps_req();
620-
_ctrl_flags |= TX_DONE_FLAG;
621-
_ctrl_flags &= ~TX_ONGOING_FLAG;
622-
state_controller(DEVICE_STATE_STATUS_CHECK);
623-
} else {
624-
if (!_loramac.continue_sending_process()) {
625-
tr_error("Retries exhausted for Class A device");
626-
_ctrl_flags &= ~TX_DONE_FLAG;
627-
_ctrl_flags |= TX_ONGOING_FLAG;
628-
state_controller(DEVICE_STATE_STATUS_CHECK);
629-
}
630-
}
631-
} else {
632-
// handle UNCONFIRMED, PROPRIETARY case here, RX slots were turned off due to
633-
// valid packet reception, so we generate a TX_DONE event
611+
if (!_loramac.nwk_joined()) {
612+
return;
613+
}
614+
615+
// if the outgoing message was of CONFIRMED type
616+
if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
617+
// if ack was not received, we will try retransmission after
618+
// ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
619+
// if ack was received. Otherwise, following method will be called in
620+
// LoRaMac.cpp, on_ack_timeout_timer_event().
621+
if (_loramac.get_mcps_indication()->is_ack_recvd) {
622+
tr_debug("Ack=OK, NbTrials=%d",
623+
_loramac.get_mcps_confirmation()->nb_retries);
634624
_loramac.post_process_mcps_req();
635625
_ctrl_flags |= TX_DONE_FLAG;
626+
_ctrl_flags &= ~TX_ONGOING_FLAG;
636627
state_controller(DEVICE_STATE_STATUS_CHECK);
628+
} else {
629+
if (!_loramac.continue_sending_process()) {
630+
tr_error("Retries exhausted for Class A device");
631+
_ctrl_flags &= ~TX_DONE_FLAG;
632+
_ctrl_flags |= TX_ONGOING_FLAG;
633+
state_controller(DEVICE_STATE_STATUS_CHECK);
634+
}
637635
}
636+
} else {
637+
// handle UNCONFIRMED case here, RX slots were turned off due to
638+
// valid packet reception
639+
_loramac.post_process_mcps_req();
640+
_ctrl_flags |= TX_DONE_FLAG;
641+
state_controller(DEVICE_STATE_STATUS_CHECK);
642+
}
638643

639-
// handle any pending MCPS indication
640-
if (_loramac.get_mcps_indication()->pending) {
641-
_loramac.post_process_mcps_ind();
642-
_ctrl_flags |= MSG_RECVD_FLAG;
643-
state_controller(DEVICE_STATE_STATUS_CHECK);
644-
}
644+
// handle any pending MCPS indication
645+
if (_loramac.get_mcps_indication()->pending) {
646+
_loramac.post_process_mcps_ind();
647+
_ctrl_flags |= MSG_RECVD_FLAG;
648+
state_controller(DEVICE_STATE_STATUS_CHECK);
649+
}
645650

646-
// change the state only if a TX cycle completes for Class A
647-
// For class C it's not needed as it will already be in receiving
648-
// state, no matter if the TX cycle completed or not.
649-
if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
650-
// we are done here, update the state
651-
state_machine_run_to_completion();
652-
}
651+
// change the state only if a TX cycle completes for Class A
652+
// For class C it's not needed as it will already be in receiving
653+
// state, no matter if the TX cycle completed or not.
654+
if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
655+
// we are done here, update the state
656+
state_machine_run_to_completion();
657+
}
653658

654-
if (_loramac.get_mlme_indication()->pending) {
655-
tr_debug("MLME Indication pending");
656-
_loramac.post_process_mlme_ind();
657-
tr_debug("Automatic uplink requested");
658-
mlme_indication_handler();
659-
}
659+
if (_loramac.get_mlme_indication()->pending) {
660+
tr_debug("MLME Indication pending");
661+
_loramac.post_process_mlme_ind();
662+
tr_debug("Immediate Uplink requested");
663+
mlme_indication_handler();
660664
}
661665

662666
_ready_for_rx = true;
@@ -765,6 +769,7 @@ void LoRaWANStack::send_automatic_uplink_message(const uint8_t port)
765769
{
766770
const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true);
767771
if (ret < 0) {
772+
tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret);
768773
send_event_to_application(AUTOMATIC_UPLINK_ERROR);
769774
}
770775
}
@@ -871,8 +876,16 @@ void LoRaWANStack::mlme_confirm_handler()
871876
state_controller(DEVICE_STATE_CONNECTED);
872877
} else {
873878
tr_error("Joining error: %d", _loramac.get_mlme_confirmation()->status);
874-
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
875-
state_controller(DEVICE_STATE_JOINING);
879+
if (_loramac.get_mlme_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL) {
880+
// fatal error
881+
_device_current_state = DEVICE_STATE_IDLE;
882+
send_event_to_application(CRYPTO_ERROR);
883+
} else {
884+
// non-fatal, retry if possible
885+
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
886+
state_controller(DEVICE_STATE_JOINING);
887+
}
888+
876889
}
877890
}
878891
}

features/lorawan/lorastack/mac/LoRaMac.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ LoRaMac::LoRaMac()
8383
_mlme_indication(),
8484
_mlme_confirmation(),
8585
_is_nwk_joined(false),
86+
_continuous_rx2_window_open(false),
8687
_device_class(CLASS_A)
8788
{
8889
_params.keys.dev_eui = NULL;
@@ -196,7 +197,9 @@ void LoRaMac::on_radio_tx_done(void)
196197
_lora_phy.put_radio_to_sleep();
197198
} else {
198199
// this will open a continuous RX2 window until time==RECV_DELAY1
199-
open_rx2_window();
200+
if (!_continuous_rx2_window_open) {
201+
open_rx2_window();
202+
}
200203
}
201204

202205
if(_params.is_rx_window_enabled == true) {
@@ -226,8 +229,7 @@ void LoRaMac::on_radio_tx_done(void)
226229
/**
227230
* This part handles incoming frames in response to Radio RX Interrupt
228231
*/
229-
void LoRaMac::handle_join_accept_frame(const uint8_t *payload,
230-
uint16_t size)
232+
void LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size)
231233
{
232234
uint32_t mic = 0;
233235
uint32_t mic_rx = 0;
@@ -258,7 +260,7 @@ void LoRaMac::handle_join_accept_frame(const uint8_t *payload,
258260
mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 3] << 24);
259261

260262
if (mic_rx == mic) {
261-
263+
_lora_time.stop(_params.timers.rx_window2_timer);
262264
if (_lora_crypto.compute_skeys_for_join_frame(_params.keys.app_key,
263265
APPKEY_KEY_LENGTH,
264266
_params.rx_buffer + 1,
@@ -517,6 +519,7 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
517519
if (!is_multicast) {
518520
// We are not the destination of this frame.
519521
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
522+
_mcps_indication.pending = false;
520523
return;
521524
}
522525
} else {
@@ -533,14 +536,14 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
533536
if (!message_integrity_check(payload, size, &ptr_pos, address,
534537
&downlink_counter, nwk_skey)) {
535538
tr_error("MIC failed");
539+
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
540+
_mcps_indication.pending = false;
536541
return;
537542
}
538543

539544
// message is intended for us and MIC have passed, stop RX2 Window
540545
// Spec: 3.3.4 Receiver Activity during the receive windows
541-
if (_params.rx_slot == RX_SLOT_WIN_2) {
542-
_lora_time.stop(_params.timers.rx_window2_timer);
543-
}
546+
_lora_time.stop(_params.timers.rx_window2_timer);
544547

545548
_mcps_confirmation.ack_received = false;
546549
_mcps_indication.is_ack_recvd = false;
@@ -612,7 +615,7 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
612615
// to take retransmissions and repetitions into account. Error cases
613616
// will be handled in function OnMacStateCheckTimerEvent.
614617
if (_params.is_node_ack_requested) {
615-
if (fctrl.bits.ack == 1) {
618+
if (fctrl.bits.ack) {
616619
_mac_commands.clear_command_buffer();
617620
_mcps_confirmation.ack_received = fctrl.bits.ack;
618621
_mcps_indication.is_ack_recvd = fctrl.bits.ack;
@@ -641,7 +644,7 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
641644
_mcps_indication.buffer_size = size - ptr_pos;
642645
}
643646

644-
// only stop act timer, if the ack is actuall recieved
647+
// only stop act timer, if the ack is actually recieved
645648
if (_mcps_confirmation.ack_received) {
646649
_lora_time.stop(_params.timers.ack_timeout_timer);
647650
}
@@ -665,7 +668,9 @@ void LoRaMac::on_radio_rx_done(const uint8_t* const payload, uint16_t size,
665668
}
666669

667670
if (_device_class == CLASS_C) {
668-
open_rx2_window();
671+
if (!_continuous_rx2_window_open) {
672+
open_rx2_window();
673+
}
669674
} else {
670675
_lora_phy.put_radio_to_sleep();
671676
}
@@ -841,12 +846,14 @@ void LoRaMac::on_backoff_timer_expiry(void)
841846
Lock lock(*this);
842847
lorawan_status_t status = schedule_tx();
843848
MBED_ASSERT(status==LORAWAN_STATUS_OK);
849+
(void) status;
844850
}
845851

846852
void LoRaMac::open_rx1_window(void)
847853
{
848854
Lock lock(*this);
849855
tr_debug("Opening RX1 Window");
856+
_continuous_rx2_window_open = false;
850857
_lora_time.stop(_params.timers.rx_window1_timer);
851858
_params.rx_slot = RX_SLOT_WIN_1;
852859

@@ -880,7 +887,13 @@ void LoRaMac::open_rx2_window()
880887
_params.rx_window2_config.is_repeater_supported = _params.is_repeater_supported;
881888
_params.rx_window2_config.rx_slot = RX_SLOT_WIN_2;
882889

883-
_params.rx_window2_config.is_rx_continuous = get_device_class()==CLASS_C ? true : false;
890+
if (get_device_class() == CLASS_C) {
891+
_continuous_rx2_window_open = true;
892+
_params.rx_window2_config.is_rx_continuous = true;
893+
} else {
894+
_continuous_rx2_window_open = false;
895+
_params.rx_window2_config.is_rx_continuous = false;
896+
}
884897

885898
_mcps_indication.rx_datarate = _params.rx_window2_config.datarate;
886899

@@ -911,8 +924,11 @@ void LoRaMac::on_ack_timeout_timer_event(void)
911924
tr_debug("ACK_TIMEOUT Elapses, Retrying ...");
912925
_lora_time.stop(_params.timers.ack_timeout_timer);
913926

914-
// reduce data rate
915-
if ((_params.ack_timeout_retry_counter % 2)) {
927+
// reduce data rate on every 2nd attempt if and only if the
928+
// ADR is on
929+
if ((_params.ack_timeout_retry_counter % 2)
930+
&& (_params.sys_params.adr_on)) {
931+
tr_debug("Trading datarate for range");
916932
_params.sys_params.channel_data_rate = _lora_phy.get_next_lower_tx_datarate(
917933
_params.sys_params.channel_data_rate);
918934
}
@@ -933,6 +949,7 @@ void LoRaMac::on_ack_timeout_timer_event(void)
933949
// now that is a critical failure
934950
lorawan_status_t status = handle_retransmission();
935951
MBED_ASSERT(status==LORAWAN_STATUS_OK);
952+
(void) status;
936953
}
937954

938955
_params.ack_timeout_retry_counter++;
@@ -1501,6 +1518,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
15011518
}
15021519

15031520
if (_params.is_srv_ack_requested == true) {
1521+
tr_debug("Acking to NS");
15041522
fctrl->bits.ack = 1;
15051523
}
15061524

features/lorawan/lorastack/mac/LoRaMac.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,8 @@ class LoRaMac {
675675

676676
bool _is_nwk_joined;
677677

678+
bool _continuous_rx2_window_open;
679+
678680
device_class_t _device_class;
679681

680682
#if defined(LORAWAN_COMPLIANCE_TEST)

features/lorawan/lorawan_types.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ typedef struct lorawan_connect {
192192
* TX_DONE - When a packet is sent
193193
* TX_TIMEOUT, - When stack was unable to send packet in TX window
194194
* TX_ERROR, - A general TX error
195-
* TX_CRYPTO_ERROR, - If MIC fails, or any other crypto relted error
195+
* CRYPTO_ERROR, - A crypto error indicating wrong keys
196196
* TX_SCHEDULING_ERROR, - When stack is unable to schedule packet
197197
* RX_DONE, - When there is something to receive
198198
* RX_TIMEOUT, - Not yet mapped
@@ -209,7 +209,8 @@ typedef enum lora_events {
209209
TX_DONE,
210210
TX_TIMEOUT,
211211
TX_ERROR,
212-
TX_CRYPTO_ERROR,
212+
CRYPTO_ERROR,
213+
TX_CRYPTO_ERROR = CRYPTO_ERROR, //keeping this for backward compatibility
213214
TX_SCHEDULING_ERROR,
214215
RX_DONE,
215216
RX_TIMEOUT,

0 commit comments

Comments
 (0)