mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			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.pull/6910/head
							parent
							
								
									0feb0efb89
								
							
						
					
					
						commit
						9973eb3e79
					
				| 
						 | 
				
			
			@ -608,55 +608,59 @@ void LoRaWANStack::process_reception(const uint8_t* const payload, uint16_t size
 | 
			
		|||
        mlme_confirm_handler();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (_loramac.nwk_joined()) {
 | 
			
		||||
        if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
 | 
			
		||||
            // if ack was not received, we will try retransmission after
 | 
			
		||||
            // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
 | 
			
		||||
            // if ack was received. Otherwise, following method will be called in
 | 
			
		||||
            // LoRaMac.cpp, on_ack_timeout_timer_event().
 | 
			
		||||
            if (_loramac.get_mcps_indication()->is_ack_recvd) {
 | 
			
		||||
                tr_debug("Ack=OK, NbTrials=%d", _loramac.get_mcps_confirmation()->nb_retries);
 | 
			
		||||
                _loramac.post_process_mcps_req();
 | 
			
		||||
                _ctrl_flags |= TX_DONE_FLAG;
 | 
			
		||||
                _ctrl_flags &= ~TX_ONGOING_FLAG;
 | 
			
		||||
                state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (!_loramac.continue_sending_process()) {
 | 
			
		||||
                    tr_error("Retries exhausted for Class A device");
 | 
			
		||||
                    _ctrl_flags &= ~TX_DONE_FLAG;
 | 
			
		||||
                    _ctrl_flags |= TX_ONGOING_FLAG;
 | 
			
		||||
                    state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // handle UNCONFIRMED, PROPRIETARY case here, RX slots were turned off due to
 | 
			
		||||
            // valid packet reception, so we generate a TX_DONE event
 | 
			
		||||
    if (!_loramac.nwk_joined()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // if the outgoing message was of CONFIRMED type
 | 
			
		||||
    if (_loramac.get_mcps_confirmation()->req_type == MCPS_CONFIRMED) {
 | 
			
		||||
        // if ack was not received, we will try retransmission after
 | 
			
		||||
        // ACK_TIMEOUT. handle_data_frame() already disables ACK_TIMEOUT timer
 | 
			
		||||
        // if ack was received. Otherwise, following method will be called in
 | 
			
		||||
        // LoRaMac.cpp, on_ack_timeout_timer_event().
 | 
			
		||||
        if (_loramac.get_mcps_indication()->is_ack_recvd) {
 | 
			
		||||
            tr_debug("Ack=OK, NbTrials=%d",
 | 
			
		||||
                     _loramac.get_mcps_confirmation()->nb_retries);
 | 
			
		||||
            _loramac.post_process_mcps_req();
 | 
			
		||||
            _ctrl_flags |= TX_DONE_FLAG;
 | 
			
		||||
            _ctrl_flags &= ~TX_ONGOING_FLAG;
 | 
			
		||||
            state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!_loramac.continue_sending_process()) {
 | 
			
		||||
                tr_error("Retries exhausted for Class A device");
 | 
			
		||||
                _ctrl_flags &= ~TX_DONE_FLAG;
 | 
			
		||||
                _ctrl_flags |= TX_ONGOING_FLAG;
 | 
			
		||||
                state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // handle UNCONFIRMED case here, RX slots were turned off due to
 | 
			
		||||
        // valid packet reception
 | 
			
		||||
        _loramac.post_process_mcps_req();
 | 
			
		||||
        _ctrl_flags |= TX_DONE_FLAG;
 | 
			
		||||
        state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // handle any pending MCPS indication
 | 
			
		||||
        if (_loramac.get_mcps_indication()->pending) {
 | 
			
		||||
            _loramac.post_process_mcps_ind();
 | 
			
		||||
            _ctrl_flags |= MSG_RECVD_FLAG;
 | 
			
		||||
            state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
        }
 | 
			
		||||
    // handle any pending MCPS indication
 | 
			
		||||
    if (_loramac.get_mcps_indication()->pending) {
 | 
			
		||||
        _loramac.post_process_mcps_ind();
 | 
			
		||||
        _ctrl_flags |= MSG_RECVD_FLAG;
 | 
			
		||||
        state_controller(DEVICE_STATE_STATUS_CHECK);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // change the state only if a TX cycle completes for Class A
 | 
			
		||||
        // For class C it's not needed as it will already be in receiving
 | 
			
		||||
        // state, no matter if the TX cycle completed or not.
 | 
			
		||||
        if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
 | 
			
		||||
            // we are done here, update the state
 | 
			
		||||
              state_machine_run_to_completion();
 | 
			
		||||
        }
 | 
			
		||||
    // change the state only if a TX cycle completes for Class A
 | 
			
		||||
    // For class C it's not needed as it will already be in receiving
 | 
			
		||||
    // state, no matter if the TX cycle completed or not.
 | 
			
		||||
    if (!(_ctrl_flags & TX_ONGOING_FLAG)) {
 | 
			
		||||
        // we are done here, update the state
 | 
			
		||||
        state_machine_run_to_completion();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if (_loramac.get_mlme_indication()->pending) {
 | 
			
		||||
            tr_debug("MLME Indication pending");
 | 
			
		||||
            _loramac.post_process_mlme_ind();
 | 
			
		||||
            tr_debug("Automatic uplink requested");
 | 
			
		||||
            mlme_indication_handler();
 | 
			
		||||
        }
 | 
			
		||||
    if (_loramac.get_mlme_indication()->pending) {
 | 
			
		||||
        tr_debug("MLME Indication pending");
 | 
			
		||||
        _loramac.post_process_mlme_ind();
 | 
			
		||||
        tr_debug("Immediate Uplink requested");
 | 
			
		||||
        mlme_indication_handler();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _ready_for_rx = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -765,6 +769,7 @@ void LoRaWANStack::send_automatic_uplink_message(const uint8_t port)
 | 
			
		|||
{
 | 
			
		||||
    const int16_t ret = handle_tx(port, NULL, 0, MSG_CONFIRMED_FLAG, true, true);
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        tr_debug("Failed to generate AUTOMATIC UPLINK, error code = %d", ret);
 | 
			
		||||
        send_event_to_application(AUTOMATIC_UPLINK_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -871,8 +876,16 @@ void LoRaWANStack::mlme_confirm_handler()
 | 
			
		|||
            state_controller(DEVICE_STATE_CONNECTED);
 | 
			
		||||
        } else {
 | 
			
		||||
            tr_error("Joining error: %d", _loramac.get_mlme_confirmation()->status);
 | 
			
		||||
            _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
 | 
			
		||||
            state_controller(DEVICE_STATE_JOINING);
 | 
			
		||||
            if (_loramac.get_mlme_confirmation()->status == LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL) {
 | 
			
		||||
                // fatal error
 | 
			
		||||
                _device_current_state = DEVICE_STATE_IDLE;
 | 
			
		||||
                send_event_to_application(CRYPTO_ERROR);
 | 
			
		||||
            } else {
 | 
			
		||||
                // non-fatal, retry if possible
 | 
			
		||||
                _device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
 | 
			
		||||
                state_controller(DEVICE_STATE_JOINING);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,6 +83,7 @@ LoRaMac::LoRaMac()
 | 
			
		|||
      _mlme_indication(),
 | 
			
		||||
      _mlme_confirmation(),
 | 
			
		||||
      _is_nwk_joined(false),
 | 
			
		||||
      _continuous_rx2_window_open(false),
 | 
			
		||||
      _device_class(CLASS_A)
 | 
			
		||||
{
 | 
			
		||||
    _params.keys.dev_eui = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +197,9 @@ void LoRaMac::on_radio_tx_done(void)
 | 
			
		|||
        _lora_phy.put_radio_to_sleep();
 | 
			
		||||
    } else {
 | 
			
		||||
        // this will open a continuous RX2 window until time==RECV_DELAY1
 | 
			
		||||
        open_rx2_window();
 | 
			
		||||
        if (!_continuous_rx2_window_open) {
 | 
			
		||||
            open_rx2_window();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(_params.is_rx_window_enabled == true) {
 | 
			
		||||
| 
						 | 
				
			
			@ -226,8 +229,7 @@ void LoRaMac::on_radio_tx_done(void)
 | 
			
		|||
/**
 | 
			
		||||
 * This part handles incoming frames in response to Radio RX Interrupt
 | 
			
		||||
 */
 | 
			
		||||
void LoRaMac::handle_join_accept_frame(const uint8_t *payload,
 | 
			
		||||
                                       uint16_t size)
 | 
			
		||||
void LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t mic = 0;
 | 
			
		||||
    uint32_t mic_rx = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +260,7 @@ void LoRaMac::handle_join_accept_frame(const uint8_t *payload,
 | 
			
		|||
    mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 3] << 24);
 | 
			
		||||
 | 
			
		||||
    if (mic_rx == mic) {
 | 
			
		||||
 | 
			
		||||
        _lora_time.stop(_params.timers.rx_window2_timer);
 | 
			
		||||
        if (_lora_crypto.compute_skeys_for_join_frame(_params.keys.app_key,
 | 
			
		||||
                                                      APPKEY_KEY_LENGTH,
 | 
			
		||||
                                                      _params.rx_buffer + 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -517,6 +519,7 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
 | 
			
		|||
        if (!is_multicast) {
 | 
			
		||||
            // We are not the destination of this frame.
 | 
			
		||||
            _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
 | 
			
		||||
            _mcps_indication.pending = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -533,14 +536,14 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
 | 
			
		|||
    if (!message_integrity_check(payload, size, &ptr_pos, address,
 | 
			
		||||
                                 &downlink_counter, nwk_skey)) {
 | 
			
		||||
        tr_error("MIC failed");
 | 
			
		||||
        _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
 | 
			
		||||
        _mcps_indication.pending = false;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // message is intended for us and MIC have passed, stop RX2 Window
 | 
			
		||||
    // Spec: 3.3.4 Receiver Activity during the receive windows
 | 
			
		||||
    if (_params.rx_slot == RX_SLOT_WIN_2) {
 | 
			
		||||
        _lora_time.stop(_params.timers.rx_window2_timer);
 | 
			
		||||
    }
 | 
			
		||||
    _lora_time.stop(_params.timers.rx_window2_timer);
 | 
			
		||||
 | 
			
		||||
    _mcps_confirmation.ack_received = false;
 | 
			
		||||
    _mcps_indication.is_ack_recvd = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -612,7 +615,7 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
 | 
			
		|||
    // to take retransmissions and repetitions into account. Error cases
 | 
			
		||||
    // will be handled in function OnMacStateCheckTimerEvent.
 | 
			
		||||
    if (_params.is_node_ack_requested) {
 | 
			
		||||
        if (fctrl.bits.ack == 1) {
 | 
			
		||||
        if (fctrl.bits.ack) {
 | 
			
		||||
            _mac_commands.clear_command_buffer();
 | 
			
		||||
            _mcps_confirmation.ack_received = fctrl.bits.ack;
 | 
			
		||||
            _mcps_indication.is_ack_recvd = fctrl.bits.ack;
 | 
			
		||||
| 
						 | 
				
			
			@ -641,7 +644,7 @@ void LoRaMac::handle_data_frame(const uint8_t* const payload,
 | 
			
		|||
        _mcps_indication.buffer_size = size - ptr_pos;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // only stop act timer, if the ack is actuall recieved
 | 
			
		||||
    // only stop act timer, if the ack is actually recieved
 | 
			
		||||
    if (_mcps_confirmation.ack_received) {
 | 
			
		||||
        _lora_time.stop(_params.timers.ack_timeout_timer);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -665,7 +668,9 @@ void LoRaMac::on_radio_rx_done(const uint8_t* const payload, uint16_t size,
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (_device_class == CLASS_C) {
 | 
			
		||||
         open_rx2_window();
 | 
			
		||||
        if (!_continuous_rx2_window_open) {
 | 
			
		||||
            open_rx2_window();
 | 
			
		||||
        }
 | 
			
		||||
     } else {
 | 
			
		||||
         _lora_phy.put_radio_to_sleep();
 | 
			
		||||
     }
 | 
			
		||||
| 
						 | 
				
			
			@ -841,12 +846,14 @@ void LoRaMac::on_backoff_timer_expiry(void)
 | 
			
		|||
    Lock lock(*this);
 | 
			
		||||
    lorawan_status_t status = schedule_tx();
 | 
			
		||||
    MBED_ASSERT(status==LORAWAN_STATUS_OK);
 | 
			
		||||
    (void) status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LoRaMac::open_rx1_window(void)
 | 
			
		||||
{
 | 
			
		||||
    Lock lock(*this);
 | 
			
		||||
    tr_debug("Opening RX1 Window");
 | 
			
		||||
    _continuous_rx2_window_open = false;
 | 
			
		||||
    _lora_time.stop(_params.timers.rx_window1_timer);
 | 
			
		||||
    _params.rx_slot = RX_SLOT_WIN_1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -880,7 +887,13 @@ void LoRaMac::open_rx2_window()
 | 
			
		|||
    _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.is_rx_continuous = get_device_class()==CLASS_C ? true : false;
 | 
			
		||||
    if (get_device_class() == CLASS_C) {
 | 
			
		||||
        _continuous_rx2_window_open = true;
 | 
			
		||||
        _params.rx_window2_config.is_rx_continuous = true;
 | 
			
		||||
    } else {
 | 
			
		||||
        _continuous_rx2_window_open = false;
 | 
			
		||||
        _params.rx_window2_config.is_rx_continuous = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _mcps_indication.rx_datarate = _params.rx_window2_config.datarate;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -911,8 +924,11 @@ void LoRaMac::on_ack_timeout_timer_event(void)
 | 
			
		|||
    tr_debug("ACK_TIMEOUT Elapses, Retrying ...");
 | 
			
		||||
    _lora_time.stop(_params.timers.ack_timeout_timer);
 | 
			
		||||
 | 
			
		||||
    // reduce data rate
 | 
			
		||||
    if ((_params.ack_timeout_retry_counter % 2)) {
 | 
			
		||||
    // reduce data rate on every 2nd attempt if and only if the
 | 
			
		||||
    // ADR is on
 | 
			
		||||
    if ((_params.ack_timeout_retry_counter % 2)
 | 
			
		||||
            && (_params.sys_params.adr_on)) {
 | 
			
		||||
        tr_debug("Trading datarate for range");
 | 
			
		||||
        _params.sys_params.channel_data_rate = _lora_phy.get_next_lower_tx_datarate(
 | 
			
		||||
                                               _params.sys_params.channel_data_rate);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -933,6 +949,7 @@ void LoRaMac::on_ack_timeout_timer_event(void)
 | 
			
		|||
        // now that is a critical failure
 | 
			
		||||
        lorawan_status_t status = handle_retransmission();
 | 
			
		||||
        MBED_ASSERT(status==LORAWAN_STATUS_OK);
 | 
			
		||||
        (void) status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _params.ack_timeout_retry_counter++;
 | 
			
		||||
| 
						 | 
				
			
			@ -1501,6 +1518,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            if (_params.is_srv_ack_requested == true) {
 | 
			
		||||
                tr_debug("Acking to NS");
 | 
			
		||||
                fctrl->bits.ack = 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -675,6 +675,8 @@ private:
 | 
			
		|||
 | 
			
		||||
    bool _is_nwk_joined;
 | 
			
		||||
 | 
			
		||||
    bool _continuous_rx2_window_open;
 | 
			
		||||
 | 
			
		||||
    device_class_t _device_class;
 | 
			
		||||
 | 
			
		||||
#if defined(LORAWAN_COMPLIANCE_TEST)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -192,7 +192,7 @@ typedef struct lorawan_connect {
 | 
			
		|||
 * TX_DONE              - When a packet is sent
 | 
			
		||||
 * TX_TIMEOUT,          - When stack was unable to send packet in TX window
 | 
			
		||||
 * TX_ERROR,            - A general TX error
 | 
			
		||||
 * TX_CRYPTO_ERROR,     - If MIC fails, or any other crypto relted error
 | 
			
		||||
 * CRYPTO_ERROR,        - A crypto error indicating wrong keys
 | 
			
		||||
 * TX_SCHEDULING_ERROR, - When stack is unable to schedule packet
 | 
			
		||||
 * RX_DONE,             - When there is something to receive
 | 
			
		||||
 * RX_TIMEOUT,          - Not yet mapped
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +209,8 @@ typedef enum lora_events {
 | 
			
		|||
    TX_DONE,
 | 
			
		||||
    TX_TIMEOUT,
 | 
			
		||||
    TX_ERROR,
 | 
			
		||||
    TX_CRYPTO_ERROR,
 | 
			
		||||
    CRYPTO_ERROR,
 | 
			
		||||
    TX_CRYPTO_ERROR = CRYPTO_ERROR, //keeping this for backward compatibility
 | 
			
		||||
    TX_SCHEDULING_ERROR,
 | 
			
		||||
    RX_DONE,
 | 
			
		||||
    RX_TIMEOUT,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue