diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index 0eee8876b7..42f9d6ff6d 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -122,56 +122,72 @@ void LoRaWANStack::bind_radio_driver(LoRaRadio& radio) lorawan_status_t LoRaWANStack::connect() { - // connection attempt without parameters. - // System tries to look for configuration in mbed_lib.json that can be - // overridden by mbed_app.json. However, if none of the json files are - // available (highly unlikely), we still fallback to some default parameters. - // Check lorawan_data_structure for fallback defaults. + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + tr_error("Stack not initialized!"); + return LORAWAN_STATUS_NOT_INITIALIZED; + } - lorawan_connect_t connection_params; + lorawan_status_t status = _loramac.prepare_join(NULL, MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); - //TODO: LoRaWANStack don't need to know these values, move to LoRaMac (or below) -#if MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION - const static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; - const static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; - const static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; + if (LORAWAN_STATUS_OK != status) { + return status; + } - connection_params.connect_type = LORAWAN_CONNECTION_OTAA; - connection_params.connection_u.otaa.app_eui = const_cast(app_eui); - connection_params.connection_u.otaa.dev_eui = const_cast(dev_eui); - connection_params.connection_u.otaa.app_key = const_cast(app_key); - connection_params.connection_u.otaa.nb_trials = MBED_CONF_LORA_NB_TRIALS; - - return join_request_by_otaa(connection_params); -#else - const static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; - const static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; - const static uint32_t dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; - const static uint32_t nwk_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK); - - connection_params.connect_type = LORAWAN_CONNECTION_ABP; - connection_params.connection_u.abp.nwk_id = const_cast(nwk_id); - connection_params.connection_u.abp.dev_addr = const_cast(dev_addr); - connection_params.connection_u.abp.nwk_skey = const_cast(nwk_skey); - connection_params.connection_u.abp.app_skey = const_cast(app_skey); - - return activation_by_personalization(connection_params); -#endif + return handle_connect(MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION); } lorawan_status_t LoRaWANStack::connect(const lorawan_connect_t &connect) { - lorawan_status_t mac_status; - - if (connect.connect_type == LORAWAN_CONNECTION_OTAA) { - mac_status = join_request_by_otaa(connect); - } else if (connect.connect_type == LORAWAN_CONNECTION_ABP) { - mac_status = activation_by_personalization(connect); - } else { - return LORAWAN_STATUS_PARAMETER_INVALID; + if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { + tr_error("Stack not initialized!"); + return LORAWAN_STATUS_NOT_INITIALIZED; } - return mac_status; + if (!(connect.connect_type == LORAWAN_CONNECTION_OTAA) && + !(connect.connect_type == LORAWAN_CONNECTION_ABP)) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + bool is_otaa = (connect.connect_type == LORAWAN_CONNECTION_OTAA); + + lorawan_status_t status = _loramac.prepare_join(&connect, is_otaa); + + if (LORAWAN_STATUS_OK != status) { + return status; + } + + return handle_connect(is_otaa); +} + +lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa) +{ + device_states_t new_state; + + if (is_otaa) { + tr_debug("Initiating OTAA"); + + // As mentioned in the comment above, in 1.0.2 spec, counters are always set + // to zero for new connection. This section is common for both normal and + // connection restore at this moment. Will change in future with 1.1 support. + _lw_session.downlink_counter = 0; + _lw_session.uplink_counter = 0; + new_state = DEVICE_STATE_JOINING; + } else { + // If current state is SHUTDOWN, device may be trying to re-establish + // communication. In case of ABP specification is meddled about frame counters. + // It says to reset counters to zero but there is no mechanism to tell the + // network server that the device was disconnected or restarted. + // At the moment, this implementation does not support a non-volatile + // memory storage. + //_lw_session.downlink_counter; //Get from NVM + //_lw_session.uplink_counter; //Get from NVM + + tr_debug("Initiating ABP"); + tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", + _lw_session.uplink_counter, _lw_session.downlink_counter); + new_state = DEVICE_STATE_ABP_CONNECTING; + } + + return lora_state_machine(new_state); } lorawan_status_t LoRaWANStack::initialize_mac_layer(EventQueue *queue) @@ -315,61 +331,6 @@ lorawan_status_t LoRaWANStack::set_channel_data_rate(uint8_t data_rate) return _loramac.set_channel_data_rate(data_rate); } -lorawan_status_t LoRaWANStack::join_request_by_otaa(const lorawan_connect_t ¶ms) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) - { - tr_error("Stack not initialized!"); - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - tr_debug("Initiating OTAA"); - - // As mentioned in the comment above, in 1.0.2 spec, counters are always set - // to zero for new connection. This section is common for both normal and - // connection restore at this moment. Will change in future with 1.1 support. - _lw_session.downlink_counter = 0; - _lw_session.uplink_counter = 0; - _lw_session.connection.connect_type = LORAWAN_CONNECTION_OTAA; - - _lw_session.connection.connection_u.otaa.dev_eui = params.connection_u.otaa.dev_eui; - _lw_session.connection.connection_u.otaa.app_eui = params.connection_u.otaa.app_eui; - _lw_session.connection.connection_u.otaa.app_key = params.connection_u.otaa.app_key; - _lw_session.connection.connection_u.otaa.nb_trials = params.connection_u.otaa.nb_trials; - - return lora_state_machine(DEVICE_STATE_JOINING); -} - -lorawan_status_t LoRaWANStack::activation_by_personalization(const lorawan_connect_t ¶ms) -{ - if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) { - tr_error("Stack not initialized!"); - return LORAWAN_STATUS_NOT_INITIALIZED; - } - - tr_debug("Initiating ABP"); - - _lw_session.connection.connect_type = LORAWAN_CONNECTION_ABP; - - _lw_session.connection.connection_u.abp.dev_addr = params.connection_u.abp.dev_addr; - _lw_session.connection.connection_u.abp.nwk_skey = params.connection_u.abp.nwk_skey; - _lw_session.connection.connection_u.abp.app_skey = params.connection_u.abp.app_skey; - - // If current state is SHUTDOWN, device may be trying to re-establish - // communication. In case of ABP specification is meddled about frame counters. - // It says to reset counters to zero but there is no mechanism to tell the - // network server that the device was disconnected or restarted. - // At the moment, this implementation does not support a non-volatile - // memory storage. - //_lw_session.downlink_counter; //Get from NVM - //_lw_session.uplink_counter; //Get from NVM - - tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu", - _lw_session.uplink_counter, _lw_session.downlink_counter); - - return lora_state_machine(DEVICE_STATE_ABP_CONNECTING); -} - int16_t LoRaWANStack::handle_tx(uint8_t port, const uint8_t* data, uint16_t length, uint8_t flags, bool null_allowed) { @@ -512,12 +473,10 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm) switch (mlme_confirm->req_type) { case MLME_JOIN: if (mlme_confirm->status == LORAMAC_EVENT_INFO_STATUS_OK) { - // Status is OK, node has joined the network if (lora_state_machine(DEVICE_STATE_JOINED) != LORAWAN_STATUS_OK) { tr_error("Lora state machine did not return LORAWAN_STATUS_OK"); } } else { - // Join attempt failed. if (lora_state_machine(DEVICE_STATE_IDLE) != LORAWAN_STATUS_IDLE) { tr_error("Lora state machine did not return DEVICE_STATE_IDLE !"); } @@ -531,8 +490,6 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm) break; case MLME_LINK_CHECK: if (mlme_confirm->status == LORAMAC_EVENT_INFO_STATUS_OK) { - // Check DemodMargin - // Check NbGateways #if defined(LORAWAN_COMPLIANCE_TEST) if (_compliance_test.running == true) { _compliance_test.link_check = true; @@ -541,7 +498,6 @@ void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t *mlme_confirm) } else #endif { - // normal operation as oppose to compliance testing if (_callbacks.link_check_resp) { const int ret = _queue->call(_callbacks.link_check_resp, mlme_confirm->demod_margin, @@ -640,61 +596,63 @@ void LoRaWANStack::mcps_indication_handler(loramac_mcps_indication_t *mcps_indic } #endif - if (mcps_indication->is_data_recvd == true) { - switch (mcps_indication->port) { - case 224: { + if (!mcps_indication->is_data_recvd) { + return; + } + + switch (mcps_indication->port) { + case 224: { #if defined(LORAWAN_COMPLIANCE_TEST) - tr_debug("Compliance test command received."); - compliance_test_handler(mcps_indication); + tr_debug("Compliance test command received."); + compliance_test_handler(mcps_indication); #else - tr_info("Compliance test disabled."); + tr_info("Compliance test disabled."); #endif - break; - } - default: { - if (is_port_valid(mcps_indication->port) == true || - mcps_indication->type == MCPS_PROPRIETARY) { + break; + } + default: { + if (is_port_valid(mcps_indication->port) == true || + mcps_indication->type == MCPS_PROPRIETARY) { - // Valid message arrived. - _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; - _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size; - _rx_msg.msg.mcps_indication.port = mcps_indication->port; - _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer; + // Valid message arrived. + _rx_msg.type = LORAMAC_RX_MCPS_INDICATION; + _rx_msg.msg.mcps_indication.buffer_size = mcps_indication->buffer_size; + _rx_msg.msg.mcps_indication.port = mcps_indication->port; + _rx_msg.msg.mcps_indication.buffer = mcps_indication->buffer; - // Notify application about received frame.. - tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size); - _rx_msg.receive_ready = true; + // Notify application about received frame.. + tr_debug("Received %d bytes", _rx_msg.msg.mcps_indication.buffer_size); + _rx_msg.receive_ready = true; - if (_callbacks.events) { - const int ret = _queue->call(_callbacks.events, RX_DONE); - MBED_ASSERT(ret != 0); - (void)ret; - } - - //TODO: below if clauses can be combined, - // because those are calling same function with same parameters - - // If fPending bit is set we try to generate an empty packet - // with CONFIRMED flag set. We always set a CONFIRMED flag so - // that we could retry a certain number of times if the uplink - // failed for some reason - if (_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) { - handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); - } - - // Class C and node received a confirmed message so we need to - // send an empty packet to acknowledge the message. - // This scenario is unspecified by LoRaWAN 1.0.2 specification, - // but version 1.1.0 says that network SHALL not send any new - // confirmed messages until ack has been sent - if (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) { - handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); - } - } else { - // Invalid port, ports 0, 224 and 225-255 are reserved. + if (_callbacks.events) { + const int ret = _queue->call(_callbacks.events, RX_DONE); + MBED_ASSERT(ret != 0); + (void)ret; } - break; + + //TODO: below if clauses can be combined, + // because those are calling same function with same parameters + + // If fPending bit is set we try to generate an empty packet + // with CONFIRMED flag set. We always set a CONFIRMED flag so + // that we could retry a certain number of times if the uplink + // failed for some reason + if (_loramac.get_device_class() != CLASS_C && mcps_indication->fpending_status) { + handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); + } + + // Class C and node received a confirmed message so we need to + // send an empty packet to acknowledge the message. + // This scenario is unspecified by LoRaWAN 1.0.2 specification, + // but version 1.1.0 says that network SHALL not send any new + // confirmed messages until ack has been sent + if (_loramac.get_device_class() == CLASS_C && mcps_indication->type == MCPS_CONFIRMED) { + handle_tx(mcps_indication->port, NULL, 0, MSG_CONFIRMED_FLAG, true); + } + } else { + // Invalid port, ports 0, 224 and 225-255 are reserved. } + break; } } } @@ -774,10 +732,10 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) status = LORAWAN_STATUS_OK; break; case DEVICE_STATE_JOINING: - if (_lw_session.connection.connect_type == LORAWAN_CONNECTION_OTAA) { + if (_lw_session.connect_type == LORAWAN_CONNECTION_OTAA) { tr_debug("Send Join-request.."); - status = _loramac.join_by_otaa(_lw_session.connection.connection_u.otaa); + status = _loramac.join(true); if (status != LORAWAN_STATUS_OK) { return status; } @@ -801,7 +759,7 @@ lorawan_status_t LoRaWANStack::lora_state_machine(device_states_t new_state) break; case DEVICE_STATE_ABP_CONNECTING: - _loramac.join_by_abp(_lw_session.connection.connection_u.abp); + _loramac.join(false); tr_debug("ABP Connection OK!"); @@ -1028,7 +986,7 @@ void LoRaWANStack::compliance_test_handler(loramac_mcps_indication_t *mcps_indic #if MBED_CONF_LORA_PHY == 0 _loramac.LoRaMacTestSetDutyCycleOn(MBED_CONF_LORA_DUTY_CYCLE_ON); #endif - _loramac.join_by_otaa(_lw_session.connection.connection_u.otaa); + _loramac.join(true); break; case 7: // (x) if (mcps_indication->buffer_size == 3) { diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index d1cd724a6f..20d229c727 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -1,27 +1,41 @@ /** - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -Description: LoRaWAN stack layer that controls both MAC and PHY underneath - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) - - -Copyright (c) 2017, Arm Limited and affiliates. - -SPDX-License-Identifier: BSD-3-Clause -*/ + * \file LoRaWANStack.h + * + * \brief LoRaWAN stack layer implementation + * + * \copyright Revised BSD License, see LICENSE.TXT file include in the project + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jaeckle ( STACKFORCE ) + * + * \defgroup LoRaWAN stack layer that controls MAC layer underneath + * + * License: Revised BSD License, see LICENSE.TXT file include in the project + * + * Copyright (c) 2017, Arm Limited and affiliates. + * + * SPDX-License-Identifier: BSD-3-Clause + */ #ifndef LORAWANSTACK_H_ #define LORAWANSTACK_H_ @@ -35,11 +49,6 @@ SPDX-License-Identifier: BSD-3-Clause #include "lorawan/system/lorawan_data_structures.h" #include "LoRaRadio.h" -/** - * A mask for the network ID. - */ -#define LORAWAN_NETWORK_ID_MASK ( uint32_t )0xFE000000 - class LoRaWANStack: private mbed::NonCopyable { private: /** End-device states. @@ -422,31 +431,10 @@ private: */ lorawan_status_t set_application_port(uint8_t port); - /** End device OTAA join. - * - * Based on the LoRaWAN standard 1.0.2. - * Join the network using the Over The Air Activation (OTAA) procedure. - * - * @param params The `lorawan_connect_t` type structure. - * - * @return LORAWAN_STATUS_OK or - * LORAWAN_STATUS_CONNECT_IN_PROGRESS on success, - * or a negative error code on failure. + /** + * Handles connection internally */ - lorawan_status_t join_request_by_otaa(const lorawan_connect_t ¶ms); - - /** End device ABP join. - * - * Based on the LoRaWAN standard 1.0.2. - * Join the network using the Activation By Personalization (ABP) procedure. - * - * @param params The `lorawan_connect_t` type structure. - * - * @return LORAWAN_STATUS_OK or - * LORAWAN_STATUS_CONNECT_IN_PROGRESS on success, - * or a negative error code on failure. - */ - lorawan_status_t activation_by_personalization(const lorawan_connect_t ¶ms); + lorawan_status_t handle_connect(bool is_otaa); private: diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index 164887583d..38a039e32c 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -76,6 +76,11 @@ using namespace events; */ #define DOWN_LINK 1 +/** + * A mask for the network ID. + */ +#define LORAWAN_NETWORK_ID_MASK ( uint32_t )0xFE000000 + LoRaMac::LoRaMac() : _lora_phy(_lora_time), mac_commands(), _is_nwk_joined(false) @@ -964,8 +969,8 @@ void LoRaMac::on_rx_window1_timer_event(void) _lora_phy.rx_config(&_params.rx_window1_config, (int8_t*) &_mcps_indication.rx_datarate); - rx_window_setup(_params.rx_window1_config.is_rx_continuous, - _params.sys_params.max_rx_win_time); + _lora_phy.setup_rx_window(_params.rx_window1_config.is_rx_continuous, + _params.sys_params.max_rx_win_time); } void LoRaMac::on_rx_window2_timer_event(void) @@ -978,18 +983,17 @@ void LoRaMac::on_rx_window2_timer_event(void) _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 = true; + if (_device_class != CLASS_C) { _params.rx_window2_config.is_rx_continuous = false; - } else { - // Setup continuous listening for class c - _params.rx_window2_config.is_rx_continuous = true; } if (_lora_phy.rx_config(&_params.rx_window2_config, (int8_t*) &_mcps_indication.rx_datarate) == true) { - rx_window_setup(_params.rx_window2_config.is_rx_continuous, - _params.sys_params.max_rx_win_time); + _lora_phy.setup_rx_window(_params.rx_window2_config.is_rx_continuous, + _params.sys_params.max_rx_win_time); _params.rx_slot = RX_SLOT_WIN_2; } @@ -1037,11 +1041,6 @@ void LoRaMac::on_ack_timeout_timer_event(void) } } -void LoRaMac::rx_window_setup(bool rx_continuous, uint32_t max_rx_window_time) -{ - _lora_phy.setup_rx_window(rx_continuous, max_rx_window_time); -} - bool LoRaMac::validate_payload_length(uint8_t length, int8_t datarate, uint8_t fopts_len) { @@ -1418,8 +1417,85 @@ void LoRaMac::setup_link_check_request() mac_commands.add_mac_command(MOTE_MAC_LINK_CHECK_REQ, 0, 0); } -lorawan_status_t LoRaMac::join_by_otaa(const lorawan_connect_otaa_t& otaa_join) +lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_otaa) { + if (params) { + if (is_otaa) { + if ((params->connection_u.otaa.dev_eui == NULL) || + (params->connection_u.otaa.app_eui == NULL) || + (params->connection_u.otaa.app_key == NULL) || + (params->connection_u.otaa.nb_trials == 0)) { + return LORAWAN_STATUS_PARAMETER_INVALID; + } + _params.keys.dev_eui = params->connection_u.otaa.dev_eui; + _params.keys.app_eui = params->connection_u.otaa.app_eui; + _params.keys.app_key = params->connection_u.otaa.app_key; + _params.max_join_request_trials = params->connection_u.otaa.nb_trials; + + if (!_lora_phy.verify_nb_join_trials(params->connection_u.otaa.nb_trials)) { + // Value not supported, get default + _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; + } + // Reset variable JoinRequestTrials + _params.join_request_trial_counter = 0; + + reset_mac_parameters(); + + _params.sys_params.channel_data_rate = + _lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1); + } else { + _params.net_id = params->connection_u.abp.nwk_id; + _params.dev_addr = params->connection_u.abp.dev_addr; + + memcpy(_params.keys.nwk_skey, params->connection_u.abp.nwk_skey, + sizeof(_params.keys.nwk_skey)); + + memcpy(_params.keys.app_skey, params->connection_u.abp.app_skey, + sizeof(_params.keys.app_skey)); + } + } else { +#if MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION + const static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI; + const static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI; + const static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY; + + _params.keys.app_eui = const_cast(app_eui); + _params.keys.dev_eui = const_cast(dev_eui); + _params.keys.app_key = const_cast(app_key); + _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; + + // Reset variable JoinRequestTrials + _params.join_request_trial_counter = 0; + + reset_mac_parameters(); + + _params.sys_params.channel_data_rate = + _lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1); + +#else + const static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY; + const static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY; + + _params.net_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK); + _params.dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS; + + memcpy(_params.keys.nwk_skey, nwk_skey, + sizeof(_params.keys.nwk_skey)); + + memcpy(_params.keys.app_skey, app_skey, + sizeof(_params.keys.app_skey)); +#endif + } + return LORAWAN_STATUS_OK; +} + +lorawan_status_t LoRaMac::join(bool is_otaa) +{ + if (!is_otaa) { + set_nwk_joined(true); + return LORAWAN_STATUS_OK; + } + if (LORAMAC_IDLE != _params.mac_state) { return LORAWAN_STATUS_BUSY; } @@ -1429,53 +1505,12 @@ lorawan_status_t LoRaMac::join_by_otaa(const lorawan_connect_otaa_t& otaa_join) _mlme_confirmation.req_type = MLME_JOIN; _params.flags.bits.mlme_req = 1; -// if ((_params.mac_state & LORAMAC_TX_DELAYED) == LORAMAC_TX_DELAYED) { -// return LORAWAN_STATUS_BUSY; -// } - - if ((otaa_join.dev_eui == NULL) || - (otaa_join.app_eui == NULL) || - (otaa_join.app_key == NULL) || - (otaa_join.nb_trials == 0)) { - return LORAWAN_STATUS_PARAMETER_INVALID; - } - _params.keys.dev_eui = otaa_join.dev_eui; - _params.keys.app_eui = otaa_join.app_eui; - _params.keys.app_key = otaa_join.app_key; - _params.max_join_request_trials = otaa_join.nb_trials; - - if (!_lora_phy.verify_nb_join_trials(otaa_join.nb_trials)) { - // Value not supported, get default - _params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS; - } - // Reset variable JoinRequestTrials - _params.join_request_trial_counter = 0; - - reset_mac_parameters(); - - _params.sys_params.channel_data_rate = - _lora_phy.get_alternate_DR(_params.join_request_trial_counter + 1); - loramac_mhdr_t machdr; machdr.value = 0; machdr.bits.mtype = FRAME_TYPE_JOIN_REQ; return send(&machdr, 0, NULL, 0); } -void LoRaMac::join_by_abp(const lorawan_connect_abp_t& abp_join) -{ - _params.net_id = abp_join.nwk_id; - _params.dev_addr = abp_join.dev_addr; - - memcpy(_params.keys.nwk_skey, abp_join.nwk_skey, - sizeof(_params.keys.nwk_skey)); - - memcpy(_params.keys.app_skey, abp_join.app_skey, - sizeof(_params.keys.app_skey)); - - set_nwk_joined(true); -} - static void memcpy_convert_endianess(uint8_t *dst, const uint8_t *src, uint16_t size) { diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index c4825b35cf..49e24492d9 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -364,18 +364,20 @@ public: void setup_link_check_request(); /** - * @brief join_by_otaa Sends OTAA join message - * @param otaa_join Joining parameters + * @brief prepare_join prepares arguments to be ready for join() call. + * @param params Join parameters to use, if NULL, the default will be used. + * @param is_otaa True if joining is to be done using OTAA, false for ABP. * * @return LORAWAN_STATUS_OK or a negative error code on failure. */ - lorawan_status_t join_by_otaa(const lorawan_connect_otaa_t& otaa_join); + lorawan_status_t prepare_join(const lorawan_connect_t *params, bool is_otaa); /** - * @brief join_by_abp Sets up ABP connectivity parameters. - * @param abp_join Connectivity parameters. + * @brief join Joins the network. + * @param is_otaa True if joining is to be done using OTAA, false for ABP. + * @return LORAWAN_STATUS_OK or a negative error code on failure. */ - void join_by_abp(const lorawan_connect_abp_t& abp_join); + lorawan_status_t join(bool is_otaa); private: /** @@ -452,11 +454,6 @@ private: */ void on_ack_timeout_timer_event(void); - /** - * Initializes and opens the reception window - */ - void rx_window_setup(bool rx_continuous, uint32_t max_rx_window_time); - /** * Validates if the payload fits into the frame, taking the datarate * into account. diff --git a/features/lorawan/lorastack/phy/loraphy_target.h b/features/lorawan/lorastack/phy/loraphy_target.h index ef83458b56..7432b01441 100644 --- a/features/lorawan/lorastack/phy/loraphy_target.h +++ b/features/lorawan/lorastack/phy/loraphy_target.h @@ -19,36 +19,69 @@ #define LORAPHY_TARGET #ifdef MBED_CONF_LORA_PHY - #if MBED_CONF_LORA_PHY == 0 + +#define LORA_REGION_EU868 0x10 +#define LORA_REGION_AS923 0x11 +#define LORA_REGION_AU915 0x12 +#define LORA_REGION_CN470 0x13 +#define LORA_REGION_CN779 0x14 +#define LORA_REGION_EU433 0x15 +#define LORA_REGION_IN865 0x16 +#define LORA_REGION_KR920 0x17 +#define LORA_REGION_US915 0x18 +#define LORA_REGION_US915_HYBRID 0x19 + +//DO NOT USE integer values in mbed_app.json! +//These are defined for backward compatibility and +//Will be DEPRECATED in the future +#define LORA_REGION_0 0x10 +#define LORA_REGION_1 0x11 +#define LORA_REGION_2 0x12 +#define LORA_REGION_3 0x13 +#define LORA_REGION_4 0x14 +#define LORA_REGION_5 0x15 +#define LORA_REGION_6 0x16 +#define LORA_REGION_7 0x17 +#define LORA_REGION_8 0x18 +#define LORA_REGION_9 0x19 + +//Since 0 would be equal to any undefined value we need to handle this in a other way +#define mbed_lora_concat_(x) LORA_REGION_##x +#define mbed_lora_concat(x) mbed_lora_concat_(x) +#define LORA_REGION mbed_lora_concat(MBED_CONF_LORA_PHY) + + #if LORA_REGION == LORA_REGION_EU868 #include "lorawan/lorastack/phy/LoRaPHYEU868.h" #define LoRaPHY_region LoRaPHYEU868 - #elif MBED_CONF_LORA_PHY == 1 + #elif LORA_REGION == LORA_REGION_AS923 #include "lorawan/lorastack/phy/LoRaPHYAS923.h" #define LoRaPHY_region LoRaPHYAS923 - #elif MBED_CONF_LORA_PHY == 2 + #elif LORA_REGION == LORA_REGION_AU915 #include "lorawan/lorastack/phy/LoRaPHYAU915.h" #define LoRaPHY_region LoRaPHYAU915; - #elif MBED_CONF_LORA_PHY == 3 + #elif LORA_REGION == LORA_REGION_CN470 #include "lorawan/lorastack/phy/LoRaPHYCN470.h" #define LoRaPHY_region LoRaPHYCN470 - #elif MBED_CONF_LORA_PHY == 4 + #elif LORA_REGION == LORA_REGION_CN779 #include "lorawan/lorastack/phy/LoRaPHYCN779.h" #define LoRaPHY_region LoRaPHYCN779 - #elif MBED_CONF_LORA_PHY == 5 + #elif LORA_REGION == LORA_REGION_EU433 #include "lorawan/lorastack/phy/LoRaPHYEU433.h" #define LoRaPHY_region LoRaPHYEU433 - #elif MBED_CONF_LORA_PHY == 6 + #elif LORA_REGION == LORA_REGION_IN865 #include "lorawan/lorastack/phy/LoRaPHYIN865.h" #define LoRaPHY_region LoRaPHYIN865 - #elif MBED_CONF_LORA_PHY == 7 + #elif LORA_REGION == LORA_REGION_KR920 #include "lorawan/lorastack/phy/LoRaPHYKR920.h" #define LoRaPHY_region LoRaPHYKR920 - #elif MBED_CONF_LORA_PHY == 8 + #elif LORA_REGION == LORA_REGION_US915 #include "lorawan/lorastack/phy/LoRaPHYUS915.h" #define LoRaPHY_region LoRaPHYUS915 - #elif MBED_CONF_LORA_PHY == 9 + #elif LORA_REGION == LORA_REGION_US915_HYBRID #include "lorawan/lorastack/phy/LoRaPHYUS915Hybrid.h" #define LoRaPHY_region LoRaPHYUS915Hybrid + #else + #error "Invalid region configuration, update mbed_app.json with correct MBED_CONF_LORA_PHY value" #endif //MBED_CONF_LORA_PHY == VALUE #else #error "Must set LoRa PHY layer parameters." diff --git a/features/lorawan/mbed_lib.json b/features/lorawan/mbed_lib.json index f88e0a5cc0..242de47d67 100644 --- a/features/lorawan/mbed_lib.json +++ b/features/lorawan/mbed_lib.json @@ -2,8 +2,8 @@ "name": "lora", "config": { "phy": { - "help": "LoRa PHY region. 0 = EU868 (default), 1 = AS923, 2 = AU915, 3 = CN470, 4 = CN779, 5 = EU433, 6 = IN865, 7 = KR920, 8 = US915, 9 = US915_HYBRID", - "value": "0" + "help": "LoRa PHY region: EU868, AS923, AU915, CN470, CN779, EU433, IN865, KR920, US915, US915_HYBRID", + "value": "EU868" }, "over-the-air-activation": { "help": "When set to 1 the application uses the Over-the-Air activation procedure, default: true", diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index be47685b64..88b717440a 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1277,7 +1277,12 @@ typedef struct lorawan_session { */ bool active; - lorawan_connect_t connection; + /*! + * Select the connection type, either LORAWAN_CONNECTION_OTAA + * or LORAWAN_CONNECTION_ABP. + */ + uint8_t connect_type; + /** * LoRaWAN uplink counter */